Python中的反射与attr内置函数

一. 反射

反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)
在Python中反射的表现形式是:
通过字符串的形式操作对象相关的属性
在Python中通过四个函数实现反射:

函数名 意义
hasattr(obj,name) 判断object中有没有一个name字符串对应的方法或属性
getattr(obj,name, default) 检查obj.__dict__中有没有name这个键值,有则不做任何处理,没有则报错
setattr(obj,name,value) 等价于obj.name=value
delattr(obj,name) 等价于del obj.name
class People:
    country = 'China'

    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

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

    def sleep(self):
        print('% is sleeping' % self.name)

p1=People('Jack', 'male')

#检测是否含有某属性
print(hasattr(p1, 'name'))
print(hasattr(p1, 'eat'))

>>True
>>True

#获取属性
n = getattr(p1, 'name')
print(n)
func = getattr(p1, 'eat')
func()
getattr(p1, 'aaaaaaaa') #报错
print(getattr(p1, 'aaaaaaaa', 'not exist'))
>>Jack
>>Jack is eating
>>not exist

#设置属性
setattr(p1, 'Joe', 'female')
setattr(p1, 'run', lambda self: self.name+' is running')
print(p1.__dict__)
print(p1.run(p1))
>>{'name': 'Jack', 'gender': 'male', 'Joe': 'female', 'run': <function <lambda> at 0x0000021D2B3E3E18>}
>>Jack is running

#删除属性
print(p1.__dict__)
delattr(p1, 'name')
print(p1.__dict__)
>>  {'name': 'Jack', 'gender': 'male'}
>>{'gender': 'male'}
#只能删除对象的属性,如果是类那么只能删类的方法,如果是类实例化的对象只能删实例化对象的属性不能删类的,比如说执行delattr(p1, 'eat')会报错,如果删除的属性不存在也报错

反射当前模块成员

import sys


def s1():
    print('s1')


def s2():
    print('s2')


this_module = sys.modules[__name__]

print(hasattr(this_module, 's1'))
print(getattr(this_module, 's2'))

使用反射的用途

可插拔

可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用
建立``ftpClient.py`模块

class FtpClient:    # 仅定义,不实现具体方法
    def __init__(self, addr):
        print('正在连接服务器[%s]' % addr)
        self.addr = addr

建立ftpServer.py模块

from ftpClient import FtpClient

f1=FtpClient('192.168.1.1')
if hasattr(f1,'get'):
    func_get=getattr(f1,'get')
    func_get()
else:
    print('not exist')

>>正在连接服务器[192.168.1.1]
not exist

动态导入模块

通过字符串名称导入模块

import importlib
t = importlib.import_module('time')
print(t.time())

二. attr内置函数

__setattr__, __delattr__,__getattr__

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

    def __setattr__(self, key, value):
        print('running __setattr__')
        self.__dict__[key] = value

    def __getattr__(self, item):
        print('running __getattr__')
        pass

    def __delattr__(self, item):
        print('running __delattr__')
        self.__dict__.pop(item)

f = Foo('Jack')
print(f.__dict__)

f.name = 'Jax'
print(f.__dict__)

del f.name

print(f.__dict__)

f.xxx    #调用不存在的属性时才会触发__getattr__

>>running __setattr__
>>{'name': 'Jack'}
>>running __setattr__
>>{'name': 'Jax'}
>>running __delattr__
>>{}
>>running __getattr__ 

三. 定制自己的数据类型

包装

对已有的类型具有的功能进行扩展

class List(list):
    def append(self, p_object):
        if not isinstance(p_object, str):
            raise TypeError('must be str')
        super().append(p_object)

    @property
    def mid(self):  # 增加属性
        index = len(self) // 2
        return self[index]


l = List()
l.append('oo')
l.append('jj')
l.insert(0, 'ii')
print(l)
print(l.mid)

授权

授权:授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。

实现授权的关键点就是覆盖getattr方法

import time

class FileHandle:
    def __init__(self, filename, mode='r', encoding='utf-8'):
        self.file = open(filename, mode, encoding=encoding)
        self.mode = mode
        self.encoding = encoding

    def write(self, line):
        print('running write operation')
        t = time.strftime('%Y-%m-%d %X')
        self.file.write('[%s] %s' % (t, line))

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

f = FileHandle('a.txt', 'w+')

f.write('777')    # 通过授权实现执行write函数时,为所写内容添加时间
f.seek(0)
print(f.read())
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容