What's the pythonic way to use getters and setters?
我这样做就像:
1 2 | def set_property(property,value): def get_property(property): |
或
1 2 | object.property = value value = object.property |
我对python还不熟悉,所以我仍在探索语法,我希望在这方面有一些建议。
试试这个:python属性
示例代码为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | class C(object): def __init__(self): self._x = None @property def x(self): """I'm the 'x' property.""" print("getter of x called") return self._x @x.setter def x(self, value): print("setter of x called") self._x = value @x.deleter def x(self): print("deleter of x called") del self._x c = C() c.x = 'foo' # setter called foo = c.x # getter called del c.x # deleter called |
What's the pythonic way to use getters and setters?
"pythonic"的方法不是使用"getter"和"setters",而是使用简单的属性(如问题所示),以及使用
1 2 3 4 5 | value = 'something' obj.attribute = value value = obj.attribute del obj.attribute |
如果以后要修改设置并获取,则可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Obj: """property demo""" # @property def attribute(self): # implements the get - this name is *the* name return self._attribute # @attribute.setter def attribute(self, value): # name must be the same self._attribute = value # @attribute.deleter def attribute(self): # again, name must be the same del self._attribute |
(每个装饰器复制并更新先前的属性对象,因此请注意,对于每个集合、get和delete函数/方法,您可能应该使用相同的名称。)
定义以上内容后,原始设置、获取和删除是相同的:
1 2 3 4 | obj = Obj() obj.attribute = value the_value = obj.attribute del obj.attribute |
您应该避免这样做:
1
2 def set_property(property,value):
def get_property(property):
首先,上述方法不起作用,因为您没有提供将属性设置为(通常为
1 2 3 4 5 6 | class Obj: def set_property(self, property, value): # don't do this ... def get_property(self, property): # don't do this either ... |
其次,重复了两种特殊方法的用途,即
第三,我们还有
1 2 | setattr(object, 'property_name', value) getattr(object, 'property_name', default_value) # default is optional |
例如,我们可以修改设置行为来限制正在设置的值:
1 2 3 4 5 6 7 8 9 10 | class Protective(object): @property def protected_value(self): return self._protected_value @protected_value.setter def protected_value(self, value): if acceptable(value): # e.g. type or range check self._protected_value = value |
一般来说,我们希望避免使用
这是Python用户所期望的。遵循最不令人惊讶的规则,除非你有一个非常令人信服的相反理由,否则你应该尝试给你的用户他们所期望的。
示范例如,假设我们需要我们的对象的protected属性是一个介于0和100之间(包括0和100)的整数,并防止删除它,并使用适当的消息通知用户它的正确用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class Protective(object): def __init__(self, start_protected_value=0): self.protected_value = start_protected_value @property def protected_value(self): return self._protected_value @protected_value.setter def protected_value(self, value): if value != int(value): raise TypeError("protected_value must be an integer") if 0 <= value <= 100: self._protected_value = int(value) else: raise ValueError("protected_value must be" + "between 0 and 100 inclusive") @protected_value.deleter def protected_value(self): raise AttributeError("do not delete, protected_value can be set to 0") |
用途:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | >>> p1 = Protective(3) >>> p1.protected_value 3 >>> p1 = Protective(5.0) >>> p1.protected_value 5 >>> p2 = Protective(-5) Traceback (most recent call last): File"<stdin>", line 1, in <module> File"<stdin>", line 3, in __init__ File"<stdin>", line 15, in protected_value ValueError: protectected_value must be between 0 and 100 inclusive >>> p1.protected_value = 7.3 Traceback (most recent call last): File"<stdin>", line 1, in <module> File"<stdin>", line 17, in protected_value TypeError: protected_value must be an integer >>> p1.protected_value = 101 Traceback (most recent call last): File"<stdin>", line 1, in <module> File"<stdin>", line 15, in protected_value ValueError: protectected_value must be between 0 and 100 inclusive >>> del p1.protected_value Traceback (most recent call last): File"<stdin>", line 1, in <module> File"<stdin>", line 18, in protected_value AttributeError: do not delete, protected_value can be set to 0 |
名字重要吗?
是的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Obj: """property demo""" # @property def get_only(self): return self._attribute # @get_only.setter def get_or_set(self, value): self._attribute = value # @get_or_set.deleter def get_set_or_delete(self): del self._attribute |
现在,要使其生效,您必须使用各自的名称:
1 2 3 4 5 6 7 | obj = Obj() # obj.get_only = 'value' # would error obj.get_or_set = 'value' obj.get_set_or_delete = 'new value' the_value = obj.get_only del obj.get_set_or_delete # del obj.get_or_set # would error |
我不确定这在哪里有用,但是用例是如果您想要一个get、set和/或delete-only属性。最好还是坚持语义上相同的同名属性。
结论从简单的属性开始。
如果以后需要有关设置、获取和删除的功能,可以使用属性修饰器添加它。
避免使用名为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | In [1]: class test(object): def __init__(self): self.pants = 'pants' @property def p(self): return self.pants @p.setter def p(self, value): self.pants = value * 2 ....: In [2]: t = test() In [3]: t.p Out[3]: 'pants' In [4]: t.p = 10 In [5]: t.p Out[5]: 20 |
查看
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Person(object): def __init__(self, p_name=None): self.name = p_name @property def name(self): return self._name @name.setter def name(self, new_name): if type(new_name) == str: #type checking for name property self._name = new_name else: raise Exception("Invalid value for name") |
通过这种方式,您实际上可以对客户端开发人员"隐藏"
1 | p = Person(12) |
将导致:
1 | Exception: Invalid value for name |
但是:
1 2 3 4 5 6 7 | >>>p = person('Mike') >>>print(p.name) Mike >>>p.name = 'George' >>>print(p.name) George >>>p.name = 2.3 # Causes an exception |
你可以使用魔法方法
1 2 3 4 5 6 7 8 9 | class MyClass: def __init__(self, attrvalue): self.myattr = attrvalue def __getattribute__(self, attr): if attr =="myattr": #Getter for myattr def __setattr__(self, attr): if attr =="myattr": #Setter for myattr |
请注意,