[英]How Can a function act like a descriptor?
def typed_property(name, expected_type):
storage_name = '_' + name
@property
def prop(self):
return getattr(self, storage_name)
@prop.setter
def prop(self, value):
if not isinstance(value, expected_type):
raise TypeError('{} must be a {}'.format(name, expected_type))
setattr(self, storage_name, value)
return prop
class Person:
name = typed_property('name', str)
age = typed_property('age', int)
def __init__(self, name, age):
self.name = name
self.age = age
Function typed_property() acts like a descriptor. Function typed_property() 就像一个描述符。 Why prop() is called when executing this code line (name = typed_property('name', str))?
为什么执行此代码行时会调用 prop() (name = typed_property('name', str))?
I don't know what you mean by "descriptor".我不知道您所说的“描述符”是什么意思。
typed_property
allows a property to call a function for additional processing. typed_property
允许属性调用 function 进行额外处理。 prop()
is not called when executing the line you mentioned.执行您提到的行时不会调用
prop()
。 It is called when executing self.name = name
.它在执行
self.name = name
时被调用。 The @prop.setter
makes it so the object can respond to property calls like that. @prop.setter
使得 object 可以响应这样的属性调用。
When you call typed_property
to set the value of the class properties name
and age
, you are really defining those to be methods to use to access the instance values self.name
and self.age
.当您调用
typed_property
来设置 class 属性name
和age
的值时,您实际上将它们定义为用于访问实例值self.name
和self.age
的方法。 This is the same as below omitting age for simplicity:为简单起见,这与以下省略年龄相同:
class Person:
def __init__(self, name):
self.name = name
@property
def name(self):
print("=== ACESSING")
return self.name
@name.setter
def name(self, name):
print("=== MUTATING")
self.name = name
This marks the name(self)
method as the accessor for self.name
, and name(self, val)
as the mutator.这将
name(self)
方法标记为self.name
的访问器,并将name(self, val)
标记为 mutator。 The mutator is called whenever you try to change (mutate) the value of its assigned property, in this case self.name
.每当您尝试更改(变异)其分配属性的值时,都会调用 mutator,在本例中
self.name
。 This includes when you are calling it in the __init__
method.这包括您在
__init__
方法中调用它的时间。 However, using the class as defined above will result in an infinite recursion because I am calling the mutator from inside the mutator.但是,使用上面定义的 class 将导致无限递归,因为我是从 mutator 内部调用 mutator。 So "=== MUTATING" will be printed ending in a recursion error.
所以 "=== MUTATING" 会以递归错误结尾。 So a small adjustment is needed:
所以需要做一个小调整:
class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
print("=== ACCESSING")
return self._name
@name.setter
def name(self, val):
print("=== MUTATING")
self._name = val
Now that underlying property is name _name
rather than name
the mutator will set the value of _name
rather than setting it for name
and recur into itself infinitely.现在底层属性是 name
_name
而不是name
,mutator 将设置_name
的值,而不是为name
设置它并无限循环到自身。 For example, using the class as defined above:例如,使用上面定义的 class:
>>> p = Person("joshmeranda")
>>> p.name
=== ACCESSING
"joshmeranda"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.