'''# 知识储备exec()# 参数1:字符串形式的命令# 参数2:全局作用域(字典形式),如果不指定默认就使用globals()# 参数3:局部作用域(字典形式),如果不指定默认就使用locals()'''# g = { # 'x': 2,# 'y': 4# }# l = {}# exec('''# global x, m# x = 10# m = 100## z = 3# ''', g, l)# print(g)# print(l)'''一切皆对象,元类(产生类的类叫元类,默认用class定义的类,他们的元类是type)'''# 一切皆对象,对象可以怎么用?# 1.都可以被引用,x = obj# 2.都可以当做函数的参数传入# 3.都可以当作函数的返回值# 4.都可以当做容器类型的元素,l = [func, time, obj, l]# # 类也是对象,Foo = type(...)# class Foo:# pass# obj = Foo()# print(type(obj))# print(type(Foo))# #产生类的类叫元类,默认用class定义的类,他们的元类是type'''定义类'''# 方式一class# class Chinese:# country = 'china'# def __init__(self, name):# self.name = name# def talk(self):# print('%s is talking' % self.name)# print(Chinese)# 方式二type#定义类三要素 类名,类的基类, 类的名称空间# class_name = 'Chinese'# class_bases = (object,)# class_body = '''# country = 'china'# def __init__(self, name):# self.name = name# def talk(self):# print('%s is talking' % self.name)# '''# class_dic = {}# exec(class_body, globals(), class_dic)# # print(class_dic)## Chinese1 = type(class_name, class_bases, class_dic)# print(Chinese1)'''自定义元类控制类的创建'''# class Mymeta(type):# def __init__(self, class_name, class_bases, class_dic):# if not class_name.istitle():# raise TypeError('类名首字母必须大写')# if '__doc__' not in class_dic or not class_dic['__doc__'].strip():# raise TypeError('必须有注释,且注释不能为空')# super(Mymeta, self).__init__(class_name, class_bases, class_dic)# class Chinese(object, metaclass = Mymeta):# '''# 国人# '''# country = 'china'# def __init__(self, name):# self.name = name# def talk(self):# print('%s is talking' % self.name)# c = Chinese('name')# # Chinese = type(class_name, class_bases, class_dic)'''知识储备__call__方法'''# class Foo:# def __call__(self, *args, **kwargs):# print(self)# print(args)# print(kwargs)# obj = Foo()# obj(1, 2, 3, a=1, b=2, c=3)# 元类内部也应该有一个__call__方法,会在调用Foo时触发执行'''自定义元类控制类的实例化行为'''# class Mymeta(type):# def __init__(self, class_name, class_bases, class_dic):# if not class_name.istitle():# raise TypeError('类名首字母必须大写')# if '__doc__' not in class_dic or not class_dic['__doc__'].strip():# raise TypeError('必须有注释,且注释不能为空')# super(Mymeta, self).__init__(class_name, class_bases, class_dic)# def __call__(self, *args, **kwargs):# # print(self)# # print(args)# # print(kwargs)# # 第一件事,造一个空对象# obj = object.__new__(self)# # 第二件事,初始化# self.__init__(obj, *args, **kwargs)# # 第三件事,返回obj# return obj# class Chinese(object, metaclass = Mymeta):# '''# 国人# '''# country = 'china'# def __init__(self, name):# self.name = name# def talk(self):# print('%s is talking' % self.name)# obj = Chinese('xander') # Chinese.__call__(Chinese, 'xander')# print(obj.__dict__)'''自定义元类控制类的实例化行为的应用'''# 单例模式# 实现方式一:# 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()# # obj2 = MySQL()# # print(obj1)# # print(obj2)# obj1 = MySQL.singleton()# obj2 = MySQL.singleton()# print(obj1 is obj2)# 实现方式二:元类的方式class Mymeta(type): def __init__(self, class_name, class_bases, class_dic): if not class_name.istitle(): raise TypeError('类名首字母必须大写') if '__doc__' not in class_dic or not class_dic['__doc__'].strip(): raise TypeError('必须有注释,且注释不能为空') super(Mymeta, self).__init__(class_name, class_bases, class_dic) self.__instance = None def __call__(self, *args, **kwargs): if not self.__instance: obj = object.__new__(self) self.__init__(obj) self.__instance = obj return self.__instanceclass Mysql(object, metaclass=Mymeta): '''单例模式''' 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.__instanceobj1 = Mysql()obj2 = Mysql()print(obj1 is obj2)
练习
# 练习一:在元类中控制把自定义类的数据属性都变成大写class Mymate(type): def __new__(cls, name, args, kwargs): obj = {} print(name) print(args) print(kwargs) for a, b in kwargs.items(): if not a.startswith('__'): obj[a.upper()] = b else: obj[a] = b return type.__new__(cls, name, args, obj)class Chinese(object, metaclass=Mymate): country = 'chinese' def talk(self): print('is talking')print(Chinese.__dict__)# 练习二:在元类中控制自定义的类无需init方法# 1.元类帮其完成创建对象,以及初始化操作;# 2.要求实例化时传参必须为关键字形式,否则抛出异常TypeError: must use keyword argument# 3.key作为用户自定义类产生对象的属性,且所有属性变成大写class Mymate(type): def __call__(self, *args, **kwargs): if args: raise TypeError(':must use keyword argument') obj = object.__new__(self) #创建对象,self为类Chinese for k, v in kwargs.items(): obj.__dict__[k.upper()] = v return objclass Chinese(object, metaclass=Mymate): country = 'chinese' def talk(self): print('is talking')p = Chinese(name='egon', age=18, sex='male')print(p.__dict__)