理解Python中的元类和继承

理解Python中的元类和继承,python,inheritance,metaclass,Python,Inheritance,Metaclass,我对元类有些困惑 继承 使用元类 正如上面的例子没有实际意义,只是为了理解 我有一些问题,比如 元类和继承之间有什么区别/相似之处 应该在哪里使用元类或继承 1) 元类的用途是什么以及何时使用它 元类与类的关系就像类与对象的关系一样。它们是类的类(因此表达为“meta”) 元类通常用于在OOP的正常约束之外工作的情况 2) 元类和继承之间有什么区别/相似之处 元类不是对象类层次结构的一部分,而基类是。因此,当一个对象执行obj.some_method()操作时,它不会在元类中搜索该方法,但是元类

我对元类有些困惑

继承 使用元类 正如上面的例子没有实际意义,只是为了理解

我有一些问题,比如

  • 元类和继承之间有什么区别/相似之处

  • 应该在哪里使用元类或继承

  • 1) 元类的用途是什么以及何时使用它

    元类与类的关系就像类与对象的关系一样。它们是类的类(因此表达为“meta”)

    元类通常用于在OOP的正常约束之外工作的情况

    2) 元类和继承之间有什么区别/相似之处

    元类不是对象类层次结构的一部分,而基类是。因此,当一个对象执行
    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