''' # 知识储备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.__instance class 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.__instance obj1 = 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 obj class Chinese(object, metaclass=Mymate): country = 'chinese' def talk(self): print('is talking') p = Chinese(name='egon', age=18, sex='male') print(p.__dict__)