元类
元类的介绍
产生类的类称之为元类,默认所以用class定义的类,他们的元类是type
exec的使用:
exec:三个参数
参数一:字符串形式的命令
参数二:全局作用域(字典形式),如果不指定,默认为globals()
参数三:局部作用域(字典形式),如果不指定,默认为locals()
例子:
#可以把exec命令的执行当成是一个函数的执行,会将执行期间产生的名字存放于局部名称空间中
g = {
'x':1,
'y':2
}
l = {}
exec('''
global x,z
x = 200
m = 400
''',g,l
)
print(g,l)
'''
输出结果:
{'x': 200, 'y': 2, '....}
{'m': 400}
'''
python中一切皆对象,类也是对象
满足四个条件的就是对象:
1、都可以被引用,x=obj
2、都可以当作函数的参数传入
3、都可以当作函数的返回值
4、都可以当作容器类的元素,l=[func,time,obj,1]
查看类的方法:
class Foo:
pass
f1 = Foo()
print(type(f1))
print(type(Foo))
'''
输出结果:
<class '__main__.Foo'> # 可以看出对象由Foo类创建
<class 'type'># type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象
'''
元类的创建方法:
一、使用关键字class来进行创建
class Zhugeliang:
camp = 'red'
def __init__(self,nickname,life_value,aggresivity):
self.nickname = nickname
self.life_value = life_value
self.aggresivity = aggresivity
二、就是手动模拟class创建类的过程):将创建类的步骤拆分开,手动去创建
#手动创建类
'''
#定义类的三要素:
类名
类的基类
类的名称空间
'''
#类名
class_name = 'China'
#类的基类
class_base = (object,)
#类的名称空间
class_boy = '''
country='China'
def __init__(self,namem,age):
self.name=namem
self.age=age
def talk(self):
print('%s is talking' %self.name)
'''
'''步骤一(先处理类体->名称空间):类体定义的名字都会存放于类的名称空间中(一个局部的名称空间),我们可以事先定义一个空字典,然后用exec去执行类体的代码(exec产生名称空间的过程与真正的class过程类似,只是后者会将__开头的属性变形),生成类的局部名称空间,即填充字典
'''
class_dic = {}
exec(class_boy,globals(),class_dic)
#print(class_dic)
#步骤二:调用元类type(也可以自定义)来产生类Chinense
Chinese = type(class_name,class_base,class_dic)
#print(Chinese)
Chinese1 = Chinese('egon',18)
#实例化type得到对象Chinese,即我们用class定义的类Chinese
print(Chinese1.__dict__)
'''
输出结果:
{'name': 'egon', 'age': 18}
'''
type 接收三个参数:
- 第 1 个参数是字符串 ‘Foo’,表示类名
- 第 2 个参数是元组 (object, ),表示所有的父类
- 第 3 个参数是字典,这里是一个空字典,表示没有定义属性和方法
补充:若Foo类有继承,即class Foo(Bar):.... 则等同于type('Foo',(Bar,),{})
自定义元类控制类的行为
import re
#自定义元类来控制首字母必须大写与必须加上注释
class Mymeta(type):
'''
定义自己的元类
'''
def __init__(self,class_name,class_base,class_dic):
num = re.search("^[A-Z]\w+",class_name)
if not num:
raise TypeError('首字母必须大写')
if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
raise TypeError('必须加上注释')
super(Mymeta,self).__init__(class_name,class_base,class_dic)
class Chinese(object,metaclass=Mymeta):
'''
自己的元类
'''
country='China'
def __init__(self,namem,age):
self.name=namem
self.age=age
def talk(self):
print('%s is talking' %self.name)
f = Chinese('egno',18)
自定义元类来控制类的实例化
#单例模式
#方法一:
# class Msql:
# __instance = None
# def __init__(self):
# self.host = '127.0.0.1'
# self.port = 3038
#
# @classmethod
# def singleton(cls):
# if not cls.__instance:
# obj = cls()
# cls.__instance = obj
# return cls.__instance
#
# def connt(self):
# pass
#
# m1 = Msql.singleton()
# m2 = Msql.singleton()
# m3 = Msql.singleton()
# print(m1 is m2 is m3)
#方法二:
import re
class Mymeta(type):
'''
定义自己的元类
'''
def __init__(self,class_name,class_base,class_dic):
num = re.search("^[A-Z]\w+",class_name)
if not num:
raise TypeError('首字母必须大写')
if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
raise TypeError('必须加上注释')
super(Mymeta,self).__init__(class_name,class_base,class_dic)
self.__intstance = None
def __call__(self, *args, **kwargs): #实例化的时候就会触发这个方法
if not self.__intstance:
# obj = object.__new__(self) # 产生对象
# self.__init__(obj) # 初始化对象
# self.__intstance = obj
self.__intstance = super.__call__(*args,**kwargs)#合并成一步
return self.__intstance
class Msql(object,metaclass=Mymeta):
'''
控制实例化
'''
def __init__(self):
self.host = '127.0.0.1'
self.port = 3038
def connt(self):
pass
m1 = Msql()
m2 = Msql()
print(id(m1))
print(id(m2))
print(m1 is m2)
六 练习题
练习一:在元类中控制把自定义类的数据属性都变成大写
class Mymeta(type):
'''
定义自己的元类
'''
def __new__(cls,name,base,attrs):
update_dic = {}
for i,v in attrs.items():
if not callable(v) and not i.startswith('__'):
update_dic[i.upper()] = v
else:
update_dic[i] = v
return type.__new__(cls,name,base,update_dic)
class China(object,metaclass=Mymeta):
country = 'China'
tag = 'Legend of the Dragon'
def walk(self):
print('%s is walk'%self.name)
print(China.__dict__)
练习二:在元类中控制自定义的类无需init方法
1.元类帮其完成创建对象,以及初始化操作;
2.要求实例化时传参必须为关键字形式,否则抛出异常TypeError: must use keyword argument
3.key作为用户自定义类产生对象的属性,且所有属性变成大写
class Mymeta(type):
'''
定义自己的元类
'''
def __new__(cls,name,base,attrs):
update_dic = {}
for i,v in attrs.items():
if not callable(v) and not i.startswith('__'):
update_dic[i.upper()] = v
else:
update_dic[i] = v
return type.__new__(cls,name,base,update_dic)
def __call__(self, *args, **kwargs):
if args: #如果传入的值是元组就会报错
raise TypeError('must use keyword argument')
obj = self.__new__(self) #产生对象
for i,v in kwargs.items(): #循环传入的kwargs值
obj.__dict__[i.upper()] = v
return obj
class China(object,metaclass=Mymeta):
country = 'China'
tag = 'Legend of the Dragon'
def walk(self):
print('%s is walk'%self.name)
f = China(country='中国',name='egon',age=18)
print(f.__dict__)
<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">