Online Book Reader

Home Category

Learning Python - Mark Lutz [508]

By Root 1351 0
2 instances of class with property

Q = PropSquare(32) # Each has different state information

print(P.X) # 3 ** 2

P.X = 4

print(P.X) # 4 ** 2

print(Q.X) # 32 ** 2

This class defines an attribute X that is accessed as though it were static data, but really runs code to compute its value when fetched. The effect is much like an implicit method call. When the code is run, the value is stored in the instance as state information, but each time we fetch it via the managed attribute, its value is automatically squared:

9

16

1024

Notice that we’ve made two different instances—because property methods automatically receive a self argument, they have access to the state information stored in instances. In our case, this mean the fetch computes the square of the subject instance’s data.

Coding Properties with Decorators

Although we’re saving additional details until the next chapter, we introduced function decorator basics earlier, in Chapter 31. Recall that the function decorator syntax:

@decorator

def func(args): ...

is automatically translated to this equivalent by Python, to rebind the function name to the result of the decorator callable:

def func(args): ...

func = decorator(func)

Because of this mapping, it turns out that the property built-in can serve as a decorator, to define a function that will run automatically when an attribute is fetched:

class Person:

@property

def name(self): ... # Rebinds: name = property(name)

When run, the decorated method is automatically passed to the first argument of the property built-in. This is really just alternative syntax for creating a property and rebinding the attribute name manually:

class Person:

def name(self): ...

name = property(name)

As of Python 2.6, property objects also have getter, setter, and deleter methods that assign the corresponding property accessor methods and return a copy of the property itself. We can use these to specify components of properties by decorating normal methods too, though the getter component is usually filled in automatically by the act of creating the property itself:

class Person:

def __init__(self, name):

self._name = name

@property

def name(self): # name = property(name)

"name property docs"

print('fetch...')

return self._name

@name.setter

def name(self, value): # name = name.setter(name)

print('change...')

self._name = value

@name.deleter

def name(self): # name = name.deleter(name)

print('remove...')

del self._name

bob = Person('Bob Smith') # bob has a managed attribute

print(bob.name) # Runs name getter (name 1)

bob.name = 'Robert Smith' # Runs name setter (name 2)

print(bob.name)

del bob.name # Runs name deleter (name 3)

print('-'*20)

sue = Person('Sue Jones') # sue inherits property too

print(sue.name)

print(Person.name.__doc__) # Or help(Person.name)

In fact, this code is equivalent to the first example in this section—decoration is just an alternative way to code properties in this case. When it’s run, the results are the same:

fetch...

Bob Smith

change...

fetch...

Robert Smith

remove...

--------------------

fetch...

Sue Jones

name property docs

Compared to manual assignment of property results, in this case using decorators to code properties requires just three extra lines of code (a negligible difference). As is so often the case with alternative tools, the choice between the two techniques is largely subjective.

Descriptors

Descriptors provide an alternative way to intercept attribute access; they are strongly related to the properties discussed in the prior section. In fact, a property is a kind of descriptor—technically speaking, the property built-in is just a simplified way to create a specific type of descriptor that runs method functions on attribute accesses.

Functionally speaking, the descriptor protocol allows us to route a specific attribute’s get and set operations to methods of a separate class object that we provide: they provide a way to insert code to be run automatically on attribute access, and they allow us

Return Main Page Previous Page Next Page

®Online Book Reader