exec可以在引号里声明一个名字,这个名字产生到局部作用域
g = {
'x':1,
'y':2
}
l = {}
# 我们可以把exec当成一个函数来执行
exec("""
global x, m
x = 10
m = 100
z = 3
""", g, l)
print(g['x'], g['y'], g['m'])
print(l['z'])
执行结果:
10 2 100
3
# 实际上python中的类也是对象,Foo = type() 的实例化对象
class Foo:
pass
obj = Foo()
print(type(obj))
print(type(Foo))
# 用来产生类的类称之为元类,默认所有用class定义的类,他们的元类是type
介绍了以上概念,我们来说明什么是元类 上例中的type()就是元类。 元类:用来定义类的类
所以定义类有2中方式:
+ 方式1:class关键字定义
+ 方式2:type关键字定义
方式1:
class Chinese: # Chinese = type(...)
country = 'China'
def __init__(self, name, age):
self.name = name
self.age = age
def talk(self):
print('%s is talking' % self.name)
方式2:我们用元类定义一个类,再实例化 类的3要素:类名,类的父类们,类的命名空间
# 定义类的3要素:类名,类的父类们,类的命名空间
class_name = 'Chinese' # 类名
class_bases = (object,) # 继承
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_dic = {}
exec(class_body, globals(), class_dic) # 用exec来执行
# print(class_dic) # obj.__dict__就是返回local命名空间的属性
Chinese1 = type(class_name, class_bases, class_dic) # 由元类实例化了一个类(注意,不是对象),效果相当于方式1的代码内容
obj1 = Chinese1('aaa', 11) # 实例化对象
print(obj1.name, obj1.age) # 输出结果:aaa 11
自定义元类来控制类的行为。
自定义元类一般只修改一部分,所以一般情况下继承type
class Mymeta(type):
def __init__(self, class_name, class_bases, class_dic): # 上一节中type实例化类的时候需要指定类的三要素,所以我们这里也需要初始化3个参数
print(class_name) # 可以自定义类的行为
print(class_bases) # 可以自定义类的行为
print(class_dic) # 可以自定义类的行为
if not class_name.istitle(): # 自定义行为,强制首字母大写
raise TypeError('类名的首字母必须是大写') # 异常处理
print(class_dic)
if '__doc__' not in class_dic or class_dic['__doc__'].isspace(): # 自定义注释规则
raise TypeError('类必须有注释')
super(Mymeta, self).__init__(class_name, class_bases, class_dic)
# 首字母大写,有注释,这个类可以创建
class Chinese(object, metaclass=Mymeta): # 默认值:Chinese(object, metaclass=type)
'''
comment
'''
country = 'China'
def __init__(self, name, age):
self.name = name
self.age = age
def talk(self):
print('%s is talking' % self.name)
# class ch(metaclass=Mymeta): # 首字母不是大写会报错
# pass
# class Ch(metaclass=Mymeta): # 没有注释会报错
# pass
只是储备 ‘__call__‘ 方法,正常情况下对象不能直接被调用,定义这个方法就能调用了。 这个方法会在调用对象(类也是元类的对象)的时候触发
class Mymeta(type): # 元类
def __init__(self, class_name, class_bases, class_dic): # 上一节中type实例化类的时候需要指定类的三要素,所以我们这里也需要初始化3个参数
if not class_name.istitle(): # 自定义行为,强制首字母大写
raise TypeError('类名的首字母必须是大写') # 异常处理
if '__doc__' not in class_dic or class_dic['__doc__'].isspace(): # 自定义注释规则
raise TypeError('类必须有注释')
super(Mymeta, self).__init__(class_name, class_bases, class_dic)
def __call__(self, *args, **kwargs): # 元类下的类在实例化对象的时候会调用这个方法
print("这是元类的__call__")
# 造对象
obj = object.__new__(self) # 用object类的方法__new__来造对象的方法,这个只能在元类中使用
# 初始化
self.__init__(obj, *args, **kwargs) # 传入参数
# 返回对象
return obj
# 首字母大写,有注释,这个类可以创建
class Chinese(object, metaclass=Mymeta): # 默认值:Chinese(object, metaclass=type)
'''
comment
'''
country = 'China'
def __init__(self, name, age):
self.name = name
self.age = age
def talk(self):
print('%s is talking' % self.name)
def __call__(self, *args, **kwargs):
print('这是Chinese的__call__')
# 调用就是加'()'执行
# 调用了类Chinese(本质是对象),所以触发了__call__
# 调用对象(类),实际上是执行对象的类(元类)的__call__方法
c1 = Chinese('aaa', 18) # 相当于执行 Chinese.__call__(self,'aaa', 18)
print(c1.__dict__)
c1() # 调用对象,实际上是执行对象的类的__call__方法
我们以单例模式来说明:
x = 1 # 用一切皆对象的观点,实际上是 x = int(1)
y = 1 # 同样是 y = int(1)
我们知道在python中上述代码的变量(本质其实是对象),因为value相同,所以内存地址是相同的。(参考小数据池)
那么,在python中,内容相同的对象我们可以让他们用同样的内存地址吗? 答案是肯定的,我们以下例来看一下: 单例模式: 实现方法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
obj1 = MySQL.singleton() # 内存地址都相同
obj2 = MySQL.singleton()
实现方式2:元类的方式
class Mymeta(type): # 元类
def __init__(self, class_name, class_bases, class_dic):
super(Mymeta, self).__init__(class_name, class_bases, class_dic)
self.__instance = None #
def __call__(self, *args, **kwargs): # 元类下的类在实例化对象的时候会调用这个方法
print("这是元类的__call__")
if not self.__instance:
obj = object.__new__(self) # 实例化空对象
self.__init__(obj) # 这个实例化的空对象传入空对象作为参数
self.__instance = obj
return self.__instance
# 返回对象
return obj
class MySQL(object, metaclass=Mymeta):
def __init__(self): # 这个初始化方式生成的对象都是一样的
self.host = '127.0.0.1'
self.port = 3306
obj1 = MySQL()
obj2 = MySQL()
print(obj1)
print(obj2)
原文:https://www.cnblogs.com/py-xiaoqiang/p/11210487.html