A Class Factory


In [1]:
class Dog:
    def __init__(self, name, weight, owner):
        self.name = name
        self.weight = weight
        self.owner = owner

In [2]:
rex = Dog('Rex', 30, 'Bob')

In [3]:
rex


Out[3]:
<__main__.Dog at 0x6588ff2f98>

In [25]:
def record_factory(cls_name, field_names):
    try:
        field_names = field_names.replace(',', ' ').split()
    except AttributeError: # no .replace or .split
        pass # assume it's already a sequence of identifiers
    field_names = tuple(field_names)
    
    def __init__(self, *args, **kwargs):
        attrs = dict(zip(self.__slots__, args))
        attrs.update(kwargs)
        for name, value in attrs.items():
            setattr(self, name, value)
            
    def __iter__(self):
        for name in self.__slots__:
            yield getattr(self, name)
            
    def __repr__(self):
        values = ', '.join('{}={!r}'.format(*i) for i
                          in zip(self.__slots__, self))
        return '{}({})'.format(self.__class__.__name__, values)
    
    cls_attrs = dict(__slots__ = field_names,
                    __init__ = __init__,
                    __iter__ = __iter__,
                    __repr__ = __repr__)
    
    return type(cls_name, (object,), cls_attrs)

In [26]:
Dog = record_factory('Dog', 'name weight owner')

In [27]:
rex = Dog('Rex', 30, 'Bob')

In [28]:
rex


Out[28]:
Dog(name='Rex', weight=30, owner='Bob')

In [29]:
name, weight, _ = rex

In [30]:
name, weight


Out[30]:
('Rex', 30)

In [31]:
"{2}'s dog weights {1}kg".format(*rex)


Out[31]:
"Bob's dog weights 30kg"

In [32]:
rex.weight = 32

In [33]:
rex


Out[33]:
Dog(name='Rex', weight=32, owner='Bob')

In [34]:
Dog.__mro__


Out[34]:
(__main__.Dog, object)

In [37]:
MyClass = type('MyClass', (object,), {'x':42, 'x2': lambda self: self.x * 2})

In [40]:
help(MyClass)


Help on class MyClass in module __main__:

class MyClass(builtins.object)
 |  Methods defined here:
 |  
 |  x2 lambda self
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  x = 42

A Class Decorator for Customizing Descriptors


In [43]:
import model_v6 as model

In [44]:
@model.entity
class LineItem:
    description = model.NonBlank()
    weight = model.Quantity()
    price = model.Quantity()
    
    def __init__(self, description, weight, price):
        self.description = description
        self.weight = weight
        self.price = price
        
    def subtotal(self):
        return self.weight * self.price

In [45]:
raisins = LineItem('Golden raisins', 10, 6.95)
dir(raisins)[:3]


Out[45]:
['_NonBlank#description', '_Quantity#price', '_Quantity#weight']

In [46]:
LineItem.description.storage_name


Out[46]:
'_NonBlank#description'

In [47]:
raisins.description


Out[47]:
'Golden raisins'

In [48]:
getattr(raisins, '_NonBlank#description')


Out[48]:
'Golden raisins'

What Happens When: Import Time Versus Runtime

The Evaluation Time Excercises


In [50]:
print('<[100]> evalsupport module start')

def deco_alpha(cls):
    print('<[200]> deco_alpha')
    
    def inner_1(self):
        print('<[300]> deco_alpha:inner_1')
        
    cls.method_y = inner_1
    return cls

class MetaAleph(type):
    print('<[400]> MetaAleph body')
    
    def __init__(cls, name, bases, dic):
        print('<[500]> MetaAleph.__init__')
        
        def inner_2(self):
            print('<[600]> MetaAleph.__init__:inner_2')
            
        cls.method_z = inner_2
        
print('<[700]> evalsupport module end')


<[100]> evalsupport module start
<[400]> MetaAleph body
<[700]> evalsupport module end

In [51]:
from evalsupport import deco_alpha

print('<[1]> evaltime module start')

class ClassOne():
    print('<[2]> ClassOne body')
    
    def __init__(self):
        print('<[3]> ClassOne.__init__')
        
    def __del__(self):
        print('<[4]> ClassOne.__del__')
        
    def method_x(self):
        print('<[5]> ClassOne.method_x')
        
    class ClassTwo(object):
        print('<[6]> ClassTwo body')
        
@deco_alpha
class ClassThree():
    print('<[7]> ClassThree body')
    
    def method_y(self):
        print('<[8]> ClassThree.method_y')
        
class ClassFour(ClassThree):
    print('<[9]> ClassFour body')
    
    def method_y(self):
        print('<[10]> ClassFour.method_y')
        
if __name__ == '__main__':
    
    print('<[11]> ClassOne tests', 30 * '.')
    one = ClassOne()
    one.method_x()
    print('<[12]> ClassThree tests', 30 * '.')
    three = ClassThree()
    three.method_y()
    print('<[13]> ClassFour tests', 30 * '.')
    four = ClassFour()
    four.method_y()
    print('<[14]> evaltime module end')


<[1]> evaltime module start
<[2]> ClassOne body
<[6]> ClassTwo body
<[7]> ClassThree body
<[200]> deco_alpha
<[9]> ClassFour body
<[11]> ClassOne tests ..............................
<[3]> ClassOne.__init__
<[5]> ClassOne.method_x
<[12]> ClassThree tests ..............................
<[300]> deco_alpha:inner_1
<[13]> ClassFour tests ..............................
<[10]> ClassFour.method_y
<[14]> evaltime module end

Metaclasses 101


In [ ]: