元类对象

Posted bk134

tags:

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

# 1、在元类中控制把自定义类的数据属性都变成大写

class Mymeta(type):
    def __new__(cls, name,bases,attrs):
        update_attrs = {}
        for k,v in attrs.items():
            if not callable(v) and not k.startswith(__):
                update_attrs[k.upper()]=v
            else:
                update_attrs[k] = v
        return type.__new__(cls,name,bases,update_attrs)
class Chinese(metaclass=Mymeta):
    country=China
    tag=sdgfsdgds
    def walk(self):
        print(1)
print(Chinese.__dict__)

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 for key function)
        obj = object.__new__(self)
        for k, v in kwargs.items():
            obj.__dict__[k.upper()] = v
        return obj

class Chinese(metaclass=Mymeta):
    country=China
    tag=sdgfsdgds
    def walk(self):
        print(1)
p=Chinese(name=adasd,age=18,sex=)
print(p.__dict__)

3、在元类中控制自定义的类产生的对象相关的属性全部为隐藏属性

class Mymeta(type):
    def __call__(self, *args, **kwargs):
        #控制Foo的调用过程,即Foo对象的产生过程
        obj = self.__new__(self)
        self.__init__(obj, *args, **kwargs)
        obj.__dict__={_%s__%s %(self.__name__,k):v for k,v in obj.__dict__.items()}
        return obj

class Foo(metaclass=Mymeta):  # Foo=Mymeta(...)
    def __init__(self, name, age,sex):
        self.name=name
        self.age=age
        self.sex=sex
obj=Foo(lili,18,male)
print(obj.__dict__)

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

 

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

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

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

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

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

python 面向对象编程 之 元类

Python 元类