8

比Python更牛的语言有吗?看我用元类(metaclass)花式创建Python类

 3 years ago
source link: https://blog.csdn.net/nokiaguy/article/details/109349334
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

比Python更牛的语言有吗?看我用元类(metaclass)花式创建Python类

为了让更多的人看到本文,请各位读者动动小手,点击右上角【...】,将本文分享到朋友圈,thanks! 

Python类的定义再简单不过了。不过你有想过动态定义一个Python类吗?What?动态定义,是动态解析Python代码吗?不,这仍然是静态定义。我是说,干预类的创建过程,在类的创建过程中,对类中的一切东西动态干预,这个听起来很酷,那么到底是怎么做到的呢?继续看文章吧!

1. Python中的类

在理解元类之前,首先需要掌握Python的类。Python从Smalltalk语言中借用了一个非常特殊的类概念。

在大多数语言中,类只是描述如何产生对象的代码段。在Python中也是如此:

输出:<__main__.ObjectCreator object at 0x1055b03c8>

但在Python中,类本身也是对象。

当你使用class关键字时,Python就会执行class代码块中的代码,并创建一个对象。

这段代码在内存中创建了一个名为ObjectCreator的对象。这个对象(类)本身具有创建对象(实例)的能力,这就是为什么它是一个类。

但不管怎样,ObjectCreator仍然是一个对象,因此我们可以做如下事情:

(1)将ObjectCreator赋给一个变量;

(2)复制ObjectCreator;

(3)为ObjectCreator添加属性

(4)将ObjectCreator作为值参传入函数;

下面演示了ObjectCreator作为对象和类的使用过程:

执行这段代码,会输出如下结果:

2. 动态创建Python类

由于类是对象,因此可以像创建任何对象一样动态创建类。

首先,可以使用class在函数中创建一个类:

输出结果如下:

尽管这段代码可以根据choose_class函数的参数值返回不同的Python类,但这并不是动态的,因为仍然必须自己编写整个类。

由于类是对象,因此它们必须由某种东西生成。当使用class关键字时,Python会自动创建此对象。但与Python中大多数场景一样,为我们提供了一种手动进行操作的方法。

使用class关键字时,Python会自动创建此对象。但是,与Python中的大多数事情一样,它为您提供了一种手动进行操作的方法。

还记得type函数吗?该函数可以让你知道对象的类型。

type函数的功能很多,giant函数可以动态创建类。type函数可以将类的描述作为参数,并返回一个类。

好吧,类型具有完全不同的能力,它也可以动态创建类。type可以将类的描述作为参数,并返回一个类。

type函数的原型如下:

type(name, bases, attrs)

参数的含义如下:

  • name: 类名;

  • bases: 父类的元组(用于继承,可以为空);

  • attrs: 包含属性名称和值的字典;

例如,下面是一个Python类:

如果用动态的方法创建该类,可以使用下面的代码:

你会注意到,我们使用“ MyShinyClass”作为类的名称和变量来保存类引用。它们可以不同,但是没有理由使事情复杂化。

type函数可以使用字典来定义类的属性:

可以使用下面的代码动态创建Foo类,并动态为该类添加名为bar的属性。

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

我们可以使用下面的代码正常使用Foo类:

当然,Foo类同样可以被继承,代码如下:

使用下面的代码可以动态创建继承至Foo类的FooChild类。

最后,你需要向类中添加方法。只需定义具有适当签名的函数并将其分配为属性即可。

在动态创建类之后,可以向该类中添加更多方法,就像将方法添加到正常创建的类对象中一样。

看到这里,你应该了解了Python类的本质。类就是对象,可以像动态创建对象一样创建Python类。Python在使用class关键字时通过使用元类来完成创建类的过程。

3. 什么是元类(metaclass)

元类是创建类的“原料”。我们定义类是为了创建对象,而我们知道,Python类是对象,所以定义元类,就是为了创建类,也就是说,元类是类的类,可以通过下面的伪代码来描绘元类和类:

第1行代码其实相当于使用type函数动态创建MyClass类(或其他的类)

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

之所以可以这么用,是因为type函数是Python用于在幕后创建所有类的元类。所以type是一个类,而不是一个普通的函数。

现在还有一个疑问,Python类的命名规则都是首字母大写,那么为什么type类是首字母小写呢?

我想这与str类创建字符串对象和int类创建整数对象一致性有关。type只是创建类对象的类。

在Python中一切都是对象,其中包括整数,字符串,函数和类。它们都是对象。通过检查__class__属性可以看到这一点。

那么__class__的__class__是什么呢?

我们可以看到,__class__的__class__都是同一个东西,那就是type,所以Python中的所有类都是用type创建的。如果愿意,可以将type称为“类工厂”

type只是Python中的内建元类,当然,我们可以创建自己的元类。

4. 自定义元类(metaclass)

我们还可以自定义元类,一个元类可以是一个函数,函数的参数与type函数相同。现在给出一个使用元类的例子。假设已经有一个Foo类,该类中有若干个属性,都是小写,如bar等。现在要求将Foo类中所有的属性名都改成大写。要实现这个需求,当然可以一个一个地修改Foo类中属性的名,不过这简直太愚蠢了。万一以后领导又说,还是都是小写好,那岂不是又要改回来了。所以要实现这个需求,最好的方式就是使用元类。在Python2中,需要设置__metaclass__变量,不过在Python3中,使用元类的方式有所改变,需要在MyClass(metaclass=...)中使用metaclass指定元类函数,代码如下:

我们可以看到,通过metaclass指定upper_attr函数后,在创建Foo类时将不再调用type函数,而是调用upper_attr函数,为该函数传入的参数值与type函数相同。

推荐阅读  点击标题可跳转

1、连Python产生器(Generator)的原理都解释不了,还敢说Python用了5年?

2、牛掰了!鸿蒙与Android完美融合,将鸿蒙设备当Android设备用

3、【鸿蒙学院】鸿蒙App开发直播学员提问与回答

4、【鸿蒙学院】鸿蒙IDE:下载、安装DevEco Studio

5、 Python高效编程之88条军规(2):你真的会格式化字符串吗?

6、像极客一样提取Android的Root权限

关注「极客起源」公众号,加星标,不错过精彩技术干货


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK