讲元类前先说说两个内置函数evel、exec
evel平时会用到,exec平时用不太到但是在元类中会用到
eval内置函数的使用场景
1、执行字符串会得到相应的执行结果
2、一般用于类型转化,得到dict、list、tuple等
dic_str = "{'a': 1, 'b': 2, 'c': 3}"
list_str = "[1, 2, 3, 4, 5]"
tuple_str = "(1, 2, 3, 4, 5)"
with open('1.txt', 'r', encoding='utf-8') as rf:
data_str = rf.read()
# print(data_str, type(data_str))
# import json
# res = json.loads(data_str)
# print(res, type(res)) 如果是严格的json,则拿json来转换
# "{'a': 1, 'b': 2, 'c': 3}" => {'a': 1, 'b': 2, 'c': 3}
# res = eval(data_str)
# print(res, type(res))
exec内置函数的使用场景
1、执行字符窜,没有执行结果(没有返回值)
2、将执行的字符串中产生的名字形成对应的局部名称空间
s = '''
my_a = 10
my_b = 20
def __init__(self):
pass
@classmethod
def print_msg(msg):
print(msg)
'''
# g_dic = {}
l_dic = {}
exec(s, {}, l_dic)
print(l_dic)
类的名称空间的控制
# Python中万物皆对象,所有用来创建对象的类,本身也是对象,类是type类的对象
# type类叫做元类,是所有元类的基类
# 元类:造类的类 - 类的类
# -- 控制类的产生
# -- 控制类的对象的产生
dic = {}
exec(s, {}, dic)
C = type('C', (object, ), dic)
print(C, type(C), C.__bases__)
print(C.__dict__)
c1 = C()
print(c1.my_a)
C.print_msg('12345')
自定义元组
class CountError(Exception):
pass
class MyMeta(type):
# 自定义元类,重写init方法的目的:
# 1.该方法是从type中继承来的,所以参数同type的init
# 2.最终的工作(如果开辟空间,如果操作内存)还是要借助type
# 3.在交给type最终完成工作之前,可以对类的创建加以限制 *****
def __init__(cls, class_name: str, bases, namespace):
# print(cls)
# print(class_name)
print(bases)
# print(namespace)
# 需求:由给元类控制的类的类名必须首字母大写
if not class_name.istitle():
raise NameError('名字首字母必须大写')
# 需求:定义类是必须明确父类
if len(bases) == 0:
raise CountError('父类必须明确')
# super(MyMeta, cls).__init__(class_name, bases, namespace)
super().__init__(class_name, bases, namespace)
# 自定义元类,重写call方法的目的:
# 1.被该元类控制的类生成对象,会调用元类的call方法
# 2.在call中的返回值就是创建的对象
# 3.在call中
# -- 通过object开辟空间产生对象
# -- 用被控制的类回调到自己的init方法完成名称空间的赋值
# -- 将修饰好的对象反馈给外界
def __call__(cls, *args, **kwargs):
print('call fn run')
obj = object.__new__(cls)
# 需求:所有通过该元类控制的类产生的对象都有meta_name该属性
obj.meta_name = cls.__name__
# obj.name = args[0]
# 调回当前被控制的类自身的init方法,完成名称空间的赋值
cls.__init__(obj, *args, **kwargs)
return obj
单例:一个类只能产生一个实例
# 为什么要有单例:
# 1.该类需要对象的产生
# 2.对象一旦产生,在任何位置再实例化对象,只能得到第一次实例化出来的对象
class Songs():
# def __init__(self, song_name):
# self.song_name = song_name
def run(self):
pass
def pause(self):
pass
song = Songs()
song.run()
# ....
song = Songs()
song.pause()