理解Python中的元类和继承[重复]

2024-05-03

我对元类有一些困惑。

具有继承性

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. 元类和继承之间有什么区别/相似之处?

  2. 应该在哪里使用元类或继承?


1)元类有什么用以及何时使用它?

元类对于类就像类对于对象一样。它们是类的类(因此称为“元”)。

元类通常适用于您想要在 OOP 的正常约束之外工作的情况。

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

元类不是对象类层次结构的一部分,而基类则是。所以当一个对象这样做时obj.some_method()它不会在元类中搜索此方法,但是元类可能在类或对象的创建过程中创建了它。

在下面的示例中,元类MetaCar给对象一个defect基于随机数的属性。这defect属性未在任何对象的基类或类本身中定义。然而,这可以仅使用类来实现。

然而(与类不同),这个元类还重新路由对象创建;在里面some_cars列表中,所有丰田汽车都是使用Car班级。元类检测到Car.__init__包含一个make参数与该名称的预先存在的类相匹配,因此返回该类的对象。

此外,您还会注意到,在some_cars list, Car.__init__被称为make="GM". A 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

3)应该在哪里使用元类或继承?

正如这个答案和评论中提到的,在进行 OOP 时几乎总是使用继承。元类用于在这些限制之外工作(请参阅示例),并且几乎总是不必要的,但是一些非常先进和极其动态程序流程可以用它们来实现。这既是他们的力量,也是他们的danger.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

理解Python中的元类和继承[重复] 的相关文章

随机推荐

  • 使用创建的 201 进行重定向

    有没有办法通过 201 答案重定向 RFC规定新创建的资源必须在Location标题 我确实指定了它 我假设浏览器会重定向 但事实并非如此 即使页面没有内容 我希望用户在 POST 操作之后重定向到新资源 因此我很想使用303 See Ot
  • 如何修复 lldb 在运行调用后立即停止的问题?

    我在 Mojave 上使用 lldb 和 Xcode 10 2 1 一旦命令 运行 到 lldb 就会发生这种情况 lldb target create
  • 如果可观察对象之一停止发出事件,为什么 Observable.race 无法工作?

    如果互联网连接丢失 我想在 webapp 中实现 websocket 重新连接 为了检测互联网是否丢失 我使用乒乓方法 这意味着我从客户端发送 ping 消息 服务器返回给我 pong 消息 当 webapp 加载时 我发送 init pi
  • Leaflet.js setMaxBounds 忽略南界

    Using 传单 js http leafletjs com reference html对于开源地图项目 但我需要设置用户无法超越的特定界限 地图对象的 maxBounds 属性在北 东 西方向上按预期工作 但它让我永远向南滚动 在小提琴
  • “NoneType”对象不可订阅?

    list1 name1 info1 10 list2 name2 info2 30 list3 name3 info3 50 MASTERLIST list1 list2 list3 def printer lst print Availa
  • 为什么设置 POST Content-type:"Application/Json" 会导致 REST WebService 上出现“错误请求”?

    我在使用网络服务时遇到一个奇怪的问题 当我作为客户端将表单发布到 REST Web 服务而不设置任何 类型内容 标头时 一切正常 我接到服务器上的电话并且 Json 文本可用 如果我作为客户端将我的发布请求的内容类型标头设置为 applic
  • 为 Visual Studio 应用程序设置平台目标的目的是什么?

    对于任何 VS 项目 都可以在该项目的构建属性中设置平台目标 您可以将其设置为任何 CPU x86 x64 或 Itanium 我的问题是 如果我将此值设置为 x86 是否意味着我无法在 x64 计算机上运行该项目 如果是这样 为什么还要使
  • 为什么 urllib2 出现 urllib2.HTTPError 而 urllib 没有错误?

    我有以下简单的代码 import urllib2 import sys sys path append BeautifulSoup BeautifulSoup 3 1 0 1 from BeautifulSoup import page h
  • 如何从同一项目生成两个声纳报告?

    我想从同一项目创建两组声纳报告 一种会涵盖所有内容 另一种会排除一些包裹 这可能吗 如果可以 该怎么做 编辑 设置排除不是问题 但有两个报告才是问题 在 Maven 中创建新的配置文件 并为每个配置文件添加带有新分支的呼叫声纳 mvn cl
  • 在正则表达式中搜索连字符和破折号的所有变体

    我一直在尝试从转换为文本文件的 PDF 中提取某些文本 PDF 来自各种来源 我不知道它们是如何生成的 我试图提取的模式只是一个简单的两位数字 后跟一个连字符 然后是另外两位数字 例如12 34 所以我写了一个简单的正则表达式 d d d
  • 同位素 Jquery 插件布局问题

    我正在尝试在此站点上设置同位素 它需要处理布局 并且我需要能够将项目附加到容器中 问题是它似乎没有正确初始化图像 这是我初始化它的方法 document ready function var container container cont
  • 打印富文本框

    我正在制作一个简单的 WinForms 应用程序 我想允许用户从 RichTextBox 打印文本 我跟着MSDN链接 https msdn microsoft com en us library cwbe712d v vs 110 asp
  • .net core 2.2 & Angular 7:文件上传控制器中的 IFormFile 始终为 null

    当查看其他答案和一些谷歌时 一切似乎都很好 但我的控制器从未收到任何数据 api uris等正确 请求到达正确的控制器 角度片段 component html 我的输入字段 div class input group div
  • Wildfly Undertow 文件 Mimetypes

    我希望 Undertow 提供静态文件 如 jpg png js css txt 等 我在standalone xml中编辑了undertow子系统
  • 指定 purecss 网格的折叠顺序

    我想要一个 purecss 网格 当它折叠时 即较小屏幕上的断点 是否可以使右侧网格项出现在左侧网格项之前 即某种崩溃命令 我相信使用 Flexbox 模型可以实现这些目标 但我不是这方面的专家 所以非常感谢指导 Thanks PureCS
  • 返回 const std::string 真的比非 const 慢吗?

    在另一个问题中 用户评论说返回 const std string 会损失移动构造效率并且速度更慢 分配此方法的返回字符串真的是这样吗 const std string toJson const std string someText con
  • Excel:如何通过VBA搜索电子表格1值是否存在于电子表格2中

    在电子表格 1 中 B 列包含值 即 V 9999 我正在尝试查看电子表格 2 的 B 列中是否存在这些值 我遇到的问题是 每次更新电子表格时数据都会发生变化 并且 B 列中的每行之间并不总是 1 1 匹配 例如 V 9999 可能存在于电
  • Azure 角色配置管理

    当您别无选择只能在 web config 或 app config 中保存配置设置时 我不明白 Windows Azure 如何让您改变应用程序的配置 例如 项目经常会使用大量使用 web config 的第三方库 web config 的
  • 如何读取未知数量的输入?

    我正在使用 C Primer 这本书学习 C In 第1 4 3节 给出了以下关于读取未知数量的输入的示例代码 include
  • 理解Python中的元类和继承[重复]

    这个问题在这里已经有答案了 我对元类有一些困惑 具有继承性 class AttributeInitType object def init self kwargs for name value in kwargs items setattr