Skip to content

Instantly share code, notes, and snippets.

@LaoLiulaoliu
Created February 2, 2016 08:47
Show Gist options
  • Save LaoLiulaoliu/f6aeba58cb63114d9631 to your computer and use it in GitHub Desktop.
Save LaoLiulaoliu/f6aeba58cb63114d9631 to your computer and use it in GitHub Desktop.
several articles to explain how python metaclass works
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: Liu Yuande
# https://jakevdp.github.io/blog/2012/12/01/a-primer-on-python-metaclasses/
# http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python
# http://stackoverflow.com/questions/17801344/python-understanding-metaclass-and-inheritance
# give a name, create a new car class. define the class in a more dynamic way.
# classes can inherit properties from parents and add or specialize attributes and methods.
# classes are objects, and they are objects of type type. type is a metaclass: a class which instantiates classes. All new-style classes in Python are instances of the type metaclass, including type itself. type is an instance of itself.
import random
class CarBase(object):
pass
class meta_car(type):
car_brands = {}
def __init__(cls, cls_name, cls_bases, cls_dict):
super(meta_car, cls).__init__(cls_name, cls_bases, cls_dict)
if(not CarBase in cls_bases):
meta_car.car_brands[cls_name] = cls
def __call__(self, *args, **kwargs):
make = kwargs.get("make", "")
if meta_car.car_brands.has_key(make) and not (self is meta_car.car_brands[make]):
obj = meta_car.car_brands[make].__call__(*args, **kwargs)
if(make == "Toyota"):
if(random.randint(0, 100) < 2):
obj.defect = "sticky accelerator pedal"
elif(make == "GM"):
if(random.randint(0, 100) < 20):
obj.defect = "shithouse"
elif(make == "Great Wall"):
if(random.randint(0, 100) < 101):
obj.defect = "cancer"
else:
obj = None
if not meta_car.car_brands.has_key(self.__name__):
new_class = meta_car(make, (GenericCar,), {})
globals()[make] = new_class
obj = new_class(*args, **kwargs)
else:
obj = super(meta_car, self).__call__(*args, **kwargs)
return obj
class Car(CarBase):
__metaclass__ = meta_car
def __init__(self, **kwargs):
for name, value in kwargs.items():
setattr(self, name, value)
def __repr__(self):
return "<%s>" % self.description
@property
def description(self):
return "%s %s %s %s" % (self.color, self.year, self.make, self.model)
class GenericCar(Car):
def __init__(self, **kwargs):
kwargs["make"] = self.__class__.__name__
super(GenericCar, self).__init__(**kwargs)
class Toyota(GenericCar):
pass
colours = \
[
"blue",
"green",
"red",
"yellow",
"orange",
"purple",
"silver",
"black",
"white"
]
def rand_colour():
return colours[random.randint(0, len(colours) - 1)]
some_cars = \
[
Car(make="Toyota", model="Prius", year=2005, color=rand_colour()),
Car(make="Toyota", model="Camry", year=2007, color=rand_colour()),
Car(make="Toyota", model="Camry Hybrid", year=2013, color=rand_colour()),
Car(make="Toyota", model="Land Cruiser", year=2009, color=rand_colour()),
Car(make="Toyota", model="FJ Cruiser", year=2012, color=rand_colour()),
Car(make="Toyota", model="Corolla", year=2010, color=rand_colour()),
Car(make="Toyota", model="Hiace", year=2006, color=rand_colour()),
Car(make="Toyota", model="Townace", year=2003, color=rand_colour()),
Car(make="Toyota", model="Aurion", year=2008, color=rand_colour()),
Car(make="Toyota", model="Supra", year=2004, color=rand_colour()),
Car(make="Toyota", model="86", year=2013, color=rand_colour()),
Car(make="GM", model="Camaro", year=2008, color=rand_colour())
]
dodgy_vehicles = filter(lambda x: hasattr(x, "defect"), some_cars)
print dodgy_vehicles
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment