Amit Kumar | aktech | dtu.amit@gmail.com
An object is created by a class:
>>> Class Foo():
... pass
>>> foo_object = Foo()
Object:
Created by Class Foo:
Foo is also an object, since everything is an object in Python!
Lets see the class which creates Foo:
>>> type(Foo)
type
type? What does that mean?
Now what class creates "type"?
>>> type(type)
type
Inception!
You can create classes with type on the fly!
type( , , )
Name of the
class to be created
tuple of the parent class (for inheritance, can be empty)
dictionary containing attributes names and values
class_name
parent_classes
attributes
>>> class MyClass(object): pass
>>> MyClass
__main__.MyClass
>>> MyClass = type('MyClass', (), {})
>>> MyClass
__main__.MyClass
Both are equivalent!
>>> class Foo(object):
... bar = True
>>> Foo.bar
True
>>> Foo = type('Foo', (), {'bar':True})
>>> Foo.bar
True
=
type accepts a dictionary to define the attributes of the class.
>>> class Car(Foo):
... def wheels(self):
... return 4
>>> car = Car()
>>> car.wheels()
4
>>> def wheels(self):
... return 4
>>> Car = type('Car', (), {'wheels': wheels})
>>> car = Car()
>>> car.wheels()
4
=
Define methods!
This is what happens behind the scenes when you use the keyword class, and it does so by using a "metaclass".
>>> x = 1
>>> type(x)
int
class Car(object):
def WHEELS(self):
return 4
When you do this:
This Happens:
Car = type('Car', (),
{'WHEELS': WHEELS})
Where wheels is:
def WHEELS(self):
return 4
and we would like to change that!
So we will write our custom metaclass to change that behaviour, on top of type metaclass
class LowerAttrMetaclass(type):
def __new__(lowerattr_metaclass, future_class_name,
future_class_parents, future_class_attr):
# do some custom stuff here
# change future_class_attr to lowercase_attr
return type(future_class_name, future_class_parents,
lowercase_attr)
class LowerAttrMetaclass(type):
def __new__(lowerattr_metaclass, future_class_name,
future_class_parents, future_class_attr):
lowercase_attr = {}
for name, val in future_class_attr.items():
if not name.startswith('__'):
lowercase_attr[name.lower()] = val
else:
lowercase_attr[name] = val
return type(future_class_name, future_class_parents,
lowercase_attr)
How would we make our classes use our custom metaclass?
Instead of type!
This is how we make our classes use custom metaclasses:
class Foo():
__metaclass__ = CustomMetaClass
# Do stuff
class Foo(metaclass=CustomMetaClass):
# Do stuff
Python 2
Python 3
Example 1
Example 1
class DocMeta(type):
def __init__(self, name, bases, attrs):
for key, value in attrs.items():
# skip special/private methods
if key.startswith("__"): continue
# skip any non-callable
if not hasattr(value, "__call__"): continue
# check for a doc string.
if not getattr(value, '__doc__'):
raise TypeError("%s must have a docstring" % key)
type.__init__(self, name, bases, attrs)
Example 1
class Door(metaclass=DocMeta):
def __init__(self, number, status):
self.number = number
self.status = status
def open(self):
self.status = 'open'
def close(self):
self.status = 'closed'
>>> D = Door(1, 'open')
Traceback [...]
TypeError: close must have a
docstring
Example 2
Not meant to be instantiated!
Example 2
from abc import (ABCMeta,
abstractmethod)
class Vehicle(object):
__metaclass__ = ABCMeta
@abstractmethod
def change_gear(self):
pass
@abstractmethod
def start_engine(self):
pass
class Car(Vehicle):
def __init__(self, make, model, color):
self.make = make
self.model = model
self.color = color
# abstract methods not implemented
>>> car = Vehicle("Toyota", "Avensis", "silver")
Traceback [..]
TypeError: Can't instantiate abstract class Car
with abstract methods change_gear, start_engine
Example 2
class Car(Vehicle):
def __init__(self, make, model, color):
self.make = make
self.model = model
self.color = color
def change_gear(self):
print("Changing gear")
def start_engine(self):
print("Changing engine")
>>> car = Car("Audi", "A4", "white")
>>> print(isinstance(car, Vehicle))
True
# Now it works!
@iaktech dtu.amit.@gmail.com
This work is licensed under a Creative Commons