In the section "Coding a property factory" of 《fluent python》,the code as follow:
def quantity(storage_name):def qty_getter(instance): # B return instance.__dict__[storage_name] def qty_setter(instance, value): if value > 0: instance.__dict__[storage_name] = value else: raise ValueError('value must be > 0') return property(qty_getter, qty_setter)
class LineItem: weight = quantity('weight') # A price = quantity('price')
def __init__(self, description, weight, price): self.description = description self.weight = weight self.price = price def subtotal(self): return self.weight * self.price
In the "A" only pass a argument,but in the function quantity receive two arguments:storage_name and instance. I am confused that the argument "instance" in the "B" how it passed to the qty_getter
The function quantity
builds and returns a property instance defined by the statement return property(qty_getter, qty_setter)
.
The property itself is built enclosing two nested functions qty_getter
and qty_setter
. Enclosing functions can access to the parent's function arguments (in a way similar to closures).
When you call self.weight
(in the subtotal function) you are telling python to call the getter function ( qty_getter
) of the property assigned to self.weight
.
To the getter (or setter) function, by property contract, is provided the instance of the object that holds the property itself (LineItem in this case) that in turn can access to the storage_name
variable.
The property
in Python is a special decorator. Decorators are simply put functions that are wrapping an other object, usually class fields.
The hard to understand bit is that the quantity
above is not a class, but a function. Inside that function there is two nested functions: qty_getter
and qty_setter
. Note that in your class you are only using the outer function directly. That quantity
function returns the outcome of
property(qty_getter, qty_setter)
property
here is a Python builtin that behaves in a special way. Whenever you try to set the value of the property, the qty_setter
is called with the new value. When you want to get the current value, the qty_getter
is called.
Since the property is bound to a class, you will usually call it on that class' instances, eg:
line = LineItem()
line.weight = 10 # weight setter called here
print(line.price) # price getter called here
line.subtotal # this method accesses both getters
Whenever you access a class' field in Python, internally that field is looked up using a helper method. The property is overriding the default behaviour here and instead calls the functions defined in the property. The instance
you see there as argument is an instance of LineItem
. It is comparable to self
in normal methods, except you are accessing an other object's self
here.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.