反射与内置方法

反射

在Python中,反射指的是通过字符串来操作对象的属性,涉及到四个内置函数的使用(Python中一切皆对象,类和对象都可以用下述四个方法)

  • hasattr(对象名, 属性名) : 判断某个对象是否存在某个属性

  • getattr(对象名, 属性名, 默认值) : 从对象中取出属性,第三个值是默认值,当属性不存在时返回默认值

  • setattr(对象名, 属性名, 属性值) : 为对象增加新的属性和值

  • delattr(对象名, 属性名) : 删除对象的属性

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

# getattr(object, 'name', default=None)
getattr(t,'full_name',None) # 等同于t.full_name,不存在该属性则返回默认值None

# setattr(x, 'y', v)
setattr(t,'age',18) # 等同于t.age=18

# delattr(x, 'y')
delattr(t,'age') # 等同于del t.age

基于反射可以十分灵活地操作对象的属性,比如将用户交互的结果反射到具体的功能执行

>>> class FtpServer:
...     def serve_forever(self):
...         while True:
...             inp=input('input your cmd>>: ').strip()
...             cmd,file=inp.split()
...             if hasattr(self,cmd): # 根据用户输入的cmd,判断对象self有无对应的方法属性
...                 func=getattr(self,cmd) # 根据字符串cmd,获取对象self对应的方法属性
...                 func(file)
...     def get(self,file):
...         print('Downloading %s...' %file)
...     def put(self,file):
...         print('Uploading %s...' %file)
... 
>>> server=FtpServer()
>>> server.serve_forever()
input your cmd>>: get a.txt
Downloading a.txt...
input your cmd>>: put a.txt
Uploading a.txt...

补充: python中一切皆对象,模块也是对象,也可通过反射获取模块中的属性方法

反射的好处

实现可插拔机制

有俩程序员,一个lili,一个是eg,lili在写程序的时候需要用到eg所写的类,但是eg去跟女朋友度蜜月去了,还没有完成他写的类,lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等eg度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。

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

# eg没有完成的代码
class FtpClient():
    # ftp客户端,但是还没实现功能
    def __init__(self, addr):
        self.addr = addr
# lili的代码
#from module import FtpClient
f1=FtpClient('192.168.1.1')
if hasattr(f1,'get'):
    func_get=getattr(f1,'get')
    func_get()
else:
    print('---->不存在此方法')
    print('处理其他的逻辑')

不影响lili的代码编写

内置方法

Python的Class机制内置了很多特殊的方法来帮助使用者高度定制自己的类,这些内置方法都是以双下划线开头和结尾的,会在满足某种条件时自动触发.

  • __init__(self)

1.对象绑定方法

2.实例化对象时触发

场景:实例化对象时,会将 空对象和参数传给__init__

  • __str__(self)

1.对象绑定方法

2.打印obj时触发

场景:可以自定义print(obj)打印结果

注意: 必须要有返回值,且是字符串类型

  • __del__(self)

1.对象绑定方法

2.在对象被python系统回收之前触发,即:删除对象时

场景:脚本文件运行完python系统就会回收所有的变量,包括类的对象,如果此时在类中开启了一个需要操作系统才能回收掉的资源(如:发开文件),就需要在触发__del__函数体内将打开的文件关闭

  • __call__(self, *args, **kwargs)

1.对象绑定方法

2.调用对象或调用类时触发,即:obj(),class 类名()

3.__call__的返回值就是obj

注意: class 类名() 时,触发的是元类中的__call__

发生了三件事:

    1). 调用object.__new__ 得到一个空对象obj

        obj=self.__new__(self)

    2). 调用obj.__init__,将空对象和参数传进去

        self.__init__(obj, *args, **kwargs)

    3). 将obj return出来

        return obj

场景: 用来自定义类的创建过程

  • __doc__

类名.__doc__ 可以查看类中写的文档注释

  • __new__(self)

类加括号时,用来产生一个空对象的

  • __slots__

何禁止从外部修改实例属性

我们可以通过 __slots__ 来严格防止别人访问定义的实例属性

Python在存储实例的过程实际上是存储到 __dict__ 字典里

__slots_ 的作用就是一旦在类里定义了该属性,那么Python将再不会创建dict了,而是把实例属性存储到

__slots__ 里面(实际上是定义了一个描述器来存储)

  • 用点访问属性时

__getattr__ 用点访问属性时 如果属性不存在时执行

__setattr__ 用点访问属性时

__delattr__ 用 del 对象.属性 删除属性时执行

  • 用[ ]访问属性时

__getitem__ 当你用中括号取获取属性时 执行

__setitem__ 当你用中括号设置属性时 执行

__delitem__ 当你用中括号删除属性时 执行

  • __getattribute__

# 回顾__getattr__
class Foo:
    def __init__(self,x):
        self.x=x

    def __getattr__(self, item):
        print('执行的是我')
        # return self.__dict__[item]

f1=Foo(10)
print(f1.x)
f1.xxxxxx #不存在的属性访问,触发__getattr__
# __getattribute__
class Foo:
    def __init__(self,x):
        self.x=x

    def __getattribute__(self, item):
        print('不管是否存在,我都会执行')

f1=Foo(10)
f1.x
f1.xxxxxx
# 两者同时出现
#_*_coding:utf-8_*_
__author__ = 'xxx'

class Foo:
    def __init__(self,x):
        self.x=x

    def __getattr__(self, item):
        print('执行的是我')
        # return self.__dict__[item]
    def __getattribute__(self, item):
        print('不管是否存在,我都会执行')
        raise AttributeError('哈哈')

f1=Foo(10)
f1.x
f1.xxxxxx

#当__getattribute__与__getattr__同时存在,只会执行__getattrbute__,除非__getattribute__在执行过程中抛出异常AttributeError

补充

  • isinstance(要判断的对象, 要判断的类型)

判断一个对象是否是某个类的实例

def num(a, b):
    if isinstance(a, int) and isinstance(b, int):
        return a + b
    return None

print(num(20, 50))
  • issubclass(子类, 父类)

判断一个类是否是类一个类的子类

class Animal:
    def eat(self):
        print('吃')

class Pig(Animal):
    def eat(self):
        print('from pig')

class Tree:
    def eat(self):
        print('光合作用')

def mange(obj):
    if issubclass(type(p), Animal):
        obj.eat()
    else:
        print('非动物')

p = Pig()
t = Tree()

mange(p)
mange(t)
发布了163 篇原创文章 · 获赞 4 · 访问量 1803

猜你喜欢

转载自blog.csdn.net/Waller_/article/details/104062024