python类和元类

前段时间在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': }
"""

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))  # 

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)  # 基类(,)
# {'country': 'China', '__init__': , 'eat': }
print(class_dic)  # 类的名称空间,执行exec后,class_dic里面就有类的变量和函数

# 这样创建类
People_class = type(class_name, class_bases, class_dic)
print(People_class)  # 

# 使用类
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_name People
class_bases (,)
class_dic {'__module__': '__main__', '__qualname__': 'People', 'country': 'China', '__init__': , 'eat': }
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)  #  ,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类和元类)