Demystifying Python Metaclasses Demystifying Python Metaclasses Eric - - PowerPoint PPT Presentation

demystifying python metaclasses demystifying python
SMART_READER_LITE
LIVE PREVIEW

Demystifying Python Metaclasses Demystifying Python Metaclasses Eric - - PowerPoint PPT Presentation

Demystifying Python Metaclasses Demystifying Python Metaclasses Eric D. Wills, Ph.D. Instructor, University of Oregon Instructor, University of Oregon Director of R&D, Vizme Inc What is a metaclass? What is a metaclass? A metaclass


slide-1
SLIDE 1

Demystifying Python Metaclasses Demystifying Python Metaclasses

Eric D. Wills, Ph.D. Instructor, University of Oregon Instructor, University of Oregon Director of R&D, Vizme Inc

slide-2
SLIDE 2

What is a metaclass? What is a metaclass?

  • A metaclass specifies the fundamental

A metaclass specifies the fundamental attributes for a class, such as the class name, parent class(es) and class variables parent class(es), and class variables.

  • A class constructor creates instances of that

class; a metaclass constructor creates classes class; a metaclass constructor creates classes

  • f that metaclass.
slide-3
SLIDE 3

Agenda Agenda

  • Review Python classes

Review Python classes

  • Introduce Python metaclasses

i l i

  • Use case: Dynamic class parenting
  • Use case: Dynamic properties
slide-4
SLIDE 4

Agenda Agenda

  • Review Python classes

Review Python classes

  • Introduce Python metaclasses

i l i

  • Use case: Dynamic class parenting
  • Use case: Dynamic properties
slide-5
SLIDE 5

What is a class? What is a class?

  • A class is typically a template for the state and

A class is typically a template for the state and behavior of a real‐world phenomenon.

  • A constructor method creates specific

A constructor method creates specific instances of the class.

  • For example, a Car class might specify the

For example, a Car class might specify the heading, velocity, and position state of each car instance and provide methods for accelerating, decelerating, and turning the instance.

slide-6
SLIDE 6

Class example Class example

class Car(object): _MAX_VELOCITY = 100.0 def __init__(self, initialVelocity): self._velocity = initialVelocity @ t @property def velocity(self): return self._velocity def accelerate(self, acceleration, deltaTime): self._velocity += acceleration*deltaTime if self._velocity > self.__class__._MAX_VELOCITY: self velocity self class MAX VELOCITY self._velocity = self.__class__._MAX_VELOCITY car = Car(10.0) print(car.velocity) car.accelerate(100.0, 1.0) print(car.velocity)

slide-7
SLIDE 7

Class example Class example

class Car(object): _MAX_VELOCITY = 100.0 def __init__(self, initialVelocity): self._velocity = initialVelocity @ t @property def velocity(self): return self._velocity def accelerate(self, acceleration, deltaTime): self._velocity += acceleration*deltaTime if self._velocity > self.__class__._MAX_VELOCITY: self velocity self class MAX VELOCITY self._velocity = self.__class__._MAX_VELOCITY car = Car(10.0) print(car.velocity) car.accelerate(100.0, 1.0) print(car.velocity)

slide-8
SLIDE 8

Class example Class example

  • class Car(object):

class Car(object):

– Defines a class named Car. The ultimate parent class for all classes is object. j

slide-9
SLIDE 9

Class example Class example

class Car(object): _MAX_VELOCITY = 100.0 def __init__(self, initialVelocity): self._velocity = initialVelocity @ t @property def velocity(self): return self._velocity def accelerate(self, acceleration, deltaTime): self._velocity += acceleration*deltaTime if self._velocity > self.__class__._MAX_VELOCITY: self velocity self class MAX VELOCITY self._velocity = self.__class__._MAX_VELOCITY car = Car(10.0) print(car.velocity) car.accelerate(100.0, 1.0) print(car.velocity)

slide-10
SLIDE 10

Class example Class example

  • MAX VELOCITY = 100.0

_MAX_VELOCITY 100.0

– This is a class variable. All instances of the class share a single copy of this variable. Therefore, a g py , change to the variable’s value by one instance affects all instances.

slide-11
SLIDE 11

Class example Class example

class Car(object): _MAX_VELOCITY = 100.0 def __init__(self, initialVelocity): self._velocity = initialVelocity @ t @property def velocity(self): return self._velocity def accelerate(self, acceleration, deltaTime): self._velocity += acceleration*deltaTime if self._velocity > self.__class__._MAX_VELOCITY: self velocity self class MAX VELOCITY self._velocity = self.__class__._MAX_VELOCITY car = Car(10.0) print(car.velocity) car.accelerate(100.0, 1.0) print(car.velocity)

slide-12
SLIDE 12

Class example Class example

  • def

init (self, initialVelocity): def __init__(self, initialVelocity): self._velocity = initialVelocity

– This is the constructor. When passed an initial This is the constructor. When passed an initial velocity as an argument, the _velocity instance variable is assigned to the value of the initialVelocity parameter.

slide-13
SLIDE 13

Class example Class example

class Car(object): _MAX_VELOCITY = 100.0 def __init__(self, initialVelocity): self._velocity = initialVelocity @ t @property def velocity(self): return self._velocity def accelerate(self, acceleration, deltaTime): self._velocity += acceleration*deltaTime if self._velocity > self.__class__._MAX_VELOCITY: self velocity self class MAX VELOCITY self._velocity = self.__class__._MAX_VELOCITY car = Car(10.0) print(car.velocity) car.accelerate(100.0, 1.0) print(car.velocity)

slide-14
SLIDE 14

Class example Class example

  • @property

@property def velocity(self): return self._velocity _ y

– This is an instance getter. This method uses the built‐in @property decorator to specify that this method should be called to return a value when the public variable velocity is accessed. The h d h l i f h method returns the current velocity of the instance.

slide-15
SLIDE 15

Class example Class example

class Car(object): _MAX_VELOCITY = 100.0 def __init__(self, initialVelocity): self._velocity = initialVelocity @ t @property def velocity(self): return self._velocity def accelerate(self, acceleration, deltaTime): self._velocity += acceleration*deltaTime if self._velocity > self.__class__._MAX_VELOCITY: self velocity self class MAX VELOCITY self._velocity = self.__class__._MAX_VELOCITY car = Car(10.0) print(car.velocity) car.accelerate(100.0, 1.0) print(car.velocity)

slide-16
SLIDE 16

Class example Class example

  • def accelerate(self, acceleration, deltaTime):

self._velocity += acceleration*deltaTime if self._velocity > self.__class__._MAX_VELOCITY: self._velocity = self.__class__._MAX_VELOCITY

– This is an instance method. When called on an instance, the velocity of that instance is updated according to the input parameters and then capped at the max velocity.

slide-17
SLIDE 17

Class example Class example

class Car(object): _MAX_VELOCITY = 100.0 def __init__(self, initialVelocity): self._velocity = initialVelocity @ t @property def velocity(self): return self._velocity def accelerate(self, acceleration, deltaTime): self._velocity += acceleration*deltaTime if self._velocity > self.__class__._MAX_VELOCITY: self velocity self class MAX VELOCITY self._velocity = self.__class__._MAX_VELOCITY car = Car(10.0) print(car.velocity) car.accelerate(100.0, 1.0) print(car.velocity)

slide-18
SLIDE 18

Class example Class example

  • car = Car(10.0)

car Car(10.0) print(car.velocity) car.accelerate(100.0, 1.0) ( , ) print(car.velocity)

– Prints 10 followed by 100. y

slide-19
SLIDE 19

Class example Class example

class Car(object): _MAX_VELOCITY = 100.0 def __init__(self, initialVelocity): self._velocity = initialVelocity @ t @property def velocity(self): return self._velocity def accelerate(self, acceleration, deltaTime): self._velocity += acceleration*deltaTime if self._velocity > self.__class__._MAX_VELOCITY: self velocity self class MAX VELOCITY self._velocity = self.__class__._MAX_VELOCITY car = Car(10.0) print(car.velocity) car.accelerate(100.0, 1.0) print(car.velocity)

slide-20
SLIDE 20

Agenda Agenda

  • Review Python classes

Review Python classes

  • Introduce Python metaclasses

i l i

  • Use case: Dynamic class parenting
  • Use case: Dynamic properties
slide-21
SLIDE 21

What is a metaclass again? What is a metaclass again?

  • A metaclass specifies the fundamental

A metaclass specifies the fundamental attributes for a class, such as the class name, parent class(es) and class variables parent class(es), and class variables.

  • A class constructor creates instances of that

class; a metaclass constructor creates classes class; a metaclass constructor creates classes

  • f that metaclass.
slide-22
SLIDE 22

How is this useful? How is this useful?

  • Imagine that we now want to create several types

Imagine that we now want to create several types

  • f cars, each with a different max velocity. We

have a few options: p

– Add a max velocity to the constructor parameters:

  • This would require that we pass the max velocity as an

argument each time we create an instance.

– Create a new class for each type of car:

R i ti l j t t l d i bl

  • Requires creating a new class just to overload a variable.

– Use a metaclass to create classes dynamically:

  • Can then use a factory method to create classes at runtime

Can then use a factory method to create classes at runtime.

slide-23
SLIDE 23

Metaclass example Metaclass example

class CarMeta(type): def new (cls name bases attrs): def __new__(cls, name, bases, attrs): return type.__new__(cls, name, bases, attrs) @staticmethod @staticmethod def createCarClass(carType, maxVelocity): return CarMeta('Car_' + carType, (Car,), {' MAX VELOCITY' V l i }) {'_MAX_VELOCITY':maxVelocity}) Car_Corolla = CarMeta.createCarClass('Corolla', 80.0) car = Car_Corolla(10.0) print(car.velocity) car.accelerate(100.0, 1.0) print(car.velocity)

slide-24
SLIDE 24

Metaclass example Metaclass example

class CarMeta(type): def new (cls name bases attrs): def __new__(cls, name, bases, attrs): return type.__new__(cls, name, bases, attrs) @staticmethod @staticmethod def createCarClass(carType, maxVelocity): return CarMeta('Car_' + carType, (Car,), {' MAX VELOCITY' V l i }) {'_MAX_VELOCITY':maxVelocity}) Car_Corolla = CarMeta.createCarClass('Corolla', 80.0) car = Car_Corolla(10.0) print(car.velocity) car.accelerate(100.0, 1.0) print(car.velocity)

slide-25
SLIDE 25

Metaclass example Metaclass example

  • class CarMeta(type):

class CarMeta(type):

– Defines a metaclass named CarMeta. The ultimate parent class for all metaclasses is type. p yp

slide-26
SLIDE 26

Metaclass example Metaclass example

class CarMeta(type): def new (cls name bases attrs): def __new__(cls, name, bases, attrs): return type.__new__(cls, name, bases, attrs) @staticmethod @staticmethod def createCarClass(carType, maxVelocity): return CarMeta('Car_' + carType, (Car,), {' MAX VELOCITY' V l i }) {'_MAX_VELOCITY':maxVelocity}) Car_Corolla = CarMeta.createCarClass('Corolla', 80.0) car = Car_Corolla(10.0) print(car.velocity) car.accelerate(100.0, 1.0) print(car.velocity)

slide-27
SLIDE 27

Metaclass example Metaclass example

  • def __new__(cls, name, bases, attrs):

return type.__new__(cls, name, bases, attrs)

– The constructor can modify the name, base l ( ) d l i bl f h l b i class(es), and class variables for the class being

  • created. None of these need be modified for this

example though so the constructor is a trivial example, though, so the constructor is a trivial passthrough.

slide-28
SLIDE 28

Metaclass example Metaclass example

class CarMeta(type): def new (cls name bases attrs): def __new__(cls, name, bases, attrs): return type.__new__(cls, name, bases, attrs) @staticmethod @staticmethod def createCarClass(carType, maxVelocity): return CarMeta('Car_' + carType, (Car,), {' MAX VELOCITY' V l i }) {'_MAX_VELOCITY':maxVelocity}) Car_Corolla = CarMeta.createCarClass('Corolla', 80.0) car = Car_Corolla(10.0) print(car.velocity) car.accelerate(100.0, 1.0) print(car.velocity)

slide-29
SLIDE 29

Metaclass example Metaclass example

  • @staticmethod

def createCarClass(carType, maxVelocity): return CarMeta('Car_' + carType, (Car,), {'_MAX_VELOCITY':maxVelocity}) { _ _ y})

– This method uses the built‐in @staticmethod decorator to specify that this method is called on the metaclass itself and not classes of the

  • metaclass. The method returns a new class of the

l b i h l ( i ) metaclass by passing the class name (a string), parent classes (a tuple), and class variables (a dict) to the metaclass constructor to the metaclass constructor.

slide-30
SLIDE 30

Metaclass example Metaclass example

class CarMeta(type): def new (cls name bases attrs): def __new__(cls, name, bases, attrs): return type.__new__(cls, name, bases, attrs) @staticmethod @staticmethod def createCarClass(carType, maxVelocity): return CarMeta('Car_' + carType, (Car,), {' MAX VELOCITY' V l i }) {'_MAX_VELOCITY':maxVelocity}) Car_Corolla = CarMeta.createCarClass('Corolla', 80.0) car = Car_Corolla(10.0) print(car.velocity) car.accelerate(100.0, 1.0) print(car.velocity)

slide-31
SLIDE 31

Metaclass example Metaclass example

  • Car_Corolla = CarMeta.createCarClass('Corolla', 80.0)

car = Car_Corolla(10.0) print(car.velocity) car.accelerate(100.0, 1.0) print(car.velocity)

– Prints 10 followed by 80.

slide-32
SLIDE 32

Metaclass example Metaclass example

class CarMeta(type): def new (cls name bases attrs): def __new__(cls, name, bases, attrs): return type.__new__(cls, name, bases, attrs) @staticmethod @staticmethod def createCarClass(carType, maxVelocity): return CarMeta('Car_' + carType, (Car,), {' MAX VELOCITY' V l i }) {'_MAX_VELOCITY':maxVelocity}) Car_Corolla = CarMeta.createCarClass('Corolla', 80.0) car = Car_Corolla(10.0) print(car.velocity) car.accelerate(100.0, 1.0) print(car.velocity)

slide-33
SLIDE 33

Agenda Agenda

  • Review Python classes

Review Python classes

  • Introduce Python metaclasses

i l i

  • Use case: Dynamic class parenting
  • Use case: Dynamic properties
slide-34
SLIDE 34

Dynamic class parenting Dynamic class parenting

  • Imagine that we would like to create several

Imagine that we would like to create several similar (or even identical) classes, each of which with a different parent class. For example, we p p , might want to:

– Create multiple versions of a class, each parented to a p p different class hierarchy:

  • Useful when extending multiple classes from an API (or

multiple APIs) multiple APIs).

  • Dynamic parent class can be specified using the child’s class

name, module path, class variables, etc.

slide-35
SLIDE 35

Dynamic parenting example Dynamic parenting example

class Car(object): pass class Corolla(object): _MAX_VELOCITY = 80.0 class CarMeta(type): def __new__(cls, name, bases, attrs): return type new (cls name bases attrs) return type.__new__(cls, name, bases, attrs) @staticmethod def createCarClass(carType): ( yp ) return CarMeta('Car_' + carType, (Car, globals()[carType]), {}) Car_Corolla = CarMeta.createCarClass('Corolla') print Car_Corolla._MAX_VELOCITY

slide-36
SLIDE 36

Dynamic parenting example Dynamic parenting example

class Car(object): pass class Corolla(object): _MAX_VELOCITY = 80.0 class CarMeta(type): def __new__(cls, name, bases, attrs): return type new (cls name bases attrs) return type.__new__(cls, name, bases, attrs) @staticmethod def createCarClass(carType): ( yp ) return CarMeta('Car_' + carType, (Car, globals()[carType]), {}) Car_Corolla = CarMeta.createCarClass('Corolla') print Car_Corolla._MAX_VELOCITY

slide-37
SLIDE 37

Dynamic parenting example Dynamic parenting example

  • class Car(object):

( j ) pass class Corolla(object): _MAX_VELOCITY = 80.0

D fi C b l t t th t t d – Define a Car base class to represent the state and behavior of all car classes. – Also define a number of possible parent classes – Also define a number of possible parent classes (just one here) with state and behavior specific to

  • ne type of car.
slide-38
SLIDE 38

Dynamic parenting example Dynamic parenting example

class Car(object): pass class Corolla(object): _MAX_VELOCITY = 80.0 class CarMeta(type): def __new__(cls, name, bases, attrs): return type new (cls name bases attrs) return type.__new__(cls, name, bases, attrs) @staticmethod def createCarClass(carType): ( yp ) return CarMeta('Car_' + carType, (Car, globals()[carType]), {}) Car_Corolla = CarMeta.createCarClass('Corolla') print Car_Corolla._MAX_VELOCITY

slide-39
SLIDE 39

Dynamic parenting example Dynamic parenting example

  • @staticmethod

def createCarClass(carType): return CarMeta('Car_' + carType, (C l b l ()[ T ]) (Car, globals()[carType]), {})

– When creating a class of the metaclass lookup the – When creating a class of the metaclass, lookup the class with name equal to the value of carType and add that class as a parent class to the class to be p created.

slide-40
SLIDE 40

Dynamic parenting example Dynamic parenting example

class Car(object): pass class Corolla(object): _MAX_VELOCITY = 80.0 class CarMeta(type): def __new__(cls, name, bases, attrs): return type new (cls name bases attrs) return type.__new__(cls, name, bases, attrs) @staticmethod def createCarClass(carType): ( yp ) return CarMeta('Car_' + carType, (Car, globals()[carType]), {}) Car_Corolla = CarMeta.createCarClass('Corolla') print Car_Corolla._MAX_VELOCITY

slide-41
SLIDE 41

Dynamic parenting example Dynamic parenting example

  • Car_Corolla = CarMeta.createCarClass('Corolla')

print Car_Corolla._MAX_VELOCITY

– Prints 80.

slide-42
SLIDE 42

Dynamic parenting example Dynamic parenting example

class Car(object): pass class Corolla(object): _MAX_VELOCITY = 80.0 class CarMeta(type): def __new__(cls, name, bases, attrs): return type new (cls name bases attrs) return type.__new__(cls, name, bases, attrs) @staticmethod def createCarClass(carType): ( yp ) return CarMeta('Car_' + carType, (Car, globals()[carType]), {}) Car_Corolla = CarMeta.createCarClass('Corolla') print Car_Corolla._MAX_VELOCITY

slide-43
SLIDE 43

At Vizme… At Vizme…

  • We primarily use SQLAlchemy as our ORM:

We primarily use SQLAlchemy as our ORM:

– A canonical model class is maintained for each table which specifies the columns of the table and table which specifies the columns of the table and provides convenience methods. – New child classes of these canonical classes are New child classes of these canonical classes are created dynamically and parented to the SQLAlchemy base class for the database session.

  • Allows multiple database sessions with a single model

class per table.

slide-44
SLIDE 44

Agenda Agenda

  • Review Python classes

Review Python classes

  • Introduce Python metaclasses

i l i

  • Use case: Dynamic class parenting
  • Use case: Dynamic properties
slide-45
SLIDE 45

Dynamic properties Dynamic properties

  • Imagine that we have a class with some instance

Imagine that we have a class with some instance variables and that we want to execute a similar

  • peration when getting or setting any of the

bl l h

  • variables. For example, we might want to:

– Set a dirty bit when the state of the instance changes. P f i b d f i k t id – Perform queries based on foreign keys outside a model’s database. – Select from multiple config values based on server p g state. – Retrieve config values from a file or memory.

slide-46
SLIDE 46

Dynamic property example (part 1) Dynamic property example (part 1)

class CarGetter(object): d f i i ( lf ) def __init__(self, name): self._name = name def call (self

  • wner):

def __call__(self, owner): return getattr(owner, self._name) class CarSetter(object): class CarSetter(object): def __init__(self, name): self._name = name def __call__(self, owner, value): print "invalidate!" return setattr(owner, self._name, value)

slide-47
SLIDE 47

Dynamic property example (part 1) Dynamic property example (part 1)

class CarGetter(object): d f i i ( lf ) def __init__(self, name): self._name = name def call (self

  • wner):

def __call__(self, owner): return getattr(owner, self._name) class CarSetter(object): class CarSetter(object): def __init__(self, name): self._name = name def __call__(self, owner, value): print "invalidate!" return setattr(owner, self._name, value)

slide-48
SLIDE 48

Dynamic property example (part 1) Dynamic property example (part 1)

  • class CarGetter(object):

class CarGetter(object): def __init__(self, name): self._name = name _

– Create a callable class to serve as the property

  • getter. The constructor stores the name of the

property for use when the class is called.

slide-49
SLIDE 49

Dynamic property example (part 1) Dynamic property example (part 1)

class CarGetter(object): d f i i ( lf ) def __init__(self, name): self._name = name def call (self

  • wner):

def __call__(self, owner): return getattr(owner, self._name) class CarSetter(object): class CarSetter(object): def __init__(self, name): self._name = name def __call__(self, owner, value): print "invalidate!" return setattr(owner, self._name, value)

slide-50
SLIDE 50

Dynamic property example (part 1) Dynamic property example (part 1)

  • def

call (self, owner): def __call__(self, owner): return getattr(owner, self._name)

– When the class is called we’re implicitly given When the class is called we re implicitly given access to the owner instance, so simply return the value of the specified variable from that instance.

slide-51
SLIDE 51

Dynamic property example (part 1) Dynamic property example (part 1)

class CarGetter(object): d f i i ( lf ) def __init__(self, name): self._name = name def call (self

  • wner):

def __call__(self, owner): return getattr(owner, self._name) class CarSetter(object): class CarSetter(object): def __init__(self, name): self._name = name def __call__(self, owner, value): print "invalidate!" return setattr(owner, self._name, value)

slide-52
SLIDE 52

Dynamic property example (part 1) Dynamic property example (part 1)

  • def __call__(self, owner, value):

( , , ) print "invalidate!" return setattr(owner, self._name, value)

– When the class is called we first invalidate the instance (or just indicate that we could do so, in this case) We’re again implicitly given access to this case). We re again implicitly given access to the owner instance, so we can update the value of the specified variable on that instance. the specified variable on that instance.

slide-53
SLIDE 53

Dynamic property example (part 1) Dynamic property example (part 1)

class CarGetter(object): d f i it ( lf ) def __init__(self, name): self._name = name def __call__(self, wrappedSelf): ( , pp ) return getattr(wrappedSelf, self._name) class CarSetter(object): def init (self name): def __init__(self, name): self._name = name def __call__(self, wrappedSelf, value): print "invalidate!" return setattr(wrappedSelf, self._name, value)

slide-54
SLIDE 54

Dynamic property example (part 2) Dynamic property example (part 2)

class CarMeta(type): def __new__(cls, name, bases, attrs): for name in attrs['_instanceVars']: attrs[name[1:]] = property(CarGetter(name), CarSetter(name)) return type.__new__(cls, name, bases, attrs) yp , , , class Car(object): __metaclass__ = CarMeta _instanceVars = ['_velocity'] def __init__(self, initialVelocity): self._velocity = initialVelocity car = Car(10) car velocity = 100 car.velocity = 100 print(car.velocity)

slide-55
SLIDE 55

Dynamic property example (part 2) Dynamic property example (part 2)

class CarMeta(type): def __new__(cls, name, bases, attrs): for name in attrs['_instanceVars']: attrs[name[1:]] = property(CarGetter(name), CarSetter(name)) return type.__new__(cls, name, bases, attrs) yp , , , class Car(object): __metaclass__ = CarMeta _instanceVars = ['_velocity'] def __init__(self, initialVelocity): self._velocity = initialVelocity car = Car(10) car velocity = 100 car.velocity = 100 print(car.velocity)

slide-56
SLIDE 56

Dynamic property example (part 2) Dynamic property example (part 2)

  • def __new__(cls, name, bases, attrs):

for name in attrs['_instanceVars']: attrs[name[1:]] = property(CarGetter(name), CarSetter(name)) return type.__new__(cls, name, bases, attrs)

– When creating a new class of the metaclass, loop through all variable names in the instanceVars through all variable names in the _instanceVars class variable of the class being created. For each private variable name in _instanceVars, use the b ilt i t f ti t t bli built‐in property function to create a public property based on new CarGetter and CarSetter instances.

slide-57
SLIDE 57

Dynamic property example (part 2) Dynamic property example (part 2)

class CarMeta(type): def __new__(cls, name, bases, attrs): for name in attrs['_instanceVars']: attrs[name[1:]] = property(CarGetter(name), CarSetter(name)) return type.__new__(cls, name, bases, attrs) yp , , , class Car(object): __metaclass__ = CarMeta _instanceVars = ['_velocity'] def __init__(self, initialVelocity): self._velocity = initialVelocity car = Car(10) car velocity = 100 car.velocity = 100 print(car.velocity)

slide-58
SLIDE 58

Dynamic property example (part 2) Dynamic property example (part 2)

  • __metaclass__ = CarMeta

_instanceVars = ['_velocity']

– Specify CarMeta as the metaclass for the Car

  • class. This is an alternate method for specifying a

metaclass which ensures that the metaclass metaclass which ensures that the metaclass constructor is called implicitly when the class is created. – Also define the list of instance‐variable names for which dynamic properties will be created.

slide-59
SLIDE 59

Dynamic property example (part 2) Dynamic property example (part 2)

class CarMeta(type): def __new__(cls, name, bases, attrs): for name in attrs['_instanceVars']: attrs[name[1:]] = property(CarGetter(name), CarSetter(name)) return type.__new__(cls, name, bases, attrs) yp , , , class Car(object): __metaclass__ = CarMeta _instanceVars = ['_velocity'] def __init__(self, initialVelocity): self._velocity = initialVelocity car = Car(10) car velocity = 100 car.velocity = 100 print(car.velocity)

slide-60
SLIDE 60

Dynamic property example (part 2) Dynamic property example (part 2)

  • car = Car(10)

car Car(10) car.velocity = 100 print(car.velocity) p ( y)

– Prints “invalidate!” followed by 100.

slide-61
SLIDE 61

Dynamic property example (part 2) Dynamic property example (part 2)

class CarMeta(type): def __new__(cls, name, bases, attrs): for name in attrs['_instanceVars']: attrs[name[1:]] = property(CarGetter(name), CarSetter(name)) return type.__new__(cls, name, bases, attrs) yp , , , class Car(object): __metaclass__ = CarMeta _instanceVars = ['_velocity'] def __init__(self, initialVelocity): self._velocity = initialVelocity car = Car(10) car velocity = 100 car.velocity = 100 print(car.velocity)

slide-62
SLIDE 62

At Vizme… At Vizme…

  • Our ORM models use metaclasses to create

properties dynamically: properties dynamically:

– Columns representing foreign keys outside the model’s database are assigned property getters which f th perform the necessary query. – Searchable columns are assigned property setters which enforce coherence between the database and h d search index.

  • We maintain a config system which assigns a

property getter for each private variable: property getter for each private variable:

– The getter typically retrieves the appropriate value from Memcached.

All fi l t b difi d ith t t ti th

  • Allows config values to be modified without restarting the

web server.

slide-63
SLIDE 63

In summary… In summary…

  • Metaclasses provide yet another means for

Metaclasses provide yet another means for avoiding code duplication by dynamically creating similar classes and methods creating similar classes and methods.

  • Metaclasses allow classes to crosscut multiple

aspects by dynamically parenting to distinct aspects by dynamically parenting to distinct classes. M l ’ h i !

  • Metaclasses aren’t that mysterious!
slide-64
SLIDE 64

Questions? Questions?