元类

一:元类介绍

“元类就是深度的魔法,99%的用户应该根本不必为此操心”。

如果你想搞清楚究竟是否需要用到元类,那么你就不需要它

那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。”

—— Python界的领袖 Tim Peters

一切都源自一句话:在Python中,一切皆对象

元类:类他爹

定义类,可以控制对象的产生

元类,可以控制类的产生

# 元类==>People类==>obj类
class People(object):
    shcool = 'Chongqing University'

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

    def say(self):
        print(f'Hello{self.name}')

obj = People('wyj',18)
# 调用People类 ==> 对象obj
# 调用元类 ==> People类

# 查看类(类型)
print(type(obj)) # <class '__main__.People'>
print(type(People)) # <class 'type'>

结论:
默认的元类是type,默认情况下我们用class关键字定义的类都是有type产生的

二:class关键字底层都做了哪些事

1.先拿到一个类名

class_name = 'People'

2.然后拿到类的父类

class_bases = (object,)

3.在运行内体代码,将产生的名字放到名称空间中

class_dic={}
class_body='''
    shcool = 'Chongqing University'

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

    def say(self):
        print(f'Hello{self.name}')
'''
exec(class_body,{},class_dic)
# print(class_dic)

补充:exec的使用

dic = {}    # 空字典
s = '''
a = 1
b = 2
c = 3
'''

exec(s, {}, dic)
print(dic)

4.调用元类(传入类的3大要素:类名、基类、类的名称空间)得到1个元类的对象,然后将元类的变量赋值给People(这个People就是我们用class自定义的类)

People = type(class_name,calss_bases,calss_dic)

5.完整思路

# 先拿类名
class_name = 'People'
# 拿到类的父类
class_bases = (object,)
# 在拿到类的名称空间(运行内体代码得到)
class_dic = {}
class_body = '''
    shcool = 'Chongqing University'

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

    def say(self):
        print(f'Hello{self.name}')
'''

exec(class_body, {}, class_dic)
# 4.调用元类(传入类的3大要素:类名、基类、类的名称空间)得到1个元类的对象,然后将元类的变量赋值给People(这个People就是我们用class自定义的类)
People = type(class_name,calss_bases,calss_dic)

三:自定义元类

1.先拿到一个类名:People

2.拿到类的父类:(object,)

3.在拿到类的名称空间(运行类体代码得到的){…}

4.调用元类(传入类的3大要素:类名、基类、类的名称空间)得到一个元类的对象,然后将元类的变量

People = Mymeta(‘People’, (object,), {…})

1.自定义元类

只有继承了type的类才是自定义的元类
可以通过自定义元类来规范类的生产

import re


class Mymeta(type):  # 只有继承了type的类 才是自定义的元类
    def __init__(self, class_name, class_bases, class_dic):
        print(self)  # 类
        # print(class_name)
        # print(class_bases)
        # print(class_dic)

        # 规范类名
        if not re.match('[A-Z]', class_name):
            raise BaseException('类名必须用驼峰体')

        # 至少继承一个类
        if len(class_bases) == 0:
            raise BaseException('至少继承一个类')

        # 文档注释
        # print('文档注释:', class_dic.get('__doc__'))
        doc = class_dic.get('__doc__')
        if not (doc and len(doc.strip()) > 0):
            raise BaseException('必须要有文档注释,并且注释内容不能为空')


# People = Mymeta('People', (object,), {...})
class People(object, metaclass=Mymeta):
    '''
    这是我的文档注释
    '''
    school = 'Chongqing University'

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

    def say(self):
        print(f'Hello {self.name}!')

2.探究可否调用

①自定义的类实例化的对象和其他int、list都不可用

class Foo:
    pass


obj1 = Foo()

obj2 = int(10)

obj3 = list([1, 2, 3])


# obj1()
# TypeError: 'Foo' object is not callable

# obj2()
# TypeError: 'int' object is not callable

# obj3()
# TypeError: 'list' object is not callable

②自定义的类加上==__call__方法后,实例化的对象,是可以直接通过加()==被调用的

调用对象其实就是在调用类对象类中定义的绑定方法:__call__

class Foo:
    def __call__(self, *args, **kwargs):
        print('=========')
        print(self)
        print(args)
        print(kwargs)


obj1 = Foo()
obj1(1, 2, 3, a=1, b=2) # 调用对象 其实就是在调用对象类中 定义的绑定方法:__call__
# (1, 2, 3)
# {'a': 1, 'b': 2}

3.自定义元类控制类的调用

import re

class Mymate(type): # 只有继承了type的类才是自定义类
    def __init__(self,class_name, class_bases, class_dic):
        print(self)  # 类
        # print(class_name)
        # print(class_bases)
        # print(class_dic)

        # 规范类名
        if not re.match('[A-Z]', class_name):
            raise BaseException('类名必须用驼峰体')

        # 至少继承一个类
        if len(class_bases) == 0:
            raise BaseException('至少继承一个类')

        # 文档注释
        # print('文档注释:', class_dic.get('__doc__'))
        doc = class_dic.get('__doc__')
        if not (doc and len(doc.strip()) > 0):
            raise BaseException('必须要有文档注释,并且注释内容不能为空')

    def __call__(self, *args, **kwargs):
        # 1.先创建一个空对象
        # 2.调用类的__init__方法,将空对象连同括号内的参数 一同传给__init__
        # 3.将初始化好的对象 赋值给变量名obj
        return 123
    
# People = Mymeta('People', (object,), {...})
class People(object,metaclass=Mymate):
    '''
        这是文档注释
    '''
    shcool = 'Chongqing University'
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def say(self):
        print(f'Hello{self.name}')


people_obj = People()  # <class '__main__.People'>

print(people_obj)  # 123

4.自定义元类 控制类的调用 - 进阶

import re


class Mymate(type):  # 只有继承了type的类才是自定义类
    def __init__(self, class_name, class_bases, class_dic):
        print(self)  # 类
        # print(class_name)
        # print(class_bases)
        # print(class_dic)

        # 规范类名
        if not re.match('[A-Z]', class_name):
            raise BaseException('类名必须用驼峰体')

        # 至少继承一个类
        if len(class_bases) == 0:
            raise BaseException('至少继承一个类')

        # 文档注释
        # print('文档注释:', class_dic.get('__doc__'))
        doc = class_dic.get('__doc__')
        if not (doc and len(doc.strip()) > 0):
            raise BaseException('必须要有文档注释,并且注释内容不能为空')

    def __call__(self, *args, **kwargs):
        # 1.先创建一个人空对象
        people_obj = object.__new__(self)
        # 2.调用类的__init__方法,将空对象连同括号内的参数 一同传给__init__
        self.__init__(people_obj, *args, **kwargs)
        # 3.将初始化好的对象 赋值给变量名obj
        return people_obj


class People(object, metaclass=Mymate):
    '''
        这是文档注释
    '''
    shcool = 'Chongqing University'

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

    def say(self):
        print(f'Hello{self.name}')


people_obj = People('wyj', 18)  # <class '__main__.People'>

print(people_obj)
print(people_obj.name)  # wyj
print(people_obj.age)  # 18
print(people_obj.say)  # <bound method People.say of <__main__.People object at 0x0147A550>>

# 调用People类做的事情:
# 1、先创建一个人的空对象
# 2、调用人类内的__init__方法,然后将人的空对象连同括号内的参数的参数一同传给__init__
# 3、将初始化好的人对象赋值给变量名people_obj

5.自定义元类 将类的属性隐藏

import re


class Mymeta(type):  # 只有继承了type的类 才是自定义的元类
    def __init__(self, class_name, class_bases, class_dic):
        print(self)  # 类
        # print(class_name)
        # print(class_bases)
        # print(class_dic)

        # 规范类名
        if not re.match('[A-Z]', class_name):
            raise BaseException('类名必须用驼峰体')

        # 至少继承一个类
        if len(class_bases) == 0:
            raise BaseException('至少继承一个类')

        # 文档注释
        # print('文档注释:', class_dic.get('__doc__'))
        doc = class_dic.get('__doc__')
        if not (doc and len(doc.strip()) > 0):
            raise BaseException('必须要有文档注释,并且注释内容不能为空')

    # people_obj = People() 触发了下面的__call__
    def __call__(self, *args, **kwargs):
        # 1.先创建一个人的空对象
        people_obj = object.__new__(self)
        # 2.调用类的__init__方法,将空对象连同括号内的参数 一同传给__init__
        # People.__init__
        self.__init__(people_obj, *args, **kwargs)
        print(people_obj.__dict__)
        people_obj.__dict__ = {'_%s__%s' % (self.__name__, k): v for k, v in people_obj.__dict__.items()}
        # 3.将初始化好的人对象 赋值给变量名people_obj
        return people_obj


# People = Mymeta('People', (object,), {...})
class People(object, metaclass=Mymeta):
    '''
    这是我的文档注释
    '''
    school = 'Chongqing University'

    #      people_obj,'wyj',18
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def say(self):
        print(f'Hello {self.name}!')


people_obj = People('wyj', 18)
# <class '__main__.People'>
# {'name': 'wyj', 'age': 18}

print(people_obj.__dict__)
# {'_People__name': 'wyj', '_People__age': 18}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值