简体   繁体   中英

How works python property factory and nested functions

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM