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

一、反射

  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(‘大宝‘,)

自定义元类来控制类的调用的过程,即类的实例化过程

原文地址:https://www.cnblogs.com/Smart1san/p/9310677.html

时间: 2024-11-07 12:37:00

反射、自定义内置方法来定制类的功能、元类的相关文章

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

1.__str__方法在对象被打印时,自动触发,应该在该方法内采集与对象self有关的信息,然后拼成字符串返回 class People: def __init__(self,name,age): self.name=name self.age=age def __str__(self): print('======>') return '<name:%s age:%s>' %(self.name,self.age) obj=People('egon',18) obj1=People('

Python学习【第14篇】:面向对象之反射以及内置方法

面向对象之反射及内置方法 一.静态方法(staticmethod)和类方法(classmethod) 类方法:有个默认参数cls,并且可以直接用类名去调用,可以与类属性交互(也就是可以使用类属性) 静态方法:让类里的方法直接被类调用,就像正常调用函数一样 类方法和静态方法的相同点:都可以直接被类调用,不需要实例化 类方法和静态方法的不同点: 类方法必须有一个cls参数表示这个类,可以使用类属性 静态方法不需要参数 绑定方法:分为普通方法和类方法 普通方法:默认有一个self对象传进来,并且只能被

day27 反射、内置方法

一.isinstance和issubclass class Foo: pass class Son(Foo): pass s = Son() #判断一个对象是不是这个类的对象,传两个参数(对象,类) # print(isinstance(s,Son)) # print(isinstance(s,Foo)) # print(type(s) is Son) # print(type(s) is Foo) #判断一个类是不是另一类的子类,传两个参数(子类,父类) print(issubclass(So

09-06 反射、内置方法

一 反射 在Python中,反射指的是通过字符串来操作对象的属性,涉及到四个内置函数的使用(Python中一切皆对象,类和对象都可以用下述四个方法) class Teacher: def __init__(self,full_name): self.full_name =full_name t=Teacher('Egon Lin') # hasattr(object,'name') hasattr(t,'full_name') # 按字符串'full_name'判断有无属性t.full_name

面向对象之反射及内置方法

一.静态方法(staticmethod)和类方法(classmethod) 类方法:有个默认参数cls,并且可以直接用类名去调用,可以与类属性交互(也就是可以使用类属性) 静态方法:让类里的方法直接被类调用,就像正常调用函数一样 类方法和静态方法的相同点:都可以直接被类调用,不需要实例化 类方法和静态方法的不同点: 类方法必须有一个cls参数表示这个类,可以使用类属性 静态方法不需要参数 绑定方法:分为普通方法和类方法 普通方法:默认有一个self对象传进来,并且只能被对象调用-------绑定

面向对象的进阶---反射--一些内置方法

反射 反射和一些类的内置方法 1 isinstance ---- issubclass type()--判断 是不是 ininstance(object,cls) 判断 是不是类的对象 如果这个类有父类 这个对象也是这个父类的对象 issubclaaa(cls,cls) 判断一个类是不是另一个类的子类 ============================= 反射 ================================= 把一个字符串 类型的变量 变成一个 真实存在这个程序中的变量名

python全栈开发【第十七篇】面向对象反射和内置方法

一.静态方法(staticmethod)和类方法(classmethod) 类方法:有个默认参数cls,并且可以直接用类名去调用,可以与类属性交互(也就是可以使用类属性) 静态方法:让类里的方法直接被类调用,就像正常调用函数一样 类方法和静态方法的相同点:都可以直接被类调用,不需要实例化 类方法和静态方法的不同点: 类方法必须有一个cls参数表示这个类,可以使用类属性 静态方法不需要参数 绑定方法:分为普通方法和类方法 普通方法:默认有一个self对象传进来,并且只能被对象调用-------绑定

面向对象:反射、内置方法

反射:通过字符串映射到对象或者类的属性 反射的方法: class People: country = "China" def __init__(self,name,age): self.name = name self.age = age def talk(self): print("%s is talking" % self.name) obj = People("neo",22) """ 判断是否拥有某个属性:

面向对象进阶:反射以及内置方法

一.反射 反射:使用字符串数据类型的变量名来获取这个变量的值 input:用户输入的如果是a,那么打印1.如果输入的是b那么就打印2.如果输入name,那么打印alex 文件:从文件中读出的字符串,想转换成变量的名字 网络:将网络传输的字符串转换成变量的名字 1.反射类中的变量:静态属性,类方法 # class Foo: # School = 'oldboy' # Country = 'China' # language = 'Chinese' # @classmethod # def clas