Online Book Reader

Home Category

Learning Python - Mark Lutz [573]

By Root 1534 0
the augmentation. When run, this version’s output is the same as before—we haven’t changed what the code does, we’ve just refactored it to encapsulate the augmentation more cleanly:

Ni!Ni!

Ni!Ni!Ni!Ni!

baconham

ni?ni?ni?ni?

baconham

Notice that the metaclass in this example still performs a fairly static task: adding two known methods to every class that declares it. In fact, if all we need to do is always add the same two methods to a set of classes, we might as well code them in a normal superclass and inherit in subclasses. In practice, though, the metaclass structure supports much more dynamic behavior. For instance, the subject class might also be configured based upon arbitrary logic at runtime:

# Can also configure class based on runtime tests

class MetaExtend(type):

def __new__(meta, classname, supers, classdict):

if sometest():

classdict['eggs'] = eggsfunc1

else:

classdict['eggs'] = eggsfunc2

if someothertest():

classdict['ham'] = hamfunc

else:

classdict['ham'] = lambda *args: 'Not supported'

return type.__new__(meta, classname, supers, classdict)

Metaclasses Versus Class Decorators: Round 2

Just in case this chapter has not yet managed to make your head explode, keep in mind again that the prior chapter’s class decorators often overlap with this chapter’s metaclasses in terms of functionality. This derives from the fact that:

Class decorators rebind class names to the result of a function at the end of a class statement.

Metaclasses work by routing class object creation through an object at the end of a class statement.

Although these are slightly different models, in practice they can usually achieve the same goals, albeit in different ways. In fact, class decorators can be used to manage both instances of a class and the class itself. While decorators can manage classes naturally, though, it’s somewhat less straightforward for metaclasses to manage instances. Metaclasses are probably best used for class object management.

Decorator-based augmentation

For example, the prior section’s metaclass example, which adds methods to a class on creation, can also be coded as a class decorator; in this mode, decorators roughly correspond to the __init__ method of metaclasses, since the class object has already been created by the time the decorator is invoked. Also like with metaclasses, the original class type is retained, since no wrapper object layer is inserted. The output of the following is the same as that of the prior metaclass code:

# Extend with a decorator: same as providing __init__ in a metaclass

def eggsfunc(obj):

return obj.value * 4

def hamfunc(obj, value):

return value + 'ham'

def Extender(aClass):

aClass.eggs = eggsfunc # Manages class, not instance

aClass.ham = hamfunc # Equiv to metaclass __init__

return aClass

@Extender

class Client1: # Client1 = Extender(Client1)

def __init__(self, value): # Rebound at end of class stmt

self.value = value

def spam(self):

return self.value * 2

@Extender

class Client2:

value = 'ni?'

X = Client1('Ni!') # X is a Client1 instance

print(X.spam())

print(X.eggs())

print(X.ham('bacon'))

Y = Client2()

print(Y.eggs())

print(Y.ham('bacon'))

In other words, at least in certain cases, decorators can manage classes as easily as metaclasses. The converse isn’t quite so straightforward, though; metaclasses can be used to manage instances, but only with a certain amount of magic. The next section demonstrates.

Managing instances instead of classes

As we’ve just seen, class decorators can often serve the same class-management role as metaclasses. Metaclasses can often serve the same instance-management role as decorators, too, but this is a bit more complex. That is:

Class decorators can manage both classes and instances.

Metaclasses can manage both classes and instances, but instances take extra work.

That said, certain applications may be better coded in one or the other. For example, consider the following class decorator example from the prior chapter; it’s used to print a trace

Return Main Page Previous Page Next Page

®Online Book Reader