Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >python metaclass 详细说明

python metaclass 详细说明

作者头像
用户5760343
发布于 2019-12-13 07:10:48
发布于 2019-12-13 07:10:48
57800
代码可运行
举报
文章被收录于专栏:sktjsktj
运行总次数:0
代码可运行

<meta charset="utf-8">

Class也是Object

在理解metaclass之前,我们需要先理解Python中的class。从某种程度上来说,Python中的class的定位比较特殊。

对于大部分面向对象语言来说,class是一段定义了如何产生object的代码块。在Python中这一定义也成立:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> class example(object):
...     pass
...
>>> object1 = example()
>>> print(object1)
<__main__.example object at 0x102e26990>

但是在Python中,class并不只有这一角色。class实际上也是object。当我们使用class定义一个类的时候,Python会执行相应代码并在内存中创建一个名为example的object。

但该object(class)是具有创建其他object(instance)的能力的。这也是这个object是一个class的原因。由于本质上class任然是一个object,所以我们可以对class做出以下操作:

  • 我们可以将其赋给一个变量
  • 我们可以对其进行拷贝
  • 我们可以赋给其新的变量
  • 我们可以将其作为参数赋给其他的函数

举例如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# print a class since it's an object
>>> print(example)
<class '__main__.example'>

# assign an attribute to the class
>>> print(hasattr(example, 'new_attribute'))
False
>>> example.new_attribute = 'assign an attribute to the class'
>>> print(hasattr(example, 'new_attribute'))
True
>>> print(example.new_attribute)
assign an attribute to the class

# assign the class to a variable
>>> example_mirror = example
>>> print(example_mirror)
<class '__main__.example'>
>>> print(example_mirror())
<__main__.example object at 0x102e26a90>

# pass class as a parameter
>>> def echo(cls):
...     print(cls)
...
>>> echo(example)
<class '__main__.example'>

动态创建class

既然class也是object,那么我们就可以像创建普通的object一样动态创建class。

第一种方法,我们可以在方法中创建class。如下面的例子所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> def dynamic_class_creater(name):
...     if name == 'name1':
...         class class1(object):
...             pass
...         return class1
...     else:
...         class class2(object):
...             pass
...         return class2
...
>>> first_class = dynamic_class_creater('name1')
>>> print(first_class)
<class '__main__.class1'>
>>> print(first_class())
<__main__.class1 object at 0x10e4149d0>

但通过这种方式创建class并没有特别动态。我们任然需要自己定义类的具体内容。考虑到class也是object,那么也一定有某种方法能够像产生instance一样产生类。

当我们使用class关键字创建类的时候,Python会自动创建对应的object。像Python中其他大多数情况一样,我们也可以手动创建这个class object。这一操作可以通过type()实现。

通常情况下我们可以调用type来得到一个object的类型是什么。如下面的例子所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> print(type(1))
<type 'int'>

>>> print(type('str'))
<type 'str'>

>>> print(type(example()))
<class '__main__.example'>

>>> print(type(example))
<type 'type'>

在这里我们看到我们所创建example类的type是'type'。这实际上也就是接下来要讨论的内容。既type的完全不同的功能——type可以动态创建class。type()函数可以接收class的描述来作为参数并返回所生成的class object。type同时具有这两个迥异的功能是由于Python兼容性问题导致的。在此我们不做深究。

当使用type创建class时,其用法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type(class_name, tuple_of_parent_class, dict_of_attribute_names_and_values)

其中第二个参数tuple_of_parent_class用来表示继承关系,可以为空。第三个参数用来描述我们所要创建的类所应该具有的attribute。如下面的例子所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>>class class_example(object):
...     pass

上面定义的这个类可以由如下type函数创建:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>>class_example = type('class_example', (), {}) # create a class on the fly
>>>print(class_example)
<class '__main__.class_example'>
>>> print(class_example()) # get a instance of the class
<__main__.class_example object at 0x10e414b10>

在这个例子中,type所接收的第一个参数'class_example'是该类的类名,同时我们使用了class_example作为存储该class object引用的变量。这二者可以不同。但一般我们没有理由采用不同的名字从而使得代码更加复杂。

我们也可以使用一个字典来定义所创建的class的attribute:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> class_example = type('class_example', (), {'attr': 1})
>>> print(class_example)
<class '__main__.class_example'>
>>> print(class_example.attr)
1
>>> print(class_example())
<__main__.class_example object at 0x10e414a90>
>>> print(class_example().attr)
1

上面的例子中type返回的class等同于下面这个class:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> class class_example(object):
...     attr = 1

当然,我们也可以用type返回一个继承class_example的类:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> child_example = type('child_example', (class_example,), {})
>>> print(child_example)
<class '__main__.child_example'>
>>> print(child_example.attr)
1

上面这个例子中type返回的class等同于如下class:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> class child_example(class_example):
...     pass

我们甚至可以动态创建包括方法的类。只要我们创建好方法并将其赋给相应的attribute即可:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> def echo(self):
...     print(self.attr)
...
>>> child_example = type('child_example', (class_example,), {'echo': echo})
>>> hasattr(class_example, 'echo')
False
>>> hasattr(child_example, 'echo')
True
>>> child_example().echo()
1

同样,我们也可以先动态创建一个class,然后再赋给其新的方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> child_example = type('child_example', (class_example,), {})
>>> def another_method(self):
...     print('another method')
...
>>> child_example.another_method = another_method
>>> hasattr(child_example, 'another_method')
True
>>> child_example().another_method()
another method

综上所述,Python中的class其实是一个object,并且我们可以动态创建class。事实上这也是我们在使用class关键字的时候Python所做的事情。Python通过使用metacalss来实现这一过程。

究竟什么是metaclass?

metaclass就是Python中用来创建class object的class。我们可以将其看做能够产生class的类工厂。我们可以通过如下例子理解这个关系:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class = metaclass()
object = class()

从上文中我们知道了type()可以被用来动态创建class,这是因为实际上type是一个metaclass。而且type实际上是Python用在在幕后创建所有class的metaclass。

包括int, string, function, class在内,Python中所有的东西都是object,而所有的object都是被相应的class创造的。我们可以通过__class__的值得知这一点。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> age = 24
>>> age.__class__
<type 'int'>

>>> name = 'bob'
>>> name.__class__
<type 'str'>

>>> def foo(): pass
>>> foo.__class__
<type 'function'>

>>> class Bar(object): pass
>>> bar = Bar()
>>> bar.__class__
<class '__main__.Bar'>

那么,这些__class____class__又是什么呢?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> age.__class__.__class__
<type 'type'>
>>> name.__class__.__class__
<type 'type'>
>>> foo.__class__.__class__
<type 'type'>
>>> bar.__class__.__class__
<type 'type'>

可以看出,所有的class都来自于typetype,作为metaclass,创建了以上所有的class object。

type是Python定义好的metaclass。当然,我们也可以自定义metaclass。

类的metaclass attribute

当定义class的时候,我们可以使用__metaclass__ attribute来指定用来初始化当前class的metaclass。如下面的例子所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Foo(object):
    __metaclass__ = something
    [other statements...]

如果我们指定了__metaclass__,Python就是使用这个metaclass来生成class Foo

当Python试图创建class Foo的时候,Python会首先在class的定义中寻找__metaclass__ attribute。如果存在__metaclass__,Python将会使用指定的__metaclass__来创建class Foo。如果没有指定的话,Python就会使用默认的type作为metaclas创建Foo

所以,对于下面这个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Foo(Bar):
    pass

Python首先在Foo中寻找是否存在__metaclass__ attribute。

如果存在的话,Python将使用这个metaclass在内存中创建一个名字为Foo的class object。如果Python

如果class定义中不存在__metaclass__的话,Python将会寻找MODULE级别的__metaclass__。如果存在的话鸠进行与前述相同的操作。但是只有我们定义的class没有继承任何类的情况下,Python才会在MODULE级别寻找__metaclass__。或者说,只有当该类是一个旧类的情况下,Python才会在MODULE级别寻找__metaclass__。(关于新类和旧类的区别,请看这篇文章).

当Python仍然没有找到__metaclass__时,Python将会使用当前类的母类的metaclass来创建当前类。在我们上面这个例子中,Python会使用Foo的母类Bar的metaclass来创建Foo的class object。

同时需要注意的是,在class中定义的__metaclass__ attribute并不会被子类继承。被子类继承的是母类的metaclass,也就是母类的.__class__ attribute。比如上面的例子中,Bar.__class__将会被Foo继承。也就是说,如果Bar定义了一个__metaclass__ attribute来使用type()创建Bar的class object(而非使用type.__new__()),那么Bar的子类,也就是Foo,并不会继承这一行为。

那么问题来了:我们究竟应该在__metaclass__ attribute中定义什么?

答案是:能够创建class的东西。

那么什么能够创建class呢?type,或者任何type的子类。

自定义metaclass

metaclass的主要目的是在class被创建的时候对生成的class进行自动的动态修改。

一般来说,这一点主要应用于API,例如我们想要根据当前的内容创建相匹配的class。

举一个简单的例子如下:我们决定让当前module下所有的class的attribute的名字都是大写。要实现这个功能有很多种方法。使用__metaclass__就是其中之一。

设置了__metaclass__的话,class的创建就会由指定的metaclass处理,那么我们只需要让这个metaclass将所有attribute的名字改成大写即可。

__metaclass__可以是任何Python的callable,不必一定是一个正式的class。

下面我们首先给出一个使用function作为__metaclass__的例子。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# the metaclass will automatically get passed the same argument 
# that is passed to `type()`
def upper_attr(class_name, class_parents, class_attr):
    '''Return a class object, with the list of its attribute turned into 
    uppercase.
    '''
    # pick up any attribute that doesn't start with '__' and turn it into uppercase.
    uppercase_attr = {}
    for name, val in class_attr.items():
        if name.startswith('__'):
            uppercase_attr[name] = val
        else:
            uppercase_attr[name.upper()] = val

    # let `type` do the class creation
    return type(class_name, class_parents, uppercase_attr)

class Foo(object):
    # this __metaclass__ will affect the creation of this new style class
    __metaclass__ = upper_attr
    bar = 'bar'

print(hasattr(Foo), 'bar')
# False

print(hasattr(Foo), 'BAR')
# True

f = Foo()
print(f.BAR)
# 'bar'

接下来我们通过继承type的方式实现一个真正的class形式的metaclass。注意如果尚不清楚__new____init__的作用和区别的,请看这篇文章.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# remember that `type` is actually a just a class like int or str
# so we can inherit from it.

class UpperAttrMetaclass(type):
    '''
    __new__ is the method called before __init__
    It's the function that actually creates the object and returns it.
    __init__ only initialize the object passed as a parameter.
    We rarely use __new__, except when we want to control how the object
    is created.
    For a metaclass, the object created is a class. And since we want to 
    customize it, we need to override __new__.
    We can also do something by overriding __init__ to get customized initialization
    process as well.
    Advanced usage involves override __call__, but we won't talk about this here.
    '''
    def __new__(upperattr_metaclass, class_name, class_parents, class_attr):
        uppercase_attr = {}
        for name, val in class_attr.items():
            if name.startswith('__'):
                uppercase_attr[name] = val
            else:
                uppercase_attr[name.upper()] = val
        return type(class_name, class_parents, uppercase_attr)

但这不是很OOP。我们直接调用了type而非调用type.__new__。那么OOP的做法如下。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class UpperAttrMetaclass(type):
    def __new__(upperattr_metaclass, class_name, class_parents, class_attr):
        uppercase_attr = {}
        for name, val in class_attr.items():
            if name.startswith('__'):
                uppercase_attr[name] = val
            else:
                uppercase_attr[name.upper()] = val
        # basic OOP. Reuse the parent's `__new__()`
        return type.__new__(upperattr_metaclass, class_name, class_parents, uppercase_attr)

我们注意到,__new__所接收的参数中有一个额外的upperattr_metaclass。这没有什么特别的。如同__init__总是接收调用它的object作为第一个参数一样(惯例上用self来命名__init__所接收的第一个参数),__new__总是接收其被定义在内的class作为第一个参数,就像类方法总是接收其被定义的class作为第一个参数一样(惯例上用cls命名类方法所接收的第一个参数)。

清楚起见,这里给出的例子的变量和方法名都很长。但在实际的应用中,类似于使用selfcls代替第一个参数,我们可以将这些名字替换为更加简洁的形式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class UpperAttrMetaclass(type):
    def __new__(cls, cls_name, bases, attr_dict):
        uppercase_attr = {}
        for name, val in attr_dict.items():
            if name.startswith('__'):
                uppercase_attr[name] = val
            else:
                uppercase_attr[name.upper()] = val
        return type.__new__(cls, cls_name, bases, uppercase_attr)

通过应用super,我们可以使得上面这段代码更加干净简洁,也使得继承更加容易(我们可能有metaclass继承别的一些metaclass,而这些metaclass又继承type):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class UpperAttrMetaclass(type):
    def __new__(cls, cls_name, bases, attr_dict):
        uppercase_attr = {}
        for name, val in attr_dict.items():
            if name.startswith('__'):
                uppercase_attr[name] = val
            else:
                uppercase_attr[name.upper()] = val
        return super(UpperAttrMetaclass, cls).__new__(cls, cls_name, bases, uppercase_attr)

Voilà!上述基本就是关于metaclass的一切了。

使用metaclass之所以复杂,不是因为其代码实现复杂,而是因为我们一般使用metaclass来做一些逻辑上很复杂的操作,例如自省,修改继承以及改变类的默认attribute如__dict__等。

metaclass的确可以被用来实现一些奇妙的功能,也因此可以用来进行极其复杂的逻辑操作。但是metaclass本身是很简单的:

  • 影响class初始化的过程
  • 修改class的内容
  • 返回修改过的class

为什么我们要使用metaclass,而不是使用一些函数来实现类似的功能?

就像前文所说,__metaclass__实际上可以是任何callable,那么为什么我们还要使用metaclass而不是直接调用这些函数呢?

使用class作为metaclass有如下几个理由:

  • 使用class作为metaclass能够使得我们代码的动机更加明确。比如当我们读到上面所定义的UpperAttrMetaclass(type)代码时,我们清楚地知道接下来这段代码想要干什么(自定义class object初始化的过程)。
  • 我们能够使用OOP的思想进行处理。class作为metaclass可以继承其他的metaclass,重载母类的方法,甚至可以使用别的metaclass。
  • 如果我们使用class作为metaclass,某一使用该metaclass的class的子类将仍是是其metaclass的实例。但这一功能无法通过使用函数作为metaclass实现。
  • 使用metaclass可以使得代码结构更加优美。实际应用中我们很少使用metaclass来实现上面那样简单的功能。使用metaclass往往是为了实现非常复杂的操作。如果使用class作为metaclass,我们就可以把相应的方法封装到这一个metaclass中,使得代码更加易懂。
  • 使用class作为metaclass可以在class中容易的定义__new____init____call__方法。虽然我们在将所有的逻辑都放入__new__中,但有的时候根据需要使用其他几个方法会使得逻辑更加清晰。
  • 额贼!人家名字就叫metaclass。这不是带着个class吗?

为什么我们要使用metaclass呢?

那么究竟为什么我们要使用metaclass这样一个难以理解且容易出错的实现方式呢?

答案是通常情况下我们不需要使用metaclass。

引用Python大师Tim Peters的话来说,就是:

Metaclasses are deeper magic that 99% of users should never worry about. If you wonder whether you need them, you don't (the people who actually need them know with certainty that they need them, and don't need an explanation about why).

metaclass主要的使用情况就是用来创建API。使用metaclass的一个典型的例子是Django ORM

它是的我们可以使用如下当时定义一个model:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Person(models.Model):
    name = models.CharField(max_length=30)
    age = models.IntegerField()

同时,如果我们调用这个model:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
guy = Person(name='bob', age='35')
print(guy.age)

其并不会返回一个IntegerField对象,而是会返回一个int,甚至可以直接从数据库中调用这个值。

正是因为models.Model定义了__metaclass__,并使用了一些操作来将我们使用简单的语句定义的Person转化成了与数据库相应的域相联系的类,这种逻辑才成为可能。

Django使得很多复杂的逻辑仅暴露一个简单的API接口就可以调用,这正是通过metaclass实现的。metaclass会根据需要重新实现这些复杂操作所需要的真正的代码。

再说两句

首先我们知道了Python中的class实际上是object,同时class仍具有创建对应的实例的能力。

实际上class本身也是metaclass的实例。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> class Foo(object):
...     pass
...
>>> id(Foo)
4299321816

Python中的任何东西都是object,这些object不是class的实例就是metaclass的实例。

当然,type除外。

type事实上是其自身的metaclass。我们使用Python是无法重复这种实现的。这一逻辑是在Python代码实现的层面定义的。引用一下道德经中的说法,我们可以说Python中type生metaclass,metaclass生class,class生万物

另外,metaclass的应用一般颇为复杂,大多数情况下我们可以使用别的方法实现相同的功能。比如我们可以通过一下两种技术修改class:

  • monkey patching
  • class decorators

99%我们需要改变class的情况下,我们使用上述两种技术可以解决。

但事实是,99%的情况下我们根本不需要改变class。

作者:耀凯考前突击大师 链接:https://www.jianshu.com/p/224ffcb8e73e 来源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
深入理解Python中的元类(metaclass)
在理解元类之前,你需要先掌握Python中的类。Python中类的概念借鉴于Smalltalk,这显得有些奇特。在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段。在Python中这一点仍然成立:
Jetpropelledsnake21
2019/02/15
4620
Python教程第7章 | 元类
在了解元类之前,我们先进一步理解 Python 中的类,在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段。在 Python 中这一点也是一样的。
仲君Johnny
2024/01/24
1740
Python教程第7章 | 元类
Python(一)对 meta class 的理解
1. 理解  class 对于 class 来说,表示一个代码块规定了实例化后的 object 的属性和方法 但是在 Python 中,class 本身也是对象。定义一个 class,就相当于在内存中实例化了一个名为 className 的对象 作为一个对象,因此具备以下能力: 赋值给一个变量 对其拷贝 作为函数参数 class Example(object): pass object1 = Example() print(object1) # prints '<__main__.Exampl
西凉风雷
2022/11/23
3040
探寻Python类的鼻祖——元类
在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段。在 Python 中这一点仍然成立:
忆想不到的晖
2021/05/04
9630
什么是元类metaclass?
在理解元类之前,需要先掌握Python中的类,Python中类的概念与SmallTalk中类的概念相似。 在大多数语言中,类是用来描述如何创建对象的代码段,这在Python中也是成立的:
用户2936342
2018/08/27
4240
【python进阶】详解元类及其应用2
前言 在上一篇文章【python进阶】详解元类及其应用1中,我们提到了关于元类的一些前置知识,介绍了类对象,动态创建类,使用type创建类,这一节我们将继续接着上文来讲~~~ 5.使⽤type创建带有⽅法的类 最终你会希望为你的类增加⽅法。只需要定义⼀个有着恰当签名的函数并将 其作为属性赋值就可以了。 添加实例⽅法 In [14]: def echo_bar(self):#定义了一个普通的函数 ...: print(self.bar) ...: In [15]: FooChild
Angel_Kitty
2018/05/04
6530
每天一道 python 面试题 - Python中的元类(metaclass) 详细版本
在理解元类之前,您需要掌握Python的类。Python从Smalltalk语言中借用了一个非常特殊的类概念。
公众号---人生代码
2020/05/02
6390
每天一道 python 面试题 - Python中的元类(metaclass) 详细版本
比Python更牛的语言有吗?看我用元类(metaclass)花式创建Python类
为了让更多的人看到本文,请各位读者动动小手,点击右上角【...】,将本文分享到朋友圈,thanks!
蒙娜丽宁
2020/11/04
8730
面向对象进阶
issubclass(sub, super)检查sub类是否是 super 类的派生类
py3study
2020/01/16
3670
面向对象进阶
python类和元类
       今天在网上看到一篇关于python语言中类和元类(metaclass)的一些讲解和简单运用,感觉对python入门的童鞋非常有帮助,分享出来,希望大家喜欢。 (一) python中的类 今天看到一篇好文,然后结合自己的情况总结一波。 这里讨论的python类,都基于python2.7x以及继承于object的新式类进行讨论。 首先在python中,所有东西都是对象。这句话非常重要要理解元类我要重新来理解一下python中的类。 class Trick(object):     pass 当python在执行带class语句的时候,会初始化一个类对象放在内存里面。例如这里会初始化一个Trick对象。 这个对象(类)自身拥有创建对象(通常我们说的实例,但是在python中还是对象)的能力。 为了方便后续理解,我们可以先尝试一下在新式类中最古老厉害的关键字type。 input: class Trick(object): pass print type('123') print type(123) print type(Trick()) output: <type 'str'> <type 'int'> <class '__main__.Trick'> 可以看到能得到我们平时使用的 str, int, 以及我们初始化的一个实例对象Trick() 但是下面的方法你可能没有见过,type同样可以用来动态创建一个类 type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值)) 这个怎么用呢,我要用这个方法创建一个类 让我们看下下面的代码 input: print type('trick', (), {}) output: <class '__main__.trick'> 同样我们可以实例化这个类对象 input: print type('trick', (), {})() output: <__main__.trick object at 0x109283450> 可以看到,这里就是一个trick的实例对象了。 同样的这个方法还可以初始化创建类的父类,同时也可以初始化类属性: input: class FlyToSky(object):     pass pw = type('Trick', (FlyToSky, ), {'laugh_at': 'hahahaha'}) print pw().laugh_at print pw.__dict__ print pw.__bases__ print pw().__class__ print pw().__class__.__class__ output: hahahaha {'__module__': '__main__', 'laugh_at': 'hahahaha', '__doc__': None} (<class '__main__.FlyToSky'>,) <class '__main__.Trick'> <type 'type'> 下面我将依次理一下上面的内容,在此之前我必须先介绍两个魔法方法: __class__这个方法用于查看对象属于是哪个生成的,这样理解在python中的所有东西都是对象,类对象也是对象。如果按照以前的思维来想的话就是类是元类的实例,而实例对象是类的实例。 __bases__这个方法用于得到一个对象的父类是谁,特别注意一下__base__返回单个父类,__bases__以tuple形式返回所有父类。 好了知道了这两个方法我来依次说一下每行什么意思。 使用type创建一个类赋值给pw type的接受的三个参数的意思分辨是(类的名称, 类是否有父类(), 类的属性字典{}) 这里初始化一个类的实例,然后尝试去获得父类的laugh_at属性值,然后得到结果hahahaha 取一个pw的也就是我们常见类的类字典数据 拿到pw的父类,结果是我们指定的 FlyToSky pw的实例pw()属于哪个类初始化的,可以看到是class Trick 我们再看class trick是谁初始化的? 就是元类type了 (二) 什么是元类以及简单运用 这一切介绍完之后我们总算可以进入正题 到底什么是元类?通俗的就是说,元类就是创建类的类。。。这样听起来是不是超级抽象? 来看看这个 Trick = MetaClass() MyObject = Trick() 上面我们已经介绍了,搞一个Trick可以直接这样 Trick = type('Trick', (), {}) 可以这样其实就是因为,Type实际上是一个元类,用他可以去创建类。什么是元类刚才说了,元类就是创建类的类。也可以说他就是一个类的创建工厂。 类上面的__metaclass__属性,相信愿意了解元类细节的盆友,
超蛋lhy
2018/08/31
1.2K0
Python 元类
在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段。在Python中这一点仍然成立:
Devops海洋的渔夫
2019/05/31
1.7K0
ARTS第二周
假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−2^31, 2^31 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。
zx钟
2019/07/18
4190
Python type 和元类 metaclass
众所周知 Python 跟 Java 一样,一切皆对象,所以 class 类也是对象,而对象可以动态创建,所以一个 class 类也可以被动态创建出来。
菜皮日记
2023/12/18
1720
Python metaclass 的原理和应用
元编程(meta programming)是一项很神奇的能力,可以通过代码在运行时动态生成代码。
爬虫技术学习
2023/03/06
3780
Python metaclass 的原理和应用
type与元类
原文 1、什么是元类 通过上文的描述,我们知道了Python中的类也是对象。元类就是用来创建这些类(对象)的,元类就是类的类,你可以这样理解为: MyClass = MetaClass() #元类创建 MyObject = MyClass() #类创建实例 实际上MyClass就是通过type()来创创建出MyClass类,它是type()类的一个实例;同时MyClass本身也是类,也可以创建出自己的实例,这里就是MyObject 2、type type我们经常用来查看对象类型,如 print
用户1733462
2018/06/01
4800
python 中的元类详解
在其他语言中我们都知道类和int,string等类型一样是用来生成对象的。 类就是生成对象的代码段。 在python中任然是这样,但是Python中的类还远不止如此,在python中类也是对象。只是这个对象拥有创建对象的能力。
Tim在路上
2020/08/04
7750
Python metaclass 简介
当我们定义一个类的语句结束时,真正发生的情况,是 Python 调用 type 的 __call__ 运算符。
为为为什么
2022/08/06
4400
How does it work - with_metaclass
我在看源代码的时候,经常蹦出这一句:How does it work! 竟然有这种操作?本系列文章,试图剖析代码中发生的魔法。顺便作为自己的阅读笔记,以作提高。
岂不美哉Frost
2019/11/30
1.1K0
Python 中的元类到底是什么?这篇恐怕是最清楚的了
在理解元类之前,您需要掌握 Python 的类。Python 从 Smalltalk 语言中借用了一个非常特殊的类概念。
BigYoung小站
2020/07/01
7890
改变python对象规则的黑魔法metaclass
看到标题,你可能会想改变类的定义有什么用呢?什么时候才需要使用metaclass呢?
快学Python
2021/08/09
5000
相关推荐
深入理解Python中的元类(metaclass)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验