python元类深刻理解

1.python 中的类

在python中,类也是一个对象,只不过这个对象拥有生成实例的能力,咱们通常使用class XXX来定义一个类,在python解释器执行到这个地方的时候会自动建立出这个对象,python也为咱们提供了手动建立类的方法,type()。type()这个方法对咱们来讲并不陌生,咱们所熟知的用法是:class = type(instance),当传入一个参数时,type()返回这个参数的类。而今天咱们要用到的是type的另外一个功能。type("classname",(object,),{"name":"jiao"})。当给type传入三个参数时,就是一个手动建立类的方式。python

class A():
    def __init__(self,name):
        self.name = name
        print("建立了一个实例")

a = type("a",(A,),{"name":"jiao"}) 
print(a)              #<class '__main__.a'>
print(a.name)          #jiao
print(a("jiang"))      #建立了一个实例  
                        #<__main__.a object at 0x00000280A973AA58>

 

type接收三个参数分别是:缓存

classname: 要建立的class 的名称app

object:要建立类的父类所组成的元组函数

sttr_dict: 要建立类的属性spa

type返回一个class,咱们接收并赋值到一个变量上,如今这个变量就指向咱们所建立的类,咱们能够经过这个变量来使用类。code

 

2.python 中的type

在python 中,几乎全部的东西都是对象,这包括整数、字符串、函数以及类。它们所有都是对象,并且它们都是从一个类建立而来——typeorm

3.__metaclass__属性

python在建立类时,会按照以下的流程进行:对象

 

Foo中有__metaclass__这个属性吗?若是是,Python会在内存中经过__metaclass__建立一个名字为Foo的类对象(我说的是类对象,请紧跟个人思路)。若是Python没有找到__metaclass__,它会继续在Bar(父类)中寻找__metaclass__属性,并尝试作和前面一样的操做。若是Python在任何父类中都找不到__metaclass__,它就会在模块层次中去寻找__metaclass__,并尝试作一样的操做。若是仍是找不到__metaclass__,Python就会用内置的type来建立这个类对象。blog

那么在__metaclass__中放置什么样的代码能够建立类呢?type,或者任何使用到type或者子类化type的东东均可以。内存

 

4.自定义元类

class UpperAttrMetaClass(type):
    def __new__(cls,class_name,class_parents,class_attr, *args, **kwargs):
        print("__new__")
        class_attr['name'] = "jiao"
        return type.__new__(cls,class_name,class_parents,class_attr)

    def __init__(self,*args,**kwargs):
        print("__init__")
        super().__init__(*args, **kwargs)
        self.__cache = {}

    def __call__(self, *args, **kwargs):
        print("__call__")
        if args in self.__cache:
            return self.__cache[args]
        else:
            obj = super().__call__(*args)
            self.__cache[args] = obj
            return obj


class A(metaclass=UpperAttrMetaClass):
    def __init__(self,name):
        self.name = name
        print("a.__init__")

 

 

5.类的建立流程

1.元类的__new__(),返回建立好的类。当咱们想要改变建立方式的时候就要重写这个方法。

2.元类的__init__(),初始化一些类的属性

 

6.实例建立流程

1.元类的__call__(),建立一个实例时,首先调用这个方法,返回建立好的实例,因此咱们能够经过改写这个方法来改变实例建立过程,好比实现单例模式

2.类的__init__(),初始化实例属性

 

7.元类的应用

1.单例模式

class Singleton(type):
    def __init__(cls,*args,**kwargs):
        cls.__instance = None
        super().__init__(*args,**kwargs)

    def __call__(cls, *args, **kwargs):
        if cls.__instance is None:
            cls.__instance = super().__call__(*args,**kwargs)
            return cls.__instance
        else:
            return cls.__instance

class Spam(metaclass=Singleton):
    def __init__(self):
        print("Creating Spam")

 

2.缓存模式
import weakref

class Cached(type):
    def __init__(cls,*args,**kwargs):
        super().__init__(*args,**kwargs)
        cls.__cache = weakref.WeakValueDictionary()

    def __call__(cls, *args, **kwargs):
        if args in cls.__cache:
            return cls.__cache[args]
        else:
            obj = super().__call__(*args)
            cls.__cache[args] = obj
            return obj


class Spams(metaclass=Cached):
    def __init__(self,name):
        print("Creating Spam({!r})".format(name))
        self.name = name

 

3.获取属性的定义顺序

 

能过获取到属性的定义顺序,咱们就能够经过简单的方法实现属性到数据的映射,能够更加简单的将类中的属性数据化。

from collections import OrderedDict

class Typed:
    _excepted_type = type(None)

    def __init__(self,name=None):
        self._name = name

    def __set__(self, instance, value):
        if not isinstance(value,self._excepted_type):
            raise TypeError("Excepted"+str(self._excepted_type))
        instance.__dict__[self._name] = value

class Integer(Typed):
    _excepted_type = int

class Float(Typed):
    _excepted_type = float

class String(Typed):
    _excepted_type = str

class OrderedMeta(type):

    def __new__(cls, clsname,bases,clsdict):
        d = dict(clsdict)
        order = []
        for name,value in clsdict.items():
            if isinstance(value,Typed):
                value._name = name
                order.append(name)
                d['_order'] = order
       return type.__new__(cls,clsname,bases,d)

    @classmethod
    def __prepare__(metacls, name, bases):
        return OrderedDict()

#注:__prepare__该方法会在类定义一开始的时候调用,调用时以类名和基类名称做为参数,它必须返回一个映射对象,供处理类定义体时调用


#eg.
class Structure(metaclass=OrderedMeta):

    def as_csv(self):
        return ','.join(str(getattr(self,name)) for name in self._order)

class Stock(metaclass=OrderedMeta):
    name = String()
    shares = Integer()
    price = Float()
    def __init__(self,name,shares,price):
        self.name = name
        self.shares = shares
        self.price = price

s = Stock("haha",23,23.3)
print(s.name)
s = Stock(34,23,34)
# print(s.as_csv())

 

 

8.小结

元类主要就是在类和实例建立的时候发挥做用,来实现一些功能。

相关文章
相关标签/搜索