Online Book Reader

Home Category

Learning Python - Mark Lutz [440]

By Root 1710 0
from a class share the class’s namespace, any changes at the class level are reflected in all instances, unless they have their own versions of the changed class attributes.

Because classes, modules, and instances are all just objects with attribute namespaces, you can normally change their attributes at runtime by assignments. Consider the following class. Inside the class body, the assignment to the name a generates an attribute X.a, which lives in the class object at runtime and will be inherited by all of X’s instances:

>>> class X:

... a = 1 # Class attribute

...

>>> I = X()

>>> I.a # Inherited by instance

1

>>> X.a

1

So far, so good—this is the normal case. But notice what happens when we change the class attribute dynamically outside the class statement: it also changes the attribute in every object that inherits from the class. Moreover, new instances created from the class during this session or program run also get the dynamically set value, regardless of what the class’s source code says:

>>> X.a = 2 # May change more than X

>>> I.a # I changes too

2

>>> J = X() # J inherits from X's runtime values

>>> J.a # (but assigning to J.a changes a in J, not X or I)

2

Is this a useful feature or a dangerous trap? You be the judge. As we learned in Chapter 26, you can actually get work done by changing class attributes without ever making a single instance; this technique can simulate the use of “records” or “structs” in other languages. As a refresher, consider the following unusual but legal Python program:

class X: pass # Make a few attribute namespaces

class Y: pass

X.a = 1 # Use class attributes as variables

X.b = 2 # No instances anywhere to be found

X.c = 3

Y.a = X.a + X.b + X.c

for X.i in range(Y.a): print(X.i) # Prints 0..5

Here, the classes X and Y work like “fileless” modules—namespaces for storing variables we don’t want to clash. This is a perfectly legal Python programming trick, but it’s less appropriate when applied to classes written by others; you can’t always be sure that class attributes you change aren’t critical to the class’s internal behavior. If you’re out to simulate a C struct, you may be better off changing instances than classes, as that way only one object is affected:

class Record: pass

X = Record()

X.name = 'bob'

X.job = 'Pizza maker'

Changing Mutable Class Attributes Can Have Side Effects, Too

This gotcha is really an extension of the prior. Because class attributes are shared by all instances, if a class attribute references a mutable object, changing that object in-place from any instance impacts all instances at once:

>>> class C:

... shared = [] # Class attribute

... def __init__(self):

... self.perobj = [] # Instance attribute

...

>>> x = C() # Two instances

>>> y = C() # Implicitly share class attrs

>>> y.shared, y.perobj

([], [])

>>> x.shared.append('spam') # Impacts y's view too!

>>> x.perobj.append('spam') # Impacts x's data only

>>> x.shared, x.perobj

(['spam'], ['spam'])

>>> y.shared, y.perobj # y sees change made through x

(['spam'], [])

>>> C.shared # Stored on class and shared

['spam']

This effect is no different than many we’ve seen in this book already: mutable objects are shared by simple variables, globals are shared by functions, module-level objects are shared by multiple importers, and mutable function arguments are shared by the caller and the callee. All of these are cases of general behavior—multiple references to a mutable object—and all are impacted if the shared object is changed in-place from any reference. Here, this occurs in class attributes shared by all instances via inheritance, but it’s the same phenomenon at work. It may be made more subtle by the different behavior of assignments to instance attributes themselves:

x.shared.append('spam') # Changes shared object attached to class in-place

x.shared = 'spam' # Changed or creates instance attribute attached to x

but again, this is not a problem, it’s just something to be aware of; shared mutable class attributes can have many valid

Return Main Page Previous Page Next Page

®Online Book Reader