欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

day 28-1 元类

程序员文章站 2022-06-05 18:17:01
元类,元类的用途:自定义元类控制类的创建行为及类的实例化行为 ......

元类

元类的用途:自定义元类控制类的创建行为及类的实例化行为

python 中一切皆为对象。

一切接对象,对象可以怎么用呢?

1、都可以被引用,x=obj

2、都可以当作函数的参数传入

3、都可以当作函数的返回值

4、都可以当作容器类的元素,l=[func,time,obj,1]

让我们先定义一个类,然后逐步分析

class people():
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def say(self):
        print('%s say welcome to here' % self.name)


p = people('ysg', 21)
p.say()
print(type(p))              # <class '__main__.people'>
print(type(people))         # <class 'type'>

所有的对象都是实例化或者说调用类而得到的(调用类的过程称为类的实例化),比如对象t1是调用类oldboyteacher得到的

如果一切皆为对象,那么类 peope 本质也是一个对象,既然所有的对象都是调用类得到的,那么 peope 必然也是调用了一个类得到的,这个类称为元类

总结:产生类的类称之为元类,默认使用 class 定义的类,他们的元类是 type。

 

exec的用法

参数1:字符串形式的命令

参数2:全局作用域(字典形式),如果不指定默认就是用 globals()

参数3:局部作用局(字典形式),如果不指定默认就是用 locals()

例子

g = {
    'x': 'ysg',
    'y': '123'
}

l = {}

exec("""
global x,m
x = 'ysging'
m = 'pei'
z = '21'
""", g, l)
print(g)        # {'x': 'ysging', 'y': '123'..., 'm': 'pei'}
print(l)        # {'z': '21'}

 

元类定义的两种方式

方法一:class

class people():
    country = "china"

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def func(self):
        print('%s say good' % self.name)


p = people('ysg', '22')
print(people)                       # <class '__main__.people'>
print(p, p.name, p.age)             # <__main__.people object at 0x0000020b0fc652e8> ysg 22

方法二:type

定义类的三要素:类名、类的基类、类的名称空间

class_name = 'people'
class_bases = (object,)
class_body = """
country = "china"
def __init__(self, name, age):
    self.name = name
    self.age = age

def func(self):
    print('%s say good' % self.name)
"""
class_dic = {}
exec(class_body, globals(), class_dic)
people1 = type(class_name, class_bases, class_dic)
print(people1)                      # <class '__main__.people'>
p1 = people1('ysg', '22')
print(p1, p1.name, p1.age)          # <__main__.people object at 0x0000020b0fc65470> ysg 22

 

自定义元类控制类的创建行为

实现检索类名称是否为大写,类中是否写入注释

class mymeta(type):
    def __init__(self, class_name, class_bases, class_dic):
        super(mymeta, self).__init__(class_name, class_bases, class_dic)
        if not class_name.istitle():
            raise typeerror('类名称首字母要求大写')

        if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
            raise typeerror('新建的类必须标有注释')


class people(object, metaclass=mymeta):  # people = mymeta(class_name,class_bases,class_dic)
    '''
        使用自定义元类控制类的创建行为
    '''
    country = "china"

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def func(self):
        print('%s say good' % self.name)

 

自定义元类控制类的实例化行为

预备知识 __call__

class foo():
    pass


f = foo()
f()  # typeerror: 'foo' object is not callable
class foo():
    def __call__(self, *args, **kwargs):
        print(self)
        print(args)
        print(kwargs)


f = foo()
f(1, 2, 3, a=1, b=2, c=3)

结果:
<__main__.foo object at 0x000001dbe6b7f240>
(1, 2, 3)
{'a': 1, 'b': 2, 'c': 3}

由以上两个例子可以看出,在调用方式实际是自动调用了 __call__ 方法

所以可以得出,在使用元类控制类的实例化行为时:

  元类内部也应该有一个 __call__ 方法,会在调用 foo 时触发执行;foo(1,2,x=1) 就相当于 foo.__call__(foo,1,2,x=1)