学习笔记:Python元类

1. 什么是Python的类

在Python中,类是用于定义具有相同属性和方法的对象的模板。
类定义了该集合中每个对象所共有的属性和方法。对象是类的实例,类定义以关键字class开头,说的很抽象来个例子:

class Person(object):
    def __init__(self):
        self.name = "张三"
        self.age = 18
        
obj = Foo()

这就是一个Python类的定义, __init__是类的初始化方法,当一个类被实例化时(obj = Foo())会调用类的__init__方法完成初始化,一个简单的类就完成了,那么还有没有其它方法来创建类呢,其实Python的类内部真正的创建是由type来创建的

2.Python中的type

说到type可能第一反应是用来判断对象类型是用的,type能创建类听着有点恍惚,是的,判断对象类型type的一个作用,type最大的作用却是动态创建类

2.1 如何使用type创建类

type('类名', (继承类,), {类方法或属性})
由上面不难看出type接收三个参数,第一个是类名,第二个是继承类(可以是多个)已tuple的形式传入,可以是空元祖,默认继承object,第三个参数是一个字典,用来定义类属性和类方法,下面来点代码

class Person(object):
    def __init__(self):
        self.name = "张三"
        self.age = 18


type_obj = type("Person", (object,), {"name": "张三", "age": 18})

print(type_obj)
print(Person())

输出:
<class '__main__.Person'>
<__main__.Person object at 0x109f487f0>

由此可见使用classtype在Python中都能定义一个类,那什么又是元类呢,继续往下

3.什么是元类

  • 类是创建对象的模板(类->对象)
  • 元类是创建类的模板 (元类->类)

其实我们上面说的type它就是一个元类,那这样type能够动态创建类就能说得通了,因为元类是创建类的模板

在Python中有着一切皆对象的说法,那么我们来看看一些代码片段

a = 13
b = "hello world"
c = [1, 2, 3, 4, 5]
d = {"name": "张三", "age": 18}
e = (1, 2)


def func():
    print("hello world")

print(type(a))
print(type(b))
print(type(c))
print(type(d))
print(type(e))
print(type(func))
print(type(type))
print(type(object))

输出:
<class 'int'>
<class 'str'>
<class 'list'>
<class 'dict'>
<class 'tuple'>
<class 'function'>
<class 'type'>
<class 'type'>

看上述代码不难看出,在Python中常见的数据类型,函数其实都是 包括类的鼻祖object也是由type创建的,甚至type都是由自己创建

str:用来创建字符串对象的类。
int:是用来创建整数对象的类。
type:是用来创建类对象的类。

一个实例的类型,是类
一个类的类型,是元类
一个元类的类型,是type

4.怎么实现一个元类

先了解一下类中的三个很重要的魔法方法 __new____init____call__

__init__: 类的初始化方法
__new__: 类的构造方法,创建类,当实例化一个类时会调用这个方法
__call__: 将类的实例对象变成可调用对象,简单理解,实例化一个类时,最先调用__call__方法,在内部会先调用__new__创建类,然后调用__init__初始化 知道了这个我们就来实现一个元类的实例

class TestMeta(type):
    pass


class Person(metaclass=TestMeta):
    def __init__(self, name="张三"):
        self.name = name
 
obj = Person()
print(type(obj))
print(type(obj.__class__))
print(type(obj.__class__.__class__))

输出:
<class '__main__.Person'>
<class '__main__.TestMeta'>
<class 'type'>

先定义了一个TestMeta的元类,再定义了一个Person类继承了TestMeta元类,注意元类继承需要使用metaclass 实例化Person类时,看obj的类型就能看出来关系了

5.使用元类来写一个单例模式

class Metaclass(type):
    _instance = None

    def __call__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super().__call__()
        return cls._instance


class Person(object, metaclass=Metaclass):

    def __init__(self):
        self.name = "张三"
        

obj = Person()
obj1 = Person()
print(obj)
print(obj1)

输出:
<__main__.Person object at 0x102125b40>
<__main__.Person object at 0x102125b40>

类是元类的实例,所以在创建一个普通类时,其实会走元类的 __new__

同时,我们又知道在类里实现了 __call__ 就可以让这个类的实例变成可调用。

所以在我们对普通类进行实例化时,实际是对一个元类的实例(也就是普通类)进行直接调用,所以会走进元类的 __call__

注意事项:当在实例化Person类时, Person类同时重写了__call__方法, obj = Person() 会调用元类的__call__方法,如果要使用Person类的__call__方法还需要obj()才能调用到重写的__call__方法

6.总结

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tuple-Wang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值