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