python面向对象之反射

Posted FHBIAO

tags:

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

#!/usr/bin/env python
# coding:utf-8

# 反射
# 对象的自省
# python中四种方法 hasattr  getattr  setattr  delattr 都可用于类和对象, 因为python中一切皆对象, 类也是对象。
# python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射) class black_intro: feture = ‘Ugly‘ def __init__(self, name, addr): self.name = name self.addr = addr def sell_house(self): print(‘%s 正在卖房子,SB才买呢。‘ % self.name) def rent_house(self): print(‘%s 正在租房子,SB才租。‘ % self.name) b1 = black_intro(‘众家地产‘, ‘苏州‘) print(hasattr(b1, ‘name‘)) print(hasattr(b1, ‘rent_house‘)) print(hasattr(b1, ‘sale_house‘)) # False print(getattr(b1, ‘name‘)) r = getattr(b1, ‘rent_house‘) r() print(getattr(b1, ‘age‘, ‘没找到它.‘)) setattr(b1, ‘group‘, ‘二货‘) setattr(b1, ‘age‘, ‘11‘) print(b1.__dict__) setattr(b1, ‘agea‘, lambda x: x + 3) setattr(b1, ‘func‘, lambda self: self.name + ‘SB公司‘) print(b1.func(b1)) print(b1.agea(12)) delattr(b1, ‘name‘) delattr(b1, ‘age‘) print(b1.__dict__) ### 反射的应用场景 可插拨设计 # 可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用 from ftp_client import FtpClient f1 = FtpClient(‘1.1.1.1‘) # f1.put()
### hasattr 和 getattr 通常是配合使用,如果有xx方法,才去执行xx方法。 if hasattr(f1, ‘put‘): func_get = getattr(f1, ‘put‘) func_get() else: print(‘其他的逻辑‘) import sys obj = sys.modules[__name__] # 当前模块 即自己所在模块 print(‘--------->‘,hasattr(obj,‘black_intro‘)) # 判断当前模块是否有属性
技术分享图片

上面代码中用到的一个示例模块:

技术分享图片
class FtpClient:
    ‘ftp客户端,但是还么有实现具体的功能‘
    def __init__(self,addr):
        print(‘正在连接服务器[%s]‘ %addr)
        self.addr=addr
    # def put(self):
    #     print(‘正在上传文件‘)
技术分享图片

 

类中使用的带有双下划线的 几个: __getattr__     __delattr__     __setattr__

技术分享图片
#!/usr/bin/env python
# coding:utf-8

# 类中内置的 __getattr__   __delattr__   __setattr__
# 只有 __getattr__ 最常用

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

    def __getattr__(self, item):  # 调用不存在的属性的时候会被执行
        print("---------------------")

    def __delattr__(self, item): # 删除的时候会调用
        print("执行了删除操作__delattr__")
        self.__dict__.pop(item)

    # def __setattr__(self, key, value):
    #     print("执行了__setattr__")
    #     # self.key=value # 这样会无限递归, 溢出
    #     self.__dict__[key] = value  # 直接操作字典,才是正确方式


f1 = Foo(9) # 当设置了__setattr__ 时,实例化的同时会自动执行它
print(f1.x)
f1.xxx # 触发 __getattr__

del f1.y # 删除时触发 __delattr__

f1.y1 = 33 # 设置时触发 __setattr__
print(f1.__dict__)
技术分享图片

 

技术分享图片
#!/usr/bin/env python
# coding:utf-8

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

    # def __getattr__(self, item):  # 调用不存在的属性的时候会被执行
    #     print("---------------------")
    #
    # def __delattr__(self, item): # 删除的时候会调用
    #     print("执行了删除操作__delattr__")
    #     self.__dict__.pop(item)

    def __setattr__(self, k, v):
        print(‘设置操作 __setattr__ ‘)
        # self.key=value # 这样会无限递归, 溢出
        # self.__dict__[k] = v  # 直接操作字典 是正确方式 
        if type(v) is str:
            print(‘可以设置‘)
            self.__dict__[k] = v.lower() # 且可以加上可控制的方法
        else:
            print(‘值 必须是字符串‘)


f2 = Foo(‘Alex‘)
f2.age =18
f2.gender =‘Male‘
print(f2.__dict__)
技术分享图片

 

技术分享图片
#!/usr/bin/env python
# coding:utf-8

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

    # def __getattr__(self, item):  # 调用不存在的属性的时候会被执行
    #     print("---------------------")

    def __delattr__(self, item): # 删除的时候会调用
        # print("执行了删除操作__delattr__")
        # self.__dict__.pop(item)
        print(‘不允许删除%s‘% item) # 可以控制不允许删除

    def __setattr__(self, k, v):
        print(‘设置操作 __setattr__ ‘)
        # self.key=value # 这样会无限递归, 溢出
        # self.__dict__[k] = v  # 直接操作字典
        if type(v) is str:
            print(‘可以设置‘)
            self.__dict__[k] = v.lower() # 且可以加上可控制的方法
        else:
            print(‘值 必须是字符串‘)


f2 = Foo(‘Alex‘)
f2.age =18
f2.gender =‘Male‘
print(f2.__dict__)
del f2.name
print(f2.__dict__)
技术分享图片

 

技术分享图片
#!/usr/bin/env python
# coding:utf-8

# 包装,来自于继承和派生的概念,根源是基于继承的标准类型。用来定制自己的方法
class List(list):
    def show_middle(self):
        mid_index = int(len(self)/2)
        return self[mid_index]

    # 自定义的append
    def append(self, obj):
        if type(obj) is str:
            super().append(obj)
        else:
            print("只能添加字符串")


l2 = list("azkaban")
print(l2,type(l2))
l3 = List(l2)
print(l3.show_middle())

l3.append(‘232‘)
print(l3)
技术分享图片
技术分享图片
#!/usr/bin/env python
# coding:utf-8

# 二次加工标准类型(包装)

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

    def __getattr__(self, item):  # 调用不存在的属性的时候会被执行
        print("[%s]属性不存在" % item)

    def __getattribute__(self, item): # 不管是否找到属性都会执行。
        print("执行了getattribute")
        raise AttributeError(‘抛出异常了。‘)  # 而在使用抛出异常之后,才会去执行 __getattr__


f2 = Foo(9)
print(f2.y)
# print(f2.age)
技术分享图片

 

授权

技术分享图片
#!/usr/bin/env python
# coding:utf-8

import time

## 类似于组合的方法
class FH:
    def __init__(self,na,mo,ec="utf-8"):
        self.file = open(na,mo,encoding=ec)
        self.mode = mo
        self.encoding = ec

    def write(self,line):
        t = time.strftime(‘%Y-%m-%d %X ‘)
        self.file.write(‘%s %s‘%(t,line))

    def __getattr__(self, item):
        return getattr(self.file,item)

f1 = FH(‘a.txt‘, ‘r+‘)
f1.write(‘aaaaaaaaaaaaaaa
‘)
f1.write(‘CPU温度过高
‘)
f1.write(‘内存不足
‘)
f1.write(‘硬盘剩余空间警告
‘)
f1.seek(0)  # 其实执行的是打开的文件对象的seek方法

print(f1.read())
技术分享图片

 

判断实例是否属于类:

技术分享图片
#!/usr/bin/env python
# coding:utf-8

class Foo:
    pass

class bar(Foo):
    pass


f1 = Foo()

print(isinstance(f1,Foo)) # 实例是否属于类
print(issubclass(bar,Foo)) # 参数1 是否 参数2 的子类

b1 = bar()
print(isinstance(b1,Foo)) # 也是True

print(type(b1)) # 查看实例的类是谁
技术分享图片

 

动态导入模块:

技术分享图片
#!/usr/bin/env python
# coding:utf-8

# 动态导入的方法:

# mt = __import__(‘m1.t‘) # 只能导入最顶级模块 点后面的不会被导入
# print(mt)
# m1.t.test1()
#
# from m1.t import test1,_test2
#
# test1()
# _test2()

import importlib

m = importlib.import_module(‘m1.t‘) # 动态导入就是基于反射的

print(m)
m.test1()
m.test2()

‘‘‘
动态导入模块方法1: __import__ 

说明:

  1. 函数功能用于动态的导入模块,主要用于反射或者延迟加载模块。

  2. __import__(module)相当于import module

举例说明:

首先创建一个模块目录lib,然后在目录内创建一个模块为:aa.py

模块代码为:

class c(object):
    def __str__(self):
        return ‘C language‘
在lib目录平级新建一个测试的模块,使用 __import__ 动态以字符串形式导入lib下的aa模块。

lib = __import__(‘lib.aa‘) # 相当于import lib
c = lib.aa.c()
print(c)
动态导入模块方法2:import importlib

实例还是上面的lib.aa模块,这里使用importlib进行动态导入(这个方法好理解,也是官方建议使用的)

import importlib
aa = importlib.import_module(‘lib.aa‘)
c = aa.c()
print(c)
‘‘‘
技术分享图片


以上是关于python面向对象之反射的主要内容,如果未能解决你的问题,请参考以下文章

Python之面向对象-反射

Python面向对象之反射,双下方法

python之面向对象之反射运用

Python系列之反射面向对象

Python-面向对象之反射

Python面向对象之反射