洗礼灵魂,修炼python(44)--巩固篇—反射之重新认识hasattr,gettattr,setattr,delattr...

不急着进入正题。先动手完成一个小程序:

设计一套简单的服务开启关闭程序,每次开启或关闭都得打印服务当前的状态:

class Server(object):
    def __init__(self):
        self.status='stop' #初始状态
    def start(self): #开启服务
        if self.status=='running': #执行服务前检测当前状态,根据状态不同做相应处理
            print("the Server was running,dont't need to start")
        else:
            print('starting the Server')
            self.status = 'running'

    def stop(self):  #关闭服务
        if self.status == 'stop':  #执行服务前检测当前状态,根据状态不同做相应处理
            print("the Server was stop,dont't need to stop")
        else:
            print('stopping the Server')
            self.status = 'stop'

    def restart(self):#重启服务
        self.stop()
        self.start()

测试结果:

很简单的就把问题解决了,由于我们这是在python的交互式界面下操作的,那么是针对于py文件,在操作系统下以脚本运行的方式输入【python py文件名】命令就运行呢?这就得稍微有点难度,不过也不是不行,就是运行了没有任何结果:

这虽然没报错,但是没有任何输出对吧?这样的程序等于废的了,之前说过,有个sys模块,可以通过sys发送指令,并让系统执行,那么我们导入sys模块并用argv方法捕获命令看看:

 

 捕获到了我们输入的test,好办了对吧?我可以直接在后面输入start,stop等命令,让服务执行相应操作了,稍微改动下代码是可行的:

 

既然这样可行了,但是我们想优化一下,因为假如说是一个大型项目,难道每一个命令我们都要手动输入一遍,并调用吗?是不是觉得这就不行了,完全违背了python的简洁优雅宗旨了吧?那么有没有具体的优化方案呢?

 

利用字典,在字典内做一个命令到方法的映射,瞬间就把效率提升了对吧?但是,我想你应该看到了,当调用的并不是方法的时候会报错,你说我再加一层if判断一下就行啊或者改代码就行啊对吧?这些都还不是主要的问题,如果在字典定义时,如果不慎将方法名或者属性名输入错误呢?那么程序就不行了啊对吧?这就和前几篇里的从游戏《绝地求生-大逃杀》了针对面向对象编程一个原理了对吧,那么那一篇里使用面向对象解决的,这里也是吗?喂喂,我这里就是面向对象啊,就是用的类在解决问题啊,那么这里到底怎么办呢?主角终于登场了(终于进入正题了,你们看着也累,其实我也觉得累)

使用什么方法呢?用hasattr和getattr搞定:

前面hasattr已经说过是判断属性是否存在类里,如果存在则返回True,反之返回False,这里的意思是如果这个类存在这个属性(而这个属性就是我们输入的字符串名),那么就获取到对应的属性的内存id,后面个括号表示实例化。问题解决了吧?

还有右边的为什么已经启动过一次关闭服务会提示已经关闭,因为代码初始的时候self.status='stop',命令每次运行都是从头开始的,并不是连贯的命令,所以出现这情况(感兴趣的自己去优化了,这个问题在本篇博文里不是重点)

那么你想,加入我要传入一个参数呢?又怎么搞呢?

赋值给一个变量就行,括号内传参。其他代码大体不变,不过今天的重点不在这,而是在类外层定义一个方法时,通过特使的方法让非类里的方法能调用类里的方法和属性,这个效果觉得有点不切实际是吧?但是使用setattr是可以的,并且还可以实现刚才的传参功能

import sys
class Server(object):
    def __init__(self):
        self.status='stop' #初始状态
    def start(self): #开启服务
        if self.status=='running': #执行服务前检测当前状态,根据状态不同做相应处理
            print("the Server was running,dont't need to start")
        else:
            print('starting the Server')
            self.status = 'running'

    def stop(self):  #关闭服务
        if self.status == 'stop':  #执行服务前检测当前状态,根据状态不同做相应处理
            print("the Server was stop,dont't need to stop")
        else:
            print('stopping the Server')
            self.status = 'stop'

    def restart(self):#重启服务
        self.stop()
        self.start()


def test(name): #测试方法,注意不在类里,这里的name表示是可以传参的,
        print('this is a test')
        print('by:%s'%name)

if __name__ == '__main__':
        s=Server()
        if hasattr(s,sys.argv[1]):
                getattr(s,sys.argv[1])() #获取实例的方法并调用
        setattr(s,'test',test)  #绑定到一个非类下的方法
        s.test('yang')  #传入值并返回 

 测试结果:

是不是瞬间觉得很屌啊?注意这里有个共识,这个test方法和类的start等方法有区别的对吧?那么怎么显得没有什么区别呢?还有怎么调用类里的方法呢?

先看看setattr的使用方法:

那么我们试着改下看看:

import sys
class Server(object):
    def __init__(self):
        self.status='stop' #初始状态
    def start(self): #开启服务
        if self.status=='running': #执行服务前检测当前状态,根据状态不同做相应处理
            print("the Server was running,dont't need to start")
        else:
            print('starting the Server')
            self.status = 'running'

    def stop(self):  #关闭服务
        if self.status == 'stop':  #执行服务前检测当前状态,根据状态不同做相应处理
            print("the Server was stop,dont't need to stop")
        else:
            print('stopping the Server')
            self.status = 'stop'

    def restart(self):#重启服务
        self.stop()
        self.start()


def test(self,name):  #self参数表示自身,为了和类里的方法统一
        print('this is a test')
        print('the status [%s] was by %s looked'%(self.status,name))

if __name__ == '__main__':
        s=Server()
        if hasattr(s,sys.argv[1]):
                func=getattr(s,sys.argv[1])
                func()

        setattr(s,'test',test)
        s.test(s,'yang')  #括号里的s则是self,因为并不是类的方法,所以直接写自身

测试结果:

成功了对吧?这个功能是不是有那么一点想装饰器啊?是的,确实挺像的,可以为定义好的类动态的扩展功能。

有扩展那么肯定有删除啊是吧?有吗?有的,delattr:

但这里却出错了,为什么,我删start删不掉啊,想想为什么?我这对象是s对吧?是Server的实例化对象,start是类的方法对吧?只是被s实例化后得到的方法,所以报错,那如果我删status可以不?

果然可行,报错提示的是不存在叫【status】属性名

那么你说我可以直接删类的方法不?就刚才报错没删掉的?试试看:

果然可行的。

 

好的,那么hasattr,getattr,setattr,delattr的实际用法就是这样,很实用的对吧?在实际开发中会经常用到的。像这种类似装饰器对类进行增删扩展操作的方法就叫反射。这就是本篇博文的主题。

 

这四个内置方法在前面就提过的,相关的总结也就不提了,本篇博文是作为对四个内置函数的巩固的。

 

 

转载于:https://www.cnblogs.com/Eeyhan/p/7743953.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这个错误是由于在使用PyTorch的Conv2d对象时,尝试访问'_-getstate_'属性而导致的。根据引用\[3\]中的信息,Conv2d对象没有'_-getstate_'属性。这可能是由于PyTorch版本不匹配导致的。在较新的PyTorch版本中,可能已经更改了Conv2d对象的属性。解决这个问题的方法是检查你所使用的PyTorch版本,并根据版本的不同采取相应的措施。如果你使用的是较新的版本,你可以尝试退回到PyTorch 1.0版本,并修改相应函数(如conv2d)内部的forward()方法,添加以下代码来处理padding_mode属性:if not hasattr(self, 'padding_mode'): self.padding_mode = "none"。这样可以确保在较新版本中缺少的属性被正确处理。 #### 引用[.reference_title] - *1* *2* [AttributeError: ‘Conv2d‘ object has no attribute ‘padding_mode‘ 报错](https://blog.csdn.net/Xqing_2016/article/details/112931869)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [PyTorch的初始化](https://blog.csdn.net/weixin_39734048/article/details/111822769)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值