用于类实例变量的对象方法链接的 Python 方式 [英] Python way for object method chaining for class instance variables

查看:48
本文介绍了用于类实例变量的对象方法链接的 Python 方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

用例:

我有一个接收实例变量(表单域)的表单对象.现在我喜欢使用方法链来验证那里的变量.具有任意方法的示例:

I have a form object which receives instance variables (form fields). Now I like to validate there variables using method chaining. An example with arbitrary methods :

class Field(object):

    def __init__(self, form, name):
        self.form = form
        self.name = name

    def unspace(self):
        setattr(self.form, self.name, getattr(self.form, self.name).replace(' ',''))
        return self

    def len_valid(self, length):
        if len(getattr(self.form, self.name)) < length :
            setattr(self.form, self.name + '_invalid', True)
            self.form.valid = False
        return self

class Forms(object):                                                                                    

    def __init__(self):
        self.valid = True

    def validate(self, name):
        return Field(self,name)

f = Forms()         # create the form with some data
f.a = 'J o Hn '
f.b = ' Too   L o n g'

f.validate('a').unspace().len_valid(2)  
f.validate('b').unspace().len_valid(5)  

RESULT :
f.a : 'JoHn'
f.a_invalid : True
f.b : 'TooLong'
f.valid : False

这是在 Form 实例变量上创建方法链的 Pythonic 方式吗?

Is this the Pythonic way to create method chaining on the Form instance variables.

推荐答案

是和否.

链接方法调用的 Pythonic 方式正是您所写的:

The Pythonic way to chain method calls is exactly what you've written:

f.validate('a').unspace().len_valid(2)  

但是动态访问属性的 Pythonic 方法是不要这样做,除非您必须这样做.如果表单变量存储在 dict 中而不是作为对象的实例变量,那么一切都会变得更简单、更易读.

But the Pythonic way to access attributes dynamically is to not do that unless you have to. If the form variables were stored in a dict instead of as instance variables of the object, everything would be much simpler and more readable.

即使您确实需要将表单变量作为 fa 而不是 f['a'] 访问(例如,因为这是交互式 shell 的一部分,或某些第三方 API 要求),实际上更容易围绕 dict 编写所有代码,并使用您最喜欢的 AttrDict 类(来自 PyPI 或 ActiveState)提供您的用户/第三方 API 的属性样式访问.

Even if you really need the form variables to be accessible as f.a instead of f['a'] (e.g., because this is part of an interactive shell, or some third-party API requires that), it's actually easier to write all your code around a dict, and use your favorite AttrDict class (from PyPI or ActiveState) to provide the attribute-style access for your user/third-party API.

此外,如果您进一步将 Field 对象更改为具有某些方法的值的简单包装器,而不是(实际上)对父项和键的引用,则甚至更简单.

Also, if you further changed the Field object to be a trivial wrapper around a value with some methods, instead of (in effect) a reference to a parent and a key, it would be even simpler.

此外,如果您像 a_invalid 那样即时生成新属性,您可能希望始终生成它们,而不仅仅是在它们为真时.否则,检查 a 是否有效看起来像这样:

Also, if you generate new attributes on the fly like a_invalid, you probably want to always generate them, not only when they're true. Otherwise, checking whether a is valid looks something like this:

try:
    avalid = not f.a_invalid
except NameError:
    avalid = True

这太令人费解了,但如果您的来电者想避免这种情况,那么唯一的方法就是这样:

That's horribly convoluted, but if your caller wants to avoid that, the only way to do so is something like this:

avalid = not getattr(f, 'a_invalid', False)

这似乎首先违背了为调用者伪造属性的全部目的.

Which seems to defeat the whole purpose of faking attributes for the caller in the first place.

另外,请记住,您必须确保永远不会有名称以 _invalid 结尾的字段.因为你可以在 Python 中为几乎任何东西附加新属性,所以如果你真的想用这种方式做所有事情,为什么要使用 f.a_invalid 而不是 fainvalid?

Also, keep in mind that you have to make sure that there can never be a field whose name ends with _invalid. Since you can attach new attributes to almost anything in Python, so if you really do want to do everything this way, why use f.a_invalid instead of, say, f.a.invalid?

既然你在评论中问到,一个简单的值的包装看起来像这样:

Since you asked in the comments, a trivial wrapper around a value looks like this:

class Field(object):

    def __init__(self, value):
        self.value = value
        self.valid = True

    def unspace(self):
        self.value = self.value.replace(' ', '')
        return self

    def len_valid(self, length):
        if len(self.value) < length:
            self.valid = False
        return self

不要让每个字段都到达表单来设置其有效性,只需让表单来做:

Instead of making each field reach up to the Form to set its validity, just make the Form do it:

class Form(object):
    …
    def valid(self):
        return all(field.valid for field in self.fields)

如果你真的需要让 valid 看起来像一个成员变量而不是一个方法,只需使用 @property.

And if you really need to make that valid look like a member variable rather than a method, just use @property.

这篇关于用于类实例变量的对象方法链接的 Python 方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆