我对元类有些困惑。
带继承
class AttributeInitType(object):
def __init__(self,**kwargs):
for name, value in kwargs.items():
setattr(self, name, value)
class Car(AttributeInitType):
def __init__(self,**kwargs):
super(Car, self).__init__(**kwargs)
@property
def description(self):
return "%s %s %s %s" % (self.color, self.year, self.make, self.model)
c = Car(make='Toyota', model='Prius', year=2005, color='green')
print c.description
带有元类
class AttributeInitType(type):
def __call__(self, *args, **kwargs):
obj = type.__call__(self, *args)
for name, value in kwargs.items():
setattr(obj, name, value)
return obj
class Car(object):
__metaclass__ = AttributeInitType
@property
def description(self):
return "%s %s %s %s" % (self.color, self.year, self.make, self.model)
c = Car(make='Toyota', model='Prius', year=2005,color='blue')
print c.description
上面的例子没有实际用处,只是为了理解,
我有一些问题,比如,
元类和继承之间有什么区别/相似之处?
应该在哪里使用元类或继承?
最佳答案
1) 元类有什么用,什么时候用?
元类对类就像类对对象一样。它们是类的类(因此有“元”这个表达)。
元类通常适用于您希望在 OOP 的正常约束之外工作。
2) 元类和继承之间有什么区别/相似之处?
元类不是对象类层次结构的一部分,而基类是。因此,当一个对象执行 obj.some_method()
时,它不会在元类中搜索此方法,但是元类可能在类或对象创建期间创建了它。
在下面的示例中,元类 MetaCar
为对象提供基于随机数的 defect
属性。 defect
属性未在任何对象的基类或类本身中定义。但是,这可以仅使用类来实现。
但是(与类不同),此元类还重新路由对象创建;在 some_cars
列表中,所有的 Toyota 都是使用 Car
类创建的。元类检测到 Car.__init__
包含一个 make
参数,该参数与该名称的预先存在的类匹配,因此返回该类的对象。
此外,您还会注意到,在 some_cars
列表中,Car.__init__
是使用 make="GM"
调用的。 GM
类在程序评估中此时尚未定义。元类在 make 参数中检测到该名称不存在一个类,因此它创建一个并更新全局 namespace (因此它不需要使用返回机制)。然后它使用新定义的类创建对象并返回它。
import random
class CarBase(object):
pass
class MetaCar(type):
car_brands = {}
def __init__(cls, cls_name, cls_bases, cls_dict):
super(MetaCar, cls).__init__(cls_name, cls_bases, cls_dict)
if(not CarBase in cls_bases):
MetaCar.car_brands[cls_name] = cls
def __call__(self, *args, **kwargs):
make = kwargs.get("make", "")
if(MetaCar.car_brands.has_key(make) and not (self is MetaCar.car_brands[make])):
obj = MetaCar.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 MetaCar.car_brands.has_key(self.__name__)):
new_class = MetaCar(make, (GenericCar,), {})
globals()[make] = new_class
obj = new_class(*args, **kwargs)
else:
obj = super(MetaCar, self).__call__(*args, **kwargs)
return obj
class Car(CarBase):
__metaclass__ = MetaCar
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
3) 应该在哪里使用元类或继承?
正如这个答案和评论中提到的,在做 OOP 时几乎总是使用继承。元类用于在这些限制之外工作(请参阅示例),并且几乎总是没有必要,但是可以使用它们实现一些非常高级且极其动态的程序流程。这既是他们的力量,也是他们的危险。
关于python - 理解 Python 中的元类和继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17801344/