0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Python中元类的作用

科技绿洲 来源:Python实用宝典 作者:Python实用宝典 2023-11-02 11:18 次阅读

1.什么是类

在理解元类之前,我们必须先掌握Python中的类(class)。

和大多数语言一样,Python中的类知识用来描述如何“生成一个对象”:

图片

但是,在Python中,类不仅能用来描述如何生成一个对象, 类本身也是对象

在你使用关键词** class **的时候,Python就会执行它,并创建一个对象。

>> > class ObjectCreator(object):
...       pass
...

上述指令在内存中创建了一个“ObjectiveCreator”的对象。

这个对象(类)本身具有创建对象(实例)的能力,因此它也是一个类。你可以对它做以下操作:

1.将其分配给变量
2.复制它
3.为其添加属性
4.将其作为函数参数传递

例如:

图片

2.动态创建类

由于类是对象,因此你可以像创建任何对象(数组、字典等)一样,随时随地创建类。

你甚至可以在函数里创建类:

图片

但是,这样的类并不是很动态,因为你必须自己编写整个类。

使用class关键字时,Python会帮你自动创建此对象,但是,Python同样也提供了一种手动创建的方法,那就是type函数。

>> > print(type(1))
< type 'int' >
 >> > print(type("1"))
< type 'str' >
 >> > print(type(ObjectCreator))
< type 'type' >
 >> > print(type(ObjectCreator()))
< class '__main__.ObjectCreator' >

type函数最经典的用法是返回对象的类型。但是很少人知道,它还能接受参数并手动创建类。

type(name, bases, attrs)

其中

  • name : 类名
  • bases : 元组,父类名
  • attrs : 字典,类属性值

因此你可以这样手动创建类:

>> > MyShinyClass = type('MyShinyClass', (), {}) # returns a class object
 >> > print(MyShinyClass)
< class '__main__.MyShinyClass' >
 >> > print(MyShinyClass()) # create an instance with the class
< __main__.MyShinyClass object at 0x8997cec >

如果你想给它赋予属性,可以这样玩:

>> > class Foo(object):
...       bar = True

等同于

>> > Foo = type('Foo', (), {'bar':True})

用来继承也是可以的:

>> > FooChild = type('FooChild', (Foo,), {})
 >> > print(FooChild)
< class '__main__.FooChild' >
 >> > print(FooChild.bar) # bar is inherited from Foo
True

可见通过 type() 函数创建的类和直接写class是完全一样的。

因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用 type() 函数创建出class。

正常情况下,我们用class来定义类,但是,type()函数也允许我们动态创建类,也就是说,动态语言本身支持运行期动态创建类,这和静态语言有非常大的不同。

Python是通过什么做到这一切的?那就是元类。

3.什么是元类

元类就是用于创建类的“东西”。

你定义类是为了创建对象,Python中所有的类都是对象。元类是用于创建这些对象的。可以看这个例子:

MyClass = MetaClass()
my_object = MyClass()

这有点像套娃。这段代码转化为type就是这样的:

MyClass = type('MyClass', (), {})

因此,我们可以得到一个基本事实,type 本身就是一个 元类

其实,就是 type 在幕后创建了Python中所有的类。

通过检查__class__属性,你会看到Python中,一切对象都是基于 type 的:

>> > age = 35
 >> > age.__class__
< type 'int' >
 >> > name = 'bob'
 >> > name.__class__
< type 'str' >
 >> > def foo(): pass
 >> > foo.__class__
< type 'function' >
 >> > class Bar(object): pass
 >> > b = Bar()
 >> > b.__class__
< class '__main__.Bar' >

那么,有个有趣的问题,__class__的__class__是什么呢?

>> > age.__class__.__class__
< type 'type' >
 >> > name.__class__.__class__
< type 'type' >
 >> > foo.__class__.__class__
< type 'type' >
 >> > b.__class__.__class__
< type 'type' >

因此,元类只是创建类对象的东西,如果愿意,可以将其称为“类的工厂”。

type 是Python使用的内置元类。不过,你可以创建自己的元类。

3.1 __metaclass__属性

在Python 2中,可以在编写类时添加属性__metaclass__,使用某个元类来创建该类:

class Foo(object):
    __metaclass__ = something...
    [...]

不过要小心的是,你虽然先写了 class Foo(object),但Foo这个对象尚未被创建,Python将先寻找__metaclass__类,找到后用它来创建Foo类。

如果没有这个__metaclass__类,它将使用 type 来创建类。

因此,类创建的流程是这样的:

1.创建的类中有__metaclass__元类属性吗?

2.如果有,那就用__metaclass__给该类在内存中创建一个类对象。

3.如果Python找不到__metaclass__,它将在MODULE级别查找__metaclass__属性 。

4.如果还是没有,那就使用父类的元类来创建类对象。

现在的问题就是,你可以在__metaclass__中放置些什么代码呢?

答案就是:可以创建一个类的东西。那么什么可以用来创建一个类呢?type,或者任何继承或使用它的东西。

3.2 Python 3中的元类

设置元类的语法在Python3已改为:

class Foo(object, metaclass=something):
    ...

即不再使用__metaclass__属性,而是在基类参数列表中引入关键字参数。

不过元类的基本工作方式不变。在Python3中,你可以将属性作为关键字参数传递给元类:

class Foo(object, metaclass=something, kwarg1=value1, kwarg2=value2):
    ...

4.为什么需要元类

元类最主要的一个应用方向是创建API,一个最著名的应用是Django ORM,比如:

class Person(models.Model):
    name = models.CharField(max_length=30)
    age = models.IntegerField()

当你这样访问属性的时候:

person = Person(name='bob', age='35')
print(person.age)

它并不会返回models.IntegerField,而是返回了一个整形的数字。

这是因为models.Model引用了一个ModelBase类,该类随后进行了魔术般地操作,使其能够与数据库字段进行挂钩。

这就是元类的作用,Django通过它,完成了系列复杂的幕后工作,将原本非常复杂的事情变得非常简单。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • python
    +关注

    关注

    54

    文章

    4763

    浏览量

    84339
  • 数组
    +关注

    关注

    1

    文章

    412

    浏览量

    25873
  • 函数参数
    +关注

    关注

    0

    文章

    6

    浏览量

    5978
收藏 人收藏

    评论

    相关推荐

    如何使用Python? 优势有哪些?

      Python是一种面向对象的高级语言,因此类对于Python非常重要。是一个空间,在该空间中变量(属性/方法)分别存储。运算符' . '用于调用的属性和方法。
    发表于 07-30 18:08

    Python中的方法、实例方法和静态方法?

    Python中实例属性和实例方法Python中类属性和方法Python中调用方法
    发表于 11-05 06:25

    python的理解与使用

    python的理解与使用1. 通俗理解(英文名 class),是具有相同特性(属性)和行为(方法)的对象(实例)的抽象模板。从定义上来理解
    发表于 03-07 16:51

    python的多态和的property属性

    python的多态多态,是指在同一型下的不同形态。比如下面这段代码class People: def speak(self):passclass American(People): def
    发表于 03-09 16:38

    python开发之‘’讲解

    Python 在尽可能不增加新的语法和语义的情况下加入了机制。这种机制是 C++ 和 Modula-3 的混合。 Python中的没有在用户和定义之间建立一个绝对的屏障,而是依赖于
    发表于 03-15 14:12 1次下载

    揭开Python中self的神秘面纱

    许多python初学者,在接触到python面向对象的时候,就被中包含的方法中的self打败了,不知道self是何物?
    的头像 发表于 01-19 17:51 1747次阅读
    揭开<b class='flag-5'>Python</b><b class='flag-5'>类</b>中self的神秘面纱

    python变量的作用

    python变量的作用域 1. 作用Python作用域可以分为四种: L (Local) 局部作用
    的头像 发表于 03-03 16:50 1498次阅读

    python的理解与使用

    python的理解与使用 1. 通俗理解 (英文名 class),是具有相同特性(属性)和行为(方法)的对象(实例)的抽象模板。 从定义上来理解
    的头像 发表于 03-07 16:51 1499次阅读

    python的继承详解

    python的继承 的继承,跟人类繁衍的关系相似。 被继承的称为基(也叫做父),继承而
    的头像 发表于 03-08 16:40 3053次阅读

    10种聚介绍和Python代码

    分享一篇关于聚的文章,10种聚介绍和Python代码。
    的头像 发表于 07-30 10:25 2942次阅读

    简述python和实例属性赋值

    python主体没有任何内容,只有pass语句,称为空。 ## 1.2 obj.attr属性赋值 通过obj.attr=value进行和实例属性赋值。
    的头像 发表于 02-21 10:30 984次阅读

    Python的属性和方法是什么

    编程中我们用来创建对象。日常生活中的汽车设计图就是我们Python中的。日常生活中的小汽车就是Python中的对象。
    的头像 发表于 02-23 10:17 818次阅读

    什么是python与对象

    Python中的,type函数查看数据类型
    的头像 发表于 02-23 10:18 709次阅读

    Python中的和对象详解

    Python 是一种面向对象的编程语言,它支持和对象。是一种用户自定义的数据类型,用于定义对象的属性和方法。对象是的实例,它包含的属
    的头像 发表于 04-20 16:53 1033次阅读

    Python继承的基本规则

    继承规则 与其他基于的语言一样,可以通过继承组合多个定义。 定义可以扩展(或继承)多个其他。这些又可以扩展其他
    的头像 发表于 09-20 14:24 474次阅读