反射自定义内置方法来定制类的功能元类

Posted smart1san

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了反射自定义内置方法来定制类的功能元类相关的知识,希望对你有一定的参考价值。

一、反射

  1. 定义:通过字符串来操作类或者对象属性

  2. 方法:hasattr、getattr、setattr、delattr

  3. 使用方法:

技术分享图片
 1 class People:
 2     def __init__(self,name):
 3         self.name=name
 4     def put(self):
 5         print(%s is putting%self.name)
 6     def get(self):
 7         print(%s get sth%self.name)
 8     def run(self):
 9         while True:
10             choice=input(>>).strip()
11             method=getattr(obj,choice,None)
12 
13             # # 判断对象obj里边有没有choice这个属性
14             # print(hasattr(obj,choice))
15 
16             # # obj.choice=z
17             # setattr(obj,choice,name)
18 
19             # # delete boj.msg
20             # delattr(obj,msg)
21             if method is None:
22                 print(command is not exists)
23             else:
24                 # getattr 是取得字符串并将该字符串转成可执行的函数
25                 method()
26 
27 obj=People(大王)
28 obj.run()
hasattr、setattr、getattr、delattr

  4.反射的好处:可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能

二、自定义内置方法来实现定制类的功能

  1. __str__

  

class People:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    
    # 在打印对象时会自动触发这个功能
    # 此时应该收集跟这个对象有关的信息,输出到屏幕上
    def __str__(self):
        return <%s : %s>%(self.name,self.age)

p=People(小天使,17)
print(p)

  2.__del__析构方法

class People:
    def __init__(self,name):
        self.name=name
        self.f=open(a.txt,rt,encoding=utf8)

    # 会在对象删除之前自动触发
    def __del__(self):
        # print(‘>>>>>>>‘)

        # 做回收系统资源相关的事情
        self.f.close()
p=People(魔鬼)
print()

三、元类

  1.定义

  在python中一切都是对象,所以用class 关键字定义的类本身也是一个对象,负责产生该对象的类称之为元类,即产生类的类即称为元类。

  2.为何用元类

  元类是负责产生类的,所以学习元类或者自定义元类的目的是为了控制类的产生过程,还可以控制对象的产生过程。

知识准备:

  内置函数exec的用法:将函数体代码执行一遍

# 将函数体代码执行一遍,放至局部{}中
msg=‘‘‘
x=1
def func():
    pass
‘‘‘
class_dic={}
exec(msg,{},class_dic)
print(class_dic)

    __call__的用法

    如果想要让实例化出来的对象变成可以调用的对象,则需要在该对象的类中定义一个__call__的方法,该对象会在调用时自动触发

class Foo:
    def __call__(self, *args, **kwargs):
        print(self)
        print(args)
        print(kwargs)

obj=Foo()
obj()
obj(1,2,3,x=1,y=2)

  执行结果入下图

技术分享图片

  3. 创建类的方法有两种

如果说类也是对象的话,那么用class关键字去创建类的过程也是一个实例化的过程

该实例化的目的是为了得到一个类,调用的是元类

3.1 方式一:用默认的元类type

class People:
    def __init__(self,name):
        self.name=name

    def eat(self):
        print(%s is eating...%self.name)

print(type(People))

3.1.1 创建类的三个要素 (类名,基类们,类的名称空间)

class_name=People‘     #类名
class_bases=(object,)   #基类
class_dic={}            #类的名称空间
class_body=‘‘‘          #类体代码
class People:
    def __init__(self,name):
        self.name=name

    def eat(self):
        print(‘%s is eating...‘%self.name)

print(type(People))
‘‘‘
exec(class_body,{},class_dic)

3.2 用的自定义的元类

class Mymeta(type):  # Mymeta=type(...)
    def __init__(self,class_name,class_bases,class_dic):
        super(Mymeta, self).__init__(class_name,class_bases,class_dic)
class People(object,metaclass=Mymeta): # People=Mymeta(类名,基类们,类的名称空间)
    def __init__(self,name):
        self.name=name
    def eat(self):
        print(%s is eating...%self.name)
p=People(小三炮)
p.eat()

原理:

  3.2.1 得到一个字符串的类名 class_name = ‘People‘

  3.2.2 得到一个类的基类们 class_bases = (object,)

  3.3.3 执行类体代码,得到一个类的名称空间 class_dic = {...}

  3.3.4 调用 People = type(class_name,class_bases,class_dic)

3.3 应用

  自定义元类控制类的产生过程,类的产生过程其实就是元类的调用过程

class Mymeta(type):
    def __init__(self,class_name,class_bases,class_dic):
        super(Mymeta, self).__init__(class_name,class_bases,class_dic)
        print(class_dic) # {‘__module__‘: ‘__main__‘, ‘__qualname__‘: ‘People‘, ‘__doc__‘: ‘ ‘,
                        #  ‘__init__‘: <function People.__init__ at 0x000001FCE6048AE8>}
        print(class_name)  # People
        print(class_bases)  # (<class ‘object‘>,)
        if class_dic.get(__doc__) is None and len(class_dic.get(__doc__))==0:
            raise TypeError(Document must exists and must not be None)
        if not class_name.istitle():
            raise NameError(First letter must be capital)
class People(object,metaclass=Mymeta):  # if class_name‘initials is not capital,it 
                                                  # will report an error
    ‘‘‘ hey guys ‘‘‘  
    def __init__(self,name):
        self.name=name
p=People(明日之星)
技术分享图片
 1 class Mymeta(type):
 2 
 3 
 4     def __call__(self, *args, **kwargs):
 5 
 6         # 先造出一个类的空对象
 7         obj=self.__new__(self)
 8 
 9         # 为该空对象初始化独有属性
10         self.__init__(obj,*args,**kwargs)
11 
12         # 返回一个初始化好的对象
13         return obj
14 
15 
16 class People(object,metaclass=Mymeta):
17     def __init__(self,name):
18         print(self)
19         self.name=name
20 
21     def eat(self):
22         print(%s is eating%self.name)
23     def __new__(cls, *args, **kwargs): #(涉及查找顺序)
24         print(cls)   # <class ‘__main__.People‘>
25         # cls.__new__(cls) # 错误
26         obj=super(People,cls).__new__(cls)
27         return obj
28 obj=People(大宝,)
自定义元类来控制类的调用的过程,即类的实例化过程

 

以上是关于反射自定义内置方法来定制类的功能元类的主要内容,如果未能解决你的问题,请参考以下文章

元类(metaclass)

面向对象之元类

python 面向对象专题:元类type反射函数与类的区别特殊的双下方法

python 面向对象专题:元类type反射函数与类的区别特殊的双下方法

反射元类 练习

Sublime Text自定制代码片段(Code Snippets)