- Nice shortcut to create a list of strings
fields = '''\
test1,
test2,
test3,
test4'''.split()
Dunder methods are looked up on the type for new-style classes
Dunder methods are looked up on the instance for old-style classes
Add iteration to a class object with metaclasses
class Foo(object):
def __iter__(self):
yield 'iterating over instance'
class __metaclass__(type):
def __iter__(self):
yield 'iterating over class, not instance'
__instancecheck__
and __issubclass__
exist on the metaclass or type
itself, not on an instance
class Dangerous(object):
class __metaclass__(type):
def __instancecheck__(self):
return hasattr(obj, 'attack')
class Monster(object):
def attack(self): pass
griffin = Monster()
assert isinstance(griffin, Dangerous)
class Dangerous(object):
class __metaclass__(type):
def __subclasscheck__(self, cls):
return hasattr(obj, 'attack')
class Dragon(Monster):
def __init__(self):
self.attack = 10
print issubclass(Drangon, Dangerous)
Modeling in terms of types (userland type systems)
class PrimeSequence(object):
class __metaclass__(type):
def __instancecheck__(self):
return all([x % 2 for x in self])
print isinstance([1,2,3,4], OddSequence)
This boils to writing a function that tells us if a sequence is odd or using a class to make it look like a type check.
Metaclasses are a tool for enforcing constraints from base to derived
Build a configuration system by using the existing import system instead of config files, etc.
Instance methods in Python are dynamically created when they are asked for, this means that each time you call the method it changes
Use case for old-style classes:
Creation of a class in Python is really:
def class_builder(cls):
cls.__new__()
cls.__init__()
return cls
Use metaclasses to do something like creating your own object model:
class foo()
pass
class baz():
pass
class bar():
pass
new_class = (foo | baz) & bar
Metaclass is only looked up for in the first base class
class A(Foo, Bar, Baz):
pass
Use metaclass to add constraints to inherited classes from base class
class metaclass(type):
def __init__(self, name, bases, body):
if name == 'Derived':
raise ValueError("I don't like your name")
return type.__init__(self, name, bases, body)
class Base(metaclass=metaclass):
pass
class Derived(Base):
pass