一、面向对象之反射

0.反射的含义

反射:自省的一种方式,利用字符串操作对象的数据和方法

用户所传递的信息都是字符串类型,所以利用反射可以与用户进行交互

1. hasattr:判断一个方法是否存在与这个类中
2. getattr:根据字符串去获取obj对象里的对应的方法的内存地址,加"()"括号即可执行
3. setattr:通过setattr将外部的一个函数绑定到实例中
4. delattr:删除一个实例或者类中的方法

1.hasattr(object,name)

判断对象是否含有某个字符串对应的属性名或者方法名

2.getattr()

根据字符串获取对象对应的属性名(值)或方法名

如果没有名字则会报错,所以常常和hasattr搭配使用

(1)案例中体会反射在与用户交互中的便捷与突破性

class C1:
    name = 'duoduo'

    def choice_name(self):
        print('你是谁')

# 产生C1的对象
obj = C1()

1)判断某个名字是否可以被使用(存在)

# 当我们想判断对象obj中是否存在某个名字,却不想让其报错的时候可以考虑到用异常处理
try:
    obj.aaa
except AttributeError:
    print('不存在这个名字')

2)判断用户随意指定的名字对象是否可以使用(存在)

# 在异常处理的基础上,增加与用户交互的功能
target_name = input('请输入名字:').strip()
try:
    obj.target_name
except AttributeError:
    print('不存在这个名字')

3)反射的功能则可以用字符串来操作对象的数据和方法

# 反射:利用字符串操作对象的数据和方法
print(hasattr(obj, 'name'))  # True
print(getattr(obj, 'name'))  # duoduo
print(getattr(obj, 'choice_name'))  # <bound method C1.choice_name of <__main__.C1 object at 0x103191f10>>

4)综合起来利用反射来和用户进行交互

# 利用反射的方法,来动态获取想判断的名字
class C1:
    name = 'duoduo'

    def choice_name(self):
        print('你是谁')


obj = C1()
while True:
    target_name = input('请输入名字:').strip()
    if hasattr(obj,target_name):
        print('有名字')
        # 获取该名字对应的数据(值  函数地址)
        data_or_func = getattr(obj,target_name)
        if callable(data_or_func):
            print('这名字是某个方法')
        else:
            print('这名字对应的是值')
            print(data_or_func)
    else:
        print('没有该名字')v

3.setattr(object, name, value)

根据字符串给对象设置或者修改数据

obj1 = C1()
setattr(obj1, 'age', 18)
print(obj1.__dict__)  # {'age': 18}

4.delattr(object, name)

根据字符串删除对象里面的名字

class C1:
    name = 'duoduo'

    def choice_name(self):
        print('你是谁')

        
obj1 = C1()  # 类C1产生了一个对象obj1

1.hasattr()判断名字是否存在
res = hasattr(obj1, 'choice_name')
print(res)  # True

2.setattr()  为obj1添加属性或者方法
setattr(obj1, 'age', 18)  # 为obj1增加一个属性为 age = 18
print(obj1.__dict__)  # {'age': 18} 查看后在obj1中成功增加来 age = 18的属性
setattr(obj1, 'age', lambda a: a + 1)
print(obj1.__dict__)  # {'age': <function <lambda> at 0x10242a280>}

3.delattr() 删除属性或者方法
delattr(obj1, 'age')
print(obj1.__dict__)  # {} 空集合代表,该对象没有自己独有的功能或者属性

二、反射实战案例

1.使用反射的场景:

​ 只要需求中出现了关键字:对象…字符串…

2.案例

(1)模拟终端

class WinCmd:
    def tasklist(self):
        print("""
        1.学习编程
        2.学习python
        3.学习英语
        """)

    def ipconfig(self):
        print("""
        地址:127.0.0.1
        地址:上海浦东新区
        """)

    def get(self, target_file):
        print('获取文件', target_file)

    def put(self, target_file):
        print('上传文件', target_file)

    def server_run(self):
        print("欢迎进入简易版本cmd终端".center(50, '='))
        while True:
            target_cmd = input('请输入您的指令>>>:')
            res = target_cmd.split(' ')  # 因为在终端中输入命令常常有空格
            if len(res) == 1:
                if hasattr(self, res[0]):
                    getattr(self, res[0])()  # 存在该命令则执行
                else:
                    print(f'{res[0]}不是内部或者外部命令')  # 如果传入了参数,则执行该命令并传入参数
            elif len(res) == 2:
                if hasattr(self, res[0]):
                    getattr(self, res[0])(res[1])
                else:
                    print(f'{res[0]}不是内部或者外部命令')


obj = WinCmd()  # 产生类WinCmd的对象
obj.server_run()  # 调用obj的方法server_run

(2)一切皆对象

利用反射保留某个py文件中所有的大写变量名以及对应到数据值

  • settings.py文件中
NAME = 'duoduo'
AGE = 13
desc = '吃饭天'
info = '没到点'

def name():
    print('name')

class Person:
    name = 'duoduo'

执行文件中

查看文件中的名字也可以用dir()方法,列举对象可以使用的名字

查看文件中的名字也可以用 __dict__ 方法,print(settings.__dict__)

但是文件中的名字会有很多,所以如果class类更适合用__dict__方法

(1)传统方法

import settings

print(dir(settings))  # dir是列举对象可以使用的名字
# ['AGE', 'NAME', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'desc', 'info']

1.方式一:for循环 + 判断
# 构造一个空字典,用来存放我们想要的名字
useful_dict = {}
for name in dir(settings):
    if name.isupper():  # 保留大写
        useful_dict[name] = getattr(settings,name)
print(useful_dict)  # {'AGE': 13, 'NAME': 'duoduo'}


2.方式二:生成式
useful_dict = {name: getattr(settings, name) for name in dir(settings) if name.isupper()}

print(useful_dict)
# {'AGE': 13, 'NAME': 'duoduo'}

(2)利于反射动态获取

# 用反射判断settings.py文件中是否有某个名字

while True:
    target_name = input('请输入您想判断的某个名字:').strip()
    if hasattr(settings, target_name):

        print(getattr(settings, target_name))
        """ 
        如果存在该名字则返回值,
        是方法则返回方法的内存地址<function name at 0x1004a7d30>,
        如果是类名则返回类的名字<class 'settings.Person'>
        """

    else:
        print('该模块文件中没有该名字')

原文地址:http://www.cnblogs.com/DuoDuosg/p/16867146.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性