理解Python中的元类和继承
我对元类有些困惑 继承 使用元类 正如上面的例子没有实际意义,只是为了理解 我有一些问题,比如理解Python中的元类和继承,python,inheritance,metaclass,Python,Inheritance,Metaclass,我对元类有些困惑 继承 使用元类 正如上面的例子没有实际意义,只是为了理解 我有一些问题,比如 元类和继承之间有什么区别/相似之处 应该在哪里使用元类或继承 1) 元类的用途是什么以及何时使用它 元类与类的关系就像类与对象的关系一样。它们是类的类(因此表达为“meta”) 元类通常用于在OOP的正常约束之外工作的情况 2) 元类和继承之间有什么区别/相似之处 元类不是对象类层次结构的一部分,而基类是。因此,当一个对象执行obj.some_method()操作时,它不会在元类中搜索该方法,但是元类
obj.some_method()
操作时,它不会在元类中搜索该方法,但是元类可能在类或对象的创建过程中创建了它
在下面的示例中,元类MetaCar
基于随机数为对象提供了defect
属性。缺陷
属性未在任何对象的基类或类本身中定义。然而,这只能通过使用类来实现
但是(与类不同),这个元类也重新路由对象创建;在some_cars
列表中,所有丰田汽车都是使用Car
类创建的。元类检测到Car.\uuuu init\uuuu
包含一个make
参数,该参数通过该名称匹配预先存在的类,因此返回该类的对象
此外,您还将注意到,在some\u cars
列表中,Car.\uuuu init\uuuu
使用make=“GM”
调用。在计划评估的这一点上,GM
类尚未定义。元类在make参数中检测到不存在该名称的类,因此它创建一个类并更新全局名称空间(因此不需要使用返回机制)。然后,它使用新定义的类创建对象并返回它
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
随机导入
类别CarBase(对象):
通过
MetaCar类(类型):
汽车品牌={}
定义初始值(cls,cls,cls,cls,cls,cls,cls):
超级(MetaCar,cls)。\uuuuu初始(cls\u名称,cls\u基,cls\u dict)
如果(不是cls_碱中的碳基):
MetaCar.汽车品牌[cls\U名称]=cls
定义调用(self,*args,**kwargs):
make=kwargs.get(“make”,“”)
如果(MetaCar.car\u brands.有钥匙(make)而没有钥匙(self是MetaCar.car\u brands[make]):
obj=MetaCar.car\u品牌[make]。\u呼叫(*args,**kwargs)
如果(品牌=“丰田”):
if(random.randint(01100)<2):
obj.defect=“油门踏板粘滞”
elif(制造=“GM”):
if(random.randint(01100)<20):
obj.defect=“厕所”
elif(make==“长城”):
if(random.randint(01100)<101):
obj.defect=“癌症”
其他:
obj=无
如果(非MetaCar.car\u brands.有钥匙(自己的姓名)):
new_class=MetaCar(make,(GenericCar,),{})
globals()[make]=新的\u类
obj=新的_类(*args,**kwargs)
其他:
obj=super(MetaCar,self)。\调用(*args,**kwargs)
返回obj
等级车辆(碳基):
__元类\元卡
定义初始(自我,**kwargs):
对于名称,kwargs.items()中的值:
setattr(自身、名称、值)
定义报告(自我):
返回“%self.description”
@财产
def说明(自我):
返回“%s%s%s%s”%(self.color、self.year、self.make、self.model)
类别通用汽车(Car):
定义初始(自我,**kwargs):
kwargs[“make”]=自我名称__
超级(通用汽车,自我)。\uuuuuu初始(**kwargs)
丰田级(通用汽车):
通过
颜色=\
[
“蓝色”,
“绿色”,
“红色”,
“黄色”,
“橙色”,
“紫色”,
“银”,
“黑色”,
“白色”
]
def rand_color():
返回颜色[random.randint(0,len(颜色)-1]
有些车=\
[
汽车(make=“Toyota”,model=“Prius”,年份=2005,颜色=rand_color()),
汽车(make=“Toyota”,model=“Camry”,年份=2007,颜色=rand_color()),
汽车(make=“Toyota”,model=“Camry Hybrid”,年份=2013,颜色=rand_color()),
汽车(make=“丰田”,model=“陆地巡洋舰”,年份=2009,颜色=rand\u color()),
汽车(make=“Toyota”,model=“FJ Cruiser”,年份=2012,颜色=rand_color()),
汽车(make=“Toyota”,model=“Corolla”,年份=2010,颜色=rand_color()),
汽车(make=“Toyota”,model=“Hiace”,year=2006,color=rand\u color()),
汽车(make=“Toyota”,model=“Townace”,year=2003,color=rand\u color()),
汽车(make=“Toyota”,model=“Aurion”,year=2008,color=rand\u color()),
汽车(make=“Toyota”,model=“Supra”,年份=2004,颜色=rand_color()),
汽车(make=“Toyota”,model=“86”,年份=2013,颜色=rand_color()),
汽车(make=“GM”,model=“Camaro”,年份=2008,颜色=rand\u color())
]
危险车辆=过滤器(lambda x:hasattr(x,“缺陷”),一些车辆)
打印危险车辆
3) 应该在哪里使用元类或继承
正如本回答和评论中提到的,在执行OOP时,几乎总是使用继承。元类用于在这些约束之外工作(参考示例),几乎总是不必要的,但是可以使用它们实现一些非常高级且非常动态的程序流。这是他们的力量和危险的经验法则:如果你没有元类也能做到,就不要使用元类。如果你不得不问你是否需要元类,你就不需要元类。这不是元类的重复。这是关于元类与继承的讨论。谢谢dilbert。。gr8解释此差异可以从以下方面注意到:对于元类,issubclass(Car
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
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