社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

Python 中最黑魔法、最难懂的概念

Python开发 • 4 年前 • 367 次点击  
👇👇关注后回复 “进群” ,拉你进程序员交流群👇👇

作者丨student老胡

来源丨机器学习算法与Python实战

大家好,我是老胡

最近在看一个开源框架的源码,其中大量使用了 metaclass 方法这个概念非常抽象,本文我就以一个有趣实用更简洁和通畅的方式来理解它。

元类 ( metaclass )应该是 Python 中最黑魔法、最难懂的概念之一,它提供了创造新类型的能力,为程序设计带来更多可能性。不少功能强大的开发框架,内部实现离不开 metaclass 的魔法。

Class

面向对象编程最重要的概念就是类(Class)和实例(Instance),我们先来创建一个 Lxs 的类,它有两个基本功 sing 和 dance ,lxs 是这个类的实例:

class Lxs(object): 
    def __init__(self, name, duration):
        self.name = name
        self.duration = duration
        print('%s practiced %s years' % (self.name, self.duration))
    def sing(self):
        print('%s good at singing' % self.name)

    def dance(self):
        print('%s good at dancing' % self.name)

lxs = Lxs('laohu',1.5)
lxs.sing()
lxs.dance()

练习时常1年半的老胡擅长唱和跳
恩,针不戳!

laohu practiced 1.5 years
laohu good at singing
laohu good at dancing

再来用__class__属性或type()看看 Lxs 和 lxs 分别是谁创建的

print(lxs.__class__)
print(Lxs.__class__)

lxs 是 Lxs 的实例,它创建自 Lxs ,这很容易理解。

我们 Lxs 类是 type 创建的?

'__main__.Lxs'>
'type'>

一切对象都来自 type

先说结论:type 可以动态创建 类(class) ,对象是类(class)的实例,类(class)也是对象,是 type 的实例。type 为对象的顶点,所有对象都创建自 type 。

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

class = type(classname, superclasses, attributedict)
'''
classname:类名
superclasses:类的继承关系,用元组表示
attributedict:表示各种属性、方法,用字典表示
'
''

继续上例,先定义__init__,sing 和 dance ,然后用 type 可以创建和上面完全一样的类:

Lxs = type('Lxs', (object,), dict( __init__= __init__,sing=sing,dance=dance))
lxs = Lxs('laohu',1)
lxs.sing()
print(lxs.__class__)
print(Lxs.__class__)

这里不得不提一下__call__这个属性
此方法会在实例作为一个函数被“调用”时被调用
这里等号右边的type(classname, superclasses, attributedict),就是 type 的__call__运算符重载,它会进一步调用:

type.__new__(typeclass, classname, superclasses, attributedict)
type.__init__(class, classname, superclasses, attributedict)
# 这一部分我们以后有空再细品

总结一下:type 实际上是 Python 创建所有 class 的 metaclass。

metaclass

除了使用type()动态创建类以外,要控制类的创建行为,还可以使用metaclass。

先定义metaclass,就可以创建类,最后创建实例。

一句话:metaclass 是 type 的子类,是类的模板

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

举个例子:像老胡就只会 sing 和 dance,有人还会rap,有人会说相声,我们定义很多的 class ,有一天,一个男人横空出世,他会打篮球!然后,所有的练习生也都学会了篮球,这可怎么修改?

metaclass 就可以施展魔法了

class LxsMetaclass(type):
    def __new__(cls, cls_name, bases, attrs):
        def basketball(self):
            print('%s good at basketball' % self.name)
        attrs['basketball'] = basketball
        return super(LxsMetaclass, cls).__new__(cls, cls_name, bases, attrs)

它指示Python解释器在创建 LxsMetaclass 时,要通过LxsMetaclass.new()来创建,在此,我们可以修改类的定义,比如,加上新的方法basketball(),然后,返回修改后的定义。

我们用 LxsMetaclass 这个模板创建类:

class Cxk(object, metaclass=LxsMetaclass):
    def __init__(self, name, duration):
        self.name = name
        self.duration = duration
        print('%s practiced %s years' % (self.name, self.duration))
    
    def sing(self):
        print('%s good at singing' % self.name)
    
    def dance(self):
        print( '%s good at  dancing' % self.name)
    
    def rap(self):
        print('%s good at  rap' % self.name)

    
cxk = Cxk('cxk',2.5)
cxk.basketball()

运行结果如下,秀?

cxk practiced 2.5 years
cxk good at basketball


不过metaclass的作用肯定不限于此,举个例子,也算是个思考题,大家品一品。

比如 laohu 化身 xck 的粉丝,打着学篮球的幌子学 sing、dance和rap  :

class Funs(Cxk):
    def basketball(self):
        print('%s good at  singing&dancing&rap' % self.name)


fans = Funs('laohu',0.5)
fans.basketball()

运行结果会是什么呢?

laohu practiced 0.5 years
laohu good at basketball

laohu 真的就只学会了篮球。。。

-End-

最近有一些小伙伴,让我帮忙找一些 面试题 资料,于是我翻遍了收藏的 5T 资料后,汇总整理出来,可以说是程序员面试必备!所有资料都整理到网盘了,欢迎下载!

点击👆卡片,关注后回复【面试题】即可获取

在看点这里好文分享给更多人↓↓

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/111803
 
367 次点击