一、什么是元类
python中一切皆对象,我们可以定义一个类,那么这个类也是一个对象,对象是实例化类得到的,所以类肯定也是某个类实例化得到的,而这个类就是元类。通俗的说,元类就是负责产生类的类。
class Dog(object):
def __init__(self, name, age):
self.name = name
self.age = age
def say(self):
print('%s says wang!' % self.name)
obj = Dog('wangcai', 2) # 调用Dog类=》对象obj
# 调用元类=》Dog类
# print(type(obj))
print(type(Dog))
元类>>实例化>>Dog类>>实例化>>对象
得到一个结论:默认的元类是type,默认情况下我们用class关键字定义的类都是由type产生的。
二、class关键字底层的运作
- 先拿到一个类名
class_name = "Dog"
- 然后拿到类的父类
class_bases = (object,)
- 再运行类体代码,将产生的名字放到名称空间中
class_dic = {}
class_body = """
def __init__(self, name, age):
self.name = name
self.age = age
def say(self):
print('%s says wang' % self.name)
"""
exec(class_body,{},class_dic)
# print(class_dic)
- 调用元类(传入类的三大要素:类名、基类、类的名称空间)得到一个元类的对象,然后将元类的对象赋值给变量名Dog,Dog就是我们用class自定义的那个类.
Dog = type(class_name,class_bases,class_dic)
三、补充之exec的用法
exec:三个参数
参数一:包含一系列python代码的字符串
参数二:全局作用域(字典形式),如果不指定,默认为globals()
参数三:局部作用域(字典形式),如果不指定,默认为locals()
可以把exec命令的执行当成是一个函数的执行,会将执行期间产生的名字存放于局部名称空间中
g={
'x':1,
'y':2
}
l={}
exec('''
global x,z
x=100
z=200
m=300
''',g,l)
print(g) #{'x': 100, 'y': 2,'z':200,......}
print(l) #{'m': 300}
四、自定义元类
class Mymeta(type): # 只有继承了type类的类才是自定义的元类
pass
class Dog(object, metaclass=Mymeta):
def __init__(self, name, age):
self.name = name
self.age = age
def say(self):
print('%s says wang' % self.name)
1、先拿到一个类名:"Dog"
2、然后拿到类的父类:(object,)
3、再运行类体代码,将产生的名字放到名称空间中{...}
4、调用元类(传入类的三大要素:类名、基类、类的名称空间)得到一个元类的对象,然后将元类的对象赋值给变量名Dog,Dog就是我们用class自定义的那个类
Dog= Mymeta("Dog",(object,),{...})
五:自定义元类来控制Dog类的产生
import re
class Mymeta(type): # 只有继承了type类的类才是自定义的元类
def __init__(self, class_name, class_bases, class_dic):
# print(self) # 类<class '__main__.OldboyTeacher'>
# print(class_name)
# print(class_bases)
# print(class_dic)
if not re.match("[A-Z]", class_name):
raise BaseException("类名必须用驼峰体")
if len(class_bases) == 0:
raise BaseException("至少继承一个父类")
# print("文档注释:",class_dic.get('__doc__'))
doc=class_dic.get('__doc__')
if not (doc and len(doc.strip()) > 0):
raise BaseException("必须要有文件注释,并且注释内容不为空")
# Dog= Mymeta("Dog",(object,),{...})
class Dog(object,metaclass=Mymeta):
"""
adsaf
"""
def __init__(self, name, age):
self.name = name
self.age = age
def say(self):
print('%s says wang!' % self.name)
六:自定义元类来控制Dog类的调用
import re
class Mymeta(type): # 只有继承了type类的类才是自定义的元类
def __init__(self, class_name, class_bases, class_dic):
# print(self) # 类<class '__main__.OldboyTeacher'>
# print(class_name)
# print(class_bases)
# print(class_dic)
if not re.match("[A-Z]", class_name):
raise BaseException("类名必须用驼峰体")
if len(class_bases) == 0:
raise BaseException("至少继承一个父类")
# print("文档注释:",class_dic.get('__doc__'))
doc = class_dic.get('__doc__')
if not (doc and len(doc.strip()) > 0):
raise BaseException("必须要有文件注释,并且注释内容不为空")
# res = Dog('wangcai',2)
def __call__(self, *args, **kwargs):
# 1、先创建一个Dog的空对象
dog_obj = object.__new__(self)
# 2、调用Dog类内的__init__函数,然后将Dog的空对象连同括号内的参数的参数一同传给__init__
self.__init__(dog_obj, *args, **kwargs)
dog_obj.__dict__ = {"_%s__%s" %(self.__name__,k): v for k, v in dog_obj.__dict__.items()}
# 3、将初始化好的Dog对象赋值给变量名res
return dog_obj
# Dog= Mymeta("Dog",(object,),{...})
class Dog(object, metaclass=Mymeta):
"""
adsaf
"""
def __init__(self, name, age):
self.name = name # dog_obj.name='wangcai'
self.age = age # dog_obj.age=2
def say(self):
print('%s says wang!' % self.name)
res = Dog('wangcai', 2)
print(res.__dict__)
# print(res.name)
# print(res.age)
# print(res.say)
调用Dog类做的事情:
- 先创建一个dog的空对象
- 调用Dog类内的
__init__
方法,然后将Dog的空对象连同括号内的参数的参数一同传给__init__
- 将初始化好的dog对象赋值给变量名res
七:单例模式
实现方式1:classmethod
import settings
class MySQL:
__instance = None
def __init__(self, ip, port):
self.ip = ip
self.port = port
@classmethod
def singleton(cls):
if cls.__instance:
return cls.__instance
cls.__instance = cls(settings.IP, settings.PORT)
return cls.__instance
# obj1=MySQL("1.1.1.1",3306)
# obj2=MySQL("1.1.1.2",3306)
# print(obj1)
# print(obj2)
obj3 = MySQL.singleton()
print(obj3)
obj4 = MySQL.singleton()
print(obj4)
方式2:元类
import settings
class Mymeta(type):
__instance = None
def __init__(self,class_name,class_bases,class_dic):
self.__instance=object.__new__(self) # Mysql类的对象
self.__init__(self.__instance,settings.IP,settings.PORT)
def __call__(self, *args, **kwargs):
if args or kwargs:
obj = object.__new__(self)
self.__init__(obj, *args, **kwargs)
return obj
else:
return self.__instance
# MySQL=Mymeta(...)
class MySQL(metaclass=Mymeta):
def __init__(self, ip, port):
self.ip = ip
self.port = port
# obj1 = MySQL("1.1.1.1", 3306)
# obj2 = MySQL("1.1.1.2", 3306)
# print(obj1)
# print(obj2)
obj3 = MySQL()
obj4 = MySQL()
print(obj3 is obj4)
方式3:装饰器
import settings
def outter(func): # func = MySQl类的内存地址
_instance = func(settings.IP,settings.PORT)
def wrapper(*args,**kwargs):
if args or kwargs:
res=func(*args,**kwargs)
return res
else:
return _instance
return wrapper
@outter # MySQL=outter(MySQl类的内存地址) # MySQL=》wrapper
class MySQL:
def __init__(self, ip, port):
self.ip = ip
self.port = port
# obj1 = MySQL("1.1.1.1", 3306)
# obj2 = MySQL("1.1.1.2", 3306)
# print(obj1)
# print(obj2)
obj3 = MySQL()
obj4 = MySQL()
print(obj3 is obj4)
网友评论