Online Book Reader

Home Category

Learning Python - Mark Lutz [522]

By Root 1345 0
chapter, let’s turn to a more realistic example, coded in all four of our attribute management schemes. The example we will use defines a CardHolder object with four attributes, three of which are managed. The managed attributes validate or transform values when fetched or stored. All four versions produce the same results for the same test code, but they implement their attributes in very different ways. The examples are included largely for self-study; although I won’t go through their code in detail, they all use concepts we’ve already explored in this chapter.

Using Properties to Validate

Our first coding uses properties to manage three attributes. As usual, we could use simple methods instead of managed attributes, but properties help if we have been using attributes in existing code already. Properties run code automatically on attribute access, but are focused on a specific set of attributes; they cannot be used to intercept all attributes generically.

To understand this code, it’s crucial to notice that the attribute assignments inside the __init__ constructor method trigger property setter methods too. When this method assigns to self.name, for example, it automatically invokes the setName method, which transforms the value and assigns it to an instance attribute called __name so it won’t clash with the property’s name.

This renaming (sometimes called name mangling) is necessary because properties use common instance state and have none of their own. Data is stored in an attribute called __name, and the attribute called name is always a property, not data.

In the end, this class manages attributes called name, age, and acct; allows the attribute addr to be accessed directly; and provides a read-only attribute called remain that is entirely virtual and computed on demand. For comparison purposes, this property-based coding weighs in at 39 lines of code:

class CardHolder:

acctlen = 8 # Class data

retireage = 59.5

def __init__(self, acct, name, age, addr):

self.acct = acct # Instance data

self.name = name # These trigger prop setters too

self.age = age # __X mangled to have class name

self.addr = addr # addr is not managed

# remain has no data

def getName(self):

return self.__name

def setName(self, value):

value = value.lower().replace(' ', '_')

self.__name = value

name = property(getName, setName)

def getAge(self):

return self.__age

def setAge(self, value):

if value < 0 or value > 150:

raise ValueError('invalid age')

else:

self.__age = value

age = property(getAge, setAge)

def getAcct(self):

return self.__acct[:-3] + '***'

def setAcct(self, value):

value = value.replace('-', '')

if len(value) != self.acctlen:

raise TypeError('invald acct number')

else:

self.__acct = value

acct = property(getAcct, setAcct)

def remainGet(self): # Could be a method, not attr

return self.retireage - self.age # Unless already using as attr

remain = property(remainGet)

Self-test code

The following code tests our class; add this to the bottom of your file, or place the class in a module and import it first. We’ll use this same testing code for all four versions of this example. When it runs, we make two instances of our managed-attribute class and fetch and change its various attributes. Operations expected to fail are wrapped in try statements:

bob = CardHolder('1234-5678', 'Bob Smith', 40, '123 main st')

print(bob.acct, bob.name, bob.age, bob.remain, bob.addr, sep=' / ')

bob.name = 'Bob Q. Smith'

bob.age = 50

bob.acct = '23-45-67-89'

print(bob.acct, bob.name, bob.age, bob.remain, bob.addr, sep=' / ')

sue = CardHolder('5678-12-34', 'Sue Jones', 35, '124 main st')

print(sue.acct, sue.name, sue.age, sue.remain, sue.addr, sep=' / ')

try:

sue.age = 200

except:

print('Bad age for Sue')

try:

sue.remain = 5

except:

print("Can't set sue.remain")

try:

sue.acct = '1234567'

except:

print('Bad acct for Sue')

Here is the output of our self-test code; again, this is the same for all versions of this example. Trace through this code to see how the class’s methods

Return Main Page Previous Page Next Page

®Online Book Reader