4.15---元类练习

Posted zhubincheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了4.15---元类练习相关的知识,希望对你有一定的参考价值。

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

 




 

以上是关于4.15---元类练习的主要内容,如果未能解决你的问题,请参考以下文章

反射元类 练习

3.1.18 元类的练习

练习友元类和友元函数

深刻理解Python中的元类(metaclass)

深刻理解Python中的元类(metaclass)

面向对象进阶6:元类