python之元类

1、元类

python中一切皆为对象

1.1、元类的定义
python中一切皆为对象,那么我们自定义类本质也是一个对象,既然所有的对象都是调用类得到的,那么我们自定义的类必然也是调用了一个类得到的,这个类称为元类

元类 => 我们自定义的类 => 实例化得到对象

结论: 默认的元类是type,默认情况下我们用class关键字定义的类都是由type产生的
1.2、class关键字在底层的运行
(1) 先拿到一个类名
class_name = 'Teacher'

(2) 然后拿到类的父类
class_bases = (object,)

(3) 再运行类体代码,将产生的名字放到名称空间中
class_dic = {}
class_body = """
school_name = '北京大学'

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

def show_info(self):
    print('<{}:{}>'.format(self.name, self.age))
"""
exec(class_body,{},class_dic)

(4) 调用元类(传入类的三大要素: 类名、基类、类的名称空间)得到一个元类的对象,然后将元类的对象赋值给变量名Teacher,Teacher就是我们用class自定义的那个类
1.3、自定义元类
class Mymeta(type):  # 只有继承了type类的类才是自定义的元类
    pass

class Teacher(object, metaclass=Mymeta):
    school_name = '北京大学'

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

    def show_info(self):
        print('<{}:{}>'.format(self.name, self.age))

        
1、先拿到一个类名: "Teacher"
2、然后拿到类的父类:(object,)
3、再运行类体代码,将产生的名字放到名称空间中{...}
4、调用元类(传入类的三大要素:类名、基类、类的名称空间)得到一个元类的对象,然后将元类的对象赋值给变量名Teacher,Teacher就是我们用class自定义的那个类
1.4、自定义元类来控制Teacher类的产生
class Mymeta(type):  # 只有继承了type类的类才是自定义的元类
    def __init__(self, class_name, class_bases, class_dic):

        # 可以增加逻辑对传递的参数进行逻辑判断
        if class_name.islower():
            raise BaseException('类名必须采用驼峰法')

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

        doc = class_dic.get('__doc__')
        if not (doc and len(doc.strip()) > 0):
            raise BaseException('文档注释不能为空')


class Teacher(object, metaclass=Mymeta):
    """
    文档注释
    """
    school_name = '北京大学'

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

    def show_info(self):
        print('<{}:{}>'.format(self.name, self.age))
1.5、自定义元类来控制Teacher类的调用
# __call__的使用
class Foo:
    def __call__(self, *args, **kwargs):
        print(self)
        print(args)
        print(kwargs)

obj = Foo()
obj(1, 2, a='111', b='222')  # 调用对象其实就是在调用对象类中定义的绑定方法__call__


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

        # 可以增加逻辑对传递的参数进行逻辑判断
        if class_name.islower():
            raise BaseException('类名必须采用驼峰法')

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

        doc = class_dic.get('__doc__')
        if not (doc and len(doc.strip()) > 0):
            raise BaseException('文档注释不能为空')

    # res = Teacher('allen',18)
    def __call__(self, *args, **kwargs):
        # 1、先创建一个老师的空对象
        teacher_obj = object.__new__(self)
        # 2、调用老师类内的__init__函数,然后将老师的空对象连同括号内的参数的参数一同传给__init__
        self.__init__(teacher_obj, *args, **kwargs)
        # 3、将初始化好的老师对象赋值给变量名res
        return teacher_obj

class Teacher(object, metaclass=Mymeta):
    """
    文档注释
    """
    school_name = '北京大学'

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

    def show_info(self):
        print('<{}:{}>'.format(self.name, self.age))

res = Teacher('allen', 18)
print(res.__dict__)  # {'name': 'allen', 'age': 18}
1.6、自定义元类控制init方法中创建私有属性
class Mymeta(type):  # 只有继承了type类的类才是自定义的元类
    def __init__(self, class_name, class_bases, class_dic):

        # 可以增加逻辑对传递的参数进行逻辑判断
        if class_name.islower():
            raise BaseException('类名必须采用驼峰法')

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

        doc = class_dic.get('__doc__')
        if not (doc and len(doc.strip()) > 0):
            raise BaseException('文档注释不能为空')

    # res = Teacher('allen',18)
    def __call__(self, *args, **kwargs):
        # 1、先创建一个老师的空对象
        teacher_obj = object.__new__(self)
        # 2、调用老师类内的__init__函数,然后将老师的空对象连同括号内的参数的参数一同传给__init__
        self.__init__(teacher_obj, *args, **kwargs)
        # 拿到初始化好的对象按照隐藏属性的方法修改字典
        teacher_obj.__dict__ = {'_{}__{}'.format(self.__name__, k): v for k, v in teacher_obj.__dict__.items()}
        # 3、将初始化好的老师对象赋值给变量名res
        return teacher_obj

class Teacher(object, metaclass=Mymeta):
    """
    文档注释
    """
    school_name = '北京大学'

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

    def show_info(self):
        print('<{}:{}>'.format(self.name, self.age))

res = Teacher('allen', 18)
print(res.__dict__)  # {'_Teacher__name': 'allen', '_Teacher__age': 18}
1.7、属性查找
class Mymeta(type):
    n = 444

class Bar(object):
    n = 333

class Foo(Bar):
    n = 222

class Teacher(Foo, metaclass=Mymeta):
    n = 111

    school = '北京大学'

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

# 站在对象的角度(对象 => 所在类 => 父类 => object)
obj = Teacher('allen', 18)
print(obj.n)

# 站在类的角度(类本身 => 父类 => 元类)
print(Teacher.n)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值