美文网首页
python类和元类

python类和元类

作者: hsiaojun | 来源:发表于2021-03-08 09:20 被阅读0次

    前段时间在B站上看到python类和元类的视频讲解,整理了视频中的代码,相信看完后对类有进一步的了解。

    1.py

    cmd = """
    x = 1
    print("exec函数执行了")
    def func(self):
        pass
    """
    
    class_dict = {}
    exec(cmd, {}, class_dict)
    print(class_dict)
    
    """
    执行结果如下
    exec函数执行了
    {'x': 1, 'func': <function func at 0x000002DAC0401E18>}
    """
    

    2.py

    class People:
        country = "China"
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def eat(self):
            print("%s is eating" % self.name)
    
    
    print(type(People))  # <class 'type'>
    

    3创建类的三个要素.py

    # 创建类有三个要素:类名 基类 类的名称空间
    # People = type(类名,基类,类的名称空间)
    class_name = "People"  # 类名
    class_bases = (object,)  # 基类
    # 类的名称空间
    class_dic = {}
    class_body = """
    country = "China"
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def eat(self):
        print("%s is eating" % self.name)
    """
    
    exec(class_body,
         {},
         class_dic, )  # 执行exec后,class_dic里面就有类的变量和函数
    
    # 类的3要素
    print(class_name)  # 类名 People
    print(class_bases)  # 基类(<class 'object'>,)
    # {'country': 'China', '__init__': <function __init__ at 0x00000153DBC11E18>, 'eat': <function eat at 0x00000153DBF898C8>}
    print(class_dic)  # 类的名称空间,执行exec后,class_dic里面就有类的变量和函数
    
    # 这样创建类
    People_class = type(class_name, class_bases, class_dic)
    print(People_class)  # <class '__main__.People'>
    
    # 使用类
    o_p = People_class("jjj", 12)
    o_p.eat()  # jjj is eating
    
    

    4.自定义类.py

    # 定义一个元类
    class Mymeta(type):
        # 只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
        def __init__(self, class_name, class_bases, class_dic):
            print("self", self)  # 现在是People
            print("class_name", class_name)
            print("class_bases", class_bases)
            print("class_dic", class_dic)
            # 重用父类type的功能
            super(Mymeta, self).__init__(class_name, class_bases, class_dic)
    
    
    class People(object, metaclass=Mymeta):  # metaclass指定元类
        # People=Mymeta(类名,基类,类的名称空间
        country = "China"
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def eat(self):
            print("%s is eating" % self.name)
    
    
    # People的信息会被送到Meteta元类中去:类名 基类门 类的名称空间
    p = People("kk", 22)
    p.eat()
    """
    self <class '__main__.People'>
    class_name People
    class_bases (<class 'object'>,)
    class_dic {'__module__': '__main__', '__qualname__': 'People', 'country': 'China', '__init__': <function People.__init__ at 0x000001E8C9529950>, 'eat': <function People.eat at 0x000001E8C9529840>}
    kk is eating
    """
    

    5.控制类的产生过程.py

    # 我们可以控制类必选有文档
    class Mymeta(type):
        # 只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
        def __init__(self, class_name, class_bases, class_dic):
            if class_dic.get("__doc__") is None or len(
                    class_dic.get("__doc__").strip()) == 0:
                raise TypeError("类中必须要有文档注释,并且文档注释不能为空")
            if not class_name.istitle():
                raise TypeError("类名首字母必须大写")
            # 重用父类type的功能
            super(Mymeta, self).__init__(class_name, class_bases, class_dic)
    
    
    try:
        class People(object, metaclass=Mymeta):
            country = "China"
    
            def __init__(self, name, age):
                self.name = name
                self.age = age
    
            def eat(self):
                print("%s is eating" % self.name)
    except Exception as e:
        print(e)  # 类中必须要有文档注释,并且文档注释不能为空
    
    try:
        class people(object, metaclass=Mymeta):  # metaclass指定元类
            """
            # 有注释了,但类名是小写
            """
            country = "China"
    
            def __init__(self, name, age):
                self.name = name
                self.age = age
    
            def eat(self):
                print("%s is eating" % self.name)
    except Exception as e:
        print(e)  # 类名首字母必须大写
    

    6__call__方法.py

    class Foo:
        def __call__(self, *args, **kwargs):
            print(args)
            print(kwargs)
            print("__call__实现了,实例化对象可以加括号调用了")
    
    
    obj = Foo()
    obj("xiaojun", age=18)
    """
    ('xiaojun',)
    {'age': 18}
    __call__实现了,实例化对象可以加括号调用了
    """
    

    7__new__方法.py

    # __new__方法
    class People:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def __new__(cls, name, age):
            # 约束年龄
            if 0 < age < 150:
                # return object.__new__(cls)
                return super(People, cls).__new__(cls)
            else:
                return None
    
    
    b = People("x", 10)
    print(b)  # <__main__.People object at 0x000001732F7177B8>
    p = People("x", 150)
    print(p)  # None
    
    

    8利用new init控制类实例化产生.py

    # 利用new init控制类实例化产生
    class Mymeta(type):
    
        def __call__(self, *args, **kwargs):
            print(self)  # <class '__main__.People'> ,self是People
            print(args)  # ('name1',)
            print(kwargs)  # {'age': 12}
            # 1,先造出一个People的空对象,申请内存空间
            # __new__方法接受的参数虽然也是和__init__一样,但是__init__是在类实例创建之后调用,而__new__方式正是创建这个类实例之前调用
            obj = self.__new__(self)  # 虽然和下面同样是People,但是People没有,找到的__new__是父类的
            # 2,为该空对象初始化独有的属性
            self.__init__(obj, *args, **kwargs)
            # 3, 返回一个初始化好的对象
            obj.name2 = "haha"
            return obj
    
    
    """
    类的调用,即类实例化就是元类的调用过程,可以通过元类Mymeta的__call__方法控制
    1,先造出一个People的空对象
    2,为该空对象初始化独有的属性
    3,返回一个初始化好的对象
    """
    
    
    class People(object, metaclass=Mymeta):
        country = "China"
    
        def __init__(self, name1, age):
            self.name1 = name1
            self.age = age
    
        def eat(self):
            print("%s is eating" % self.name1)
    
    
    p = People("name1", age=12)
    p.eat()  # name1 is eating
    print(p.name2)  # haha
    
    

    9,使用元类修改属性为隐藏属性.py

    class Mymeta(type):
    
        def __init__(self, class_name, class_bases, class_dic):
            super(Mymeta, self).__init__(class_name, class_bases, class_dic)
    
        def __call__(self, *args, **kwargs):
            # 加上逻辑,控制Foo的调用过程,即Foo对象的产生过程
            obj = self.__new__(self)
            self.__init__(obj, *args, **kwargs)
    
            # 修改属性为隐藏属性
            obj.__dict__ = {
                '_%s__%s' % (self.__name__, k): v
                for k, v in obj.__dict__.items()
            }
            return obj
    
    
    class Foo(object, metaclass=Mymeta):
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
    
    obj = Foo("nick", 18, "male")
    print(obj.__dict__)
    # {'_Foo__name': 'nick', '_Foo__age': 18, '_Foo__sex': 'male'}
    
    

    相关文章

      网友评论

          本文标题:python类和元类

          本文链接:https://www.haomeiwen.com/subject/vmxpqltx.html