1、在元类中控制把自定义类的数据属性都变成大写
class Mymeta(type): def __new__(cls, name, bases,attrs): new_attrs = {} print(attrs) # {'__module__': '__main__', '__qualname__': 'Person', 'name': 'Jil', 'age': 18, 'say': <function Person.say at 0x0000018C9300B3A0>} for k,v in attrs.items(): if not callable(v) and not k.startswith("__"): new_attrs[k.upper()] = v else: new_attrs[k] = v return type.__new__(cls,name,bases,new_attrs) class Person(metaclass=Mymeta): name = "Jil" age = 18 def say(self): print(self.name,self.age)
print(Person.__dict__) # {'__module__': '__main__', 'NAME': 'Jil', 'AGE': 18, 'say': <function Person.say at 0x0000018C9300B3A0>, '__dict__': <attribute '__dict__' of 'Person' objects>, #'__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
2、在元类中控制自定义的类无需__init__方法
1.元类帮其完成创建对象,以及初始化操作;
2.要求实例化时传参必须为关键字形式,否则抛出异常TypeError: must use keyword argument
3.key作为用户自定义类产生对象的属性,且所有属性变成大写
class Mymeta(type): def __call__(self, *args, **kwargs): if args: raise TypeError("must use keyword argument") Person_obj = self.__new__(self) # print(obj.__dict__) # 此时Person_obj该对象刚被初始化。名称空间还为空 for k,v in kwargs.items(): Person_obj.__dict__[k.upper()] = v return Person_obj class Person(metaclass=Mymeta): name = "Jil" age = 18 def say(self): print(self.name, self.age)
obj = Person(name="Fishball",age="16") print(obj.__dict__) # {'NAME': 'Fishball', 'AGE': '16'}
3、在元类中控制自定义的类产生的对象相关的属性全部为隐藏属性
class Mymeta(type): def __call__(self, *args, **kwargs): obj = self.__new__(self) self.__init__(obj,*args, **kwargs) # obj.__dict__= {"_%s__%s"%(obj.__class__,k):v for k,v in obj.__dict__.items()} # obj.__class__ 为 <class '__main__.Person'> ,不符合隐藏的命名规则 obj.__dict__= {"_%s__%s"%(self.__name__,k):v for k,v in obj.__dict__.items()} return obj class Person(metaclass=Mymeta): def __init__(self,name,age): self.name = name self.age = age p = Person("Jil",22) print(p.__dict__) # {'_Person__name': 'Jil', '_Person__age': 22}
4、基于元类实现单例模式
基于元类实现单例模式
单例:即单个实例,指的是同一个类实例化多次的结果指向同一个对象,用于节省内存空间
如果我们从配置文件中读取配置来进行实例化,在配置相同的情况下,就没必要重复产生对象浪费内存了
方式一:
#settings.py文件内容如下 HOST='1.1.1.1' PORT=3306 #方式一:定义一个类方法实现单例模式 import settings class Mysql: __instance=None def __init__(self,host,port): self.host=host self.port=port @classmethod def singleton(cls): if not cls.__instance: cls.__instance=cls(settings.HOST,settings.PORT) return cls.__instance obj1=Mysql('1.1.1.2',3306) obj2=Mysql('1.1.1.3',3307) print(obj1 is obj2) #False obj3=Mysql.singleton() obj4=Mysql.singleton() print(obj3 is obj4) #True
方式二:
import settings class Mymeta(type): def __init__(self,name,bases,dic): #定义类Mysql时就触发 # 事先先从配置文件中取配置来造一个Mysql的实例出来 self.__instance = object.__new__(self) # 产生对象 self.__init__(self.__instance, settings.HOST, settings.PORT) # 初始化对象 # 上述两步可以合成下面一步 # self.__instance=super().__call__(*args,**kwargs) super().__init__(name,bases,dic) def __call__(self, *args, **kwargs): #Mysql(...)时触发 if args or kwargs: # args或kwargs内有值 obj=object.__new__(self) self.__init__(obj,*args,**kwargs) return obj return self.__instance class Mysql(metaclass=Mymeta): def __init__(self,host,port): self.host=host self.port=port obj1=Mysql() # 没有传值则默认从配置文件中读配置来实例化,所有的实例应该指向一个内存地址 obj2=Mysql() obj3=Mysql() print(obj1 is obj2 is obj3) obj4=Mysql('1.1.1.4',3307)
方式三:
import settings def singleton(cls): #cls=Mysql _instance=cls(settings.HOST,settings.PORT) def wrapper(*args,**kwargs): if args or kwargs: obj=cls(*args,**kwargs) return obj return _instance return wrapper @singleton # Mysql=singleton(Mysql) class Mysql: def __init__(self,host,port): self.host=host self.port=port obj1=Mysql() obj2=Mysql() obj3=Mysql() print(obj1 is obj2 is obj3) #True obj4=Mysql('1.1.1.3',3307) obj5=Mysql('1.1.1.4',3308) print(obj3 is obj4) #False