一、exec
exec(object,globals,locals)中有三个参数:
object:字符串形式的命令,即一段字符串形式的代码
globals:全局作用域,必须是字典形式的;如不指定,默认为globals
locals:局部作用域,必须是字典;如不指定,默认locals
g = {'x':1,'y':2}
l = {}
exec('''
global x,m
x = 100
m = 10
z = 50
''',g,l)
print(g)
print(l)
二、对象的特性
在python中一切皆对象,用对象将python中所有的变量、函数等统一起来,是有与它们都有共同的特性:
1、都可以被引用,x = obj
2、都可以当做返回值(python中返回值可是一任何类型)
3、都可以当函数的参数传入
4、都可以当做容器类的元素,如列表,字典等容器同样具备上面四种属性的都是对象。
三、元类定义
class Foo:
pass
f = Foo()
print(type(Foo))
print(type(f))
打印结果:
<class 'type'>
<class '__main__.Foo'>
由上面程序结果可以看出,f是由Foo这个类实例化得到,而Foo则是由type实例化得到的。因此type也是一个类,即Foo是以type这个类为模板,得到的类。此时type就是Foo的元类。类的类就是元类,元类时类的模板。
type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象。
四、创建对象的两种方式
1、使用class关键字
class Chinese(object):
country='China'
def __init__(self,name,age):
self.name=name
self.age=age
def talk(self):
print('%s is talking' %self.name)
2、手动模拟class创建类的过程
将创建类的步骤拆分开,手动去创建。即type模式
# 定义类的三要素
# 1、类名
class_name = 'Chinese'
# 2、父类
class_bases = (object,) # 不加逗号,会报错
# 3、名称空间
class_body = '''
country='China'
def __init__(self,name,age): # 类体代码,字符串形式
self.name=name
self.age=age
def talk(self):
print('%s is talking' %self.name)
'''
class_dict = {} # 分配类的名称空间
exec(class_body,globals(),class_dict) # 调用exec()创建类
# print(class_dict)
Chinese = type(class_name,class_bases,class_dict) # 创建元类为type的类
print(Chinese)
p = Chinese('夏天',18) # 实例化
print(p)
print(p,p.name,p.age)
p.talk()
type 接收三个参数:
第 1 个参数是字符串 Chinese,表示类名
第 2 个参数是元组 (object, ),表示所有的父类
第 3 个参数是字典,这里是一个空字典,表示没有定义属性和方法
补充:若Chinese类有继承,即class Chinese(Bar):… 则等同于type(‘Chinese’,(Bar,),{})
五、定制元类控制类的行为
class Mymeta(type): # 定义一个继承type类的元类
def __init__(self,class_name,class_bases,class_dict):
if not class_name.istitle():
raise TypeError('首字母必须大写') # raise抛异常关键字,有异常程序运行到此就结束了
# print(class_dict) # 查看类的名称空间
if not '__doc__' in class_dict or not class_dict['__doc__'].strip(): #控制创建类的行为
raise TypeError('必须有注释,且注释不能为空')
super(Mymeta,self).__init__(class_name,class_bases,class_dict) # 创建类的三要素
class Chinese(object,metaclass= Mymeta): # metaclass= Mymeta表示定义了Chinese的元类是Mymeta
'''
中国人的类
'''
country = 'Chia'
def __init__(self,name,age):
self.name = name
self.age = age
def talk(self):
print('%s is talking' %self.name)
六、定制元类控制类的实例化
1、__call__方法
# __call__方法介绍
class Foo:
def __call__(self, *args, **kwargs): # 定义一个__call__方法使产生对象也能被调用,如果没有__call__方法对象则不能被调用
print(self)
print(args)
print(kwargs)
obj = Foo()
# 元类type内部也有一个__call__方法
obj(1,2,3,a = 5,b = 6)
2、控制类的实例化
class Mymeta(type): # 定义一个继承type类的元类
def __init__(self,class_name,class_bases,class_dict):
if not class_name.istitle():
raise TypeError('首字母必须大写')
if not '__doc__' in class_dict or not class_dict['__doc__'].strip():
raise TypeError('必须有注释,且注释不能为空')
super(Mymeta,self).__init__(class_name,class_bases,class_dict)
def __call__(self, *args, **kwargs):
print('触发__call__')
# __call__方法触发后 ,进行的三部曲:
# 1、产生一个空对象china
obj = object.__new__(self) # self = Chinese
# 2、初始化空对象china,即触发__init__方法
self.__init__(obj,*args, **kwargs)
# 3、返回china对象
return obj
class Chinese(object,metaclass= Mymeta):
'''
中国人的类
'''
country = 'Chia'
def __init__(self,name,age):
self.name = name
self.age = age
def talk(self):
print('%s is talking' %self.name)
china = Chinese('夏天',18)
'''
Chinese('夏天',18)=Chinese. __call__(Chinese, '夏天',18) ,Chinese可以理解为是经过Mymeta这个元类实例化得到的 一个对象
当调用Chinese('夏天',18)时就触发了Mymeta内部的__call__方法,将Chinese传给了self,'夏天'和18传给了后面的参数。在实例化时
会经过三个步骤:1、创建一个空对象;2、将空对象初始化,即触发__init__方法;3、有返回值
'''
print(china.__dict__)
3、自定义元类控制实例化应用
(1)单例模式
将参数都一样的不同对象,将他们的内存空间整合成一个内存空间,即在每个对象生成时,申请的内存空间相同。
class MySQL:
_instance = None
def __init__(self):
self.host = '127.0.0.1'
self.port = 3306
@classmethod
def singleton(cls):
if not cls._instance:
obj = cls()
cls._instance = obj
return cls._instance
def conn(self):
pass
def execte(self):
pass
obj1 = MySQL.singleton()
obj2 = MySQL.singleton()
obj3 = MySQL.singleton()
print(id(obj1))
print(id(obj2))
print(id(obj3))
print(obj1 is obj2 is obj3)
(2)用元类方式实现单例模
class Mymeta(type): # 定义一个继承type类的元类
def __init__(self,class_name,class_bases,class_dict):
if not class_name.istitle():
raise TypeError('首字母必须大写')
if not '__doc__' in class_dict or not class_dict['__doc__'].strip():
raise TypeError('必须有注释,且注释不能为空')
super(Mymeta,self).__init__(class_name,class_bases,class_dict)
self._instance = None # 设置MySQL类的_instance属性
def __call__(self, *args, **kwargs):
if not self._instance: # 判断类里面有没有_instance属性,没有就实例化一个对象
obj = object.__new__(self)
self.__init__(obj)
self._instance = obj
return self._instance
class Mysql(object,metaclass=Mymeta):
'''
MySQL
'''
_instance = None
def __init__(self):
self.host = '127.0.0.1'
self.port = 3306
def conn(self):
pass
def execte(self):
pass
obj1 = Mysql()
obj2 = Mysql()
obj3 = Mysql()
print(obj1 is obj2 is obj3)