究竟delattr能不能删除一个方法 ?

今天在跟一个朋友讨论到关于Python中的反射操作时,引出一个很有趣的问题,就是delattr究竟能不能用来删除一个对象的方法?

何以产生这样一个疑问呢,我们来看这样一段案例代码:

def func():
    pass
class MyClass:
    pass
mc = MyClass()
setattr(mc, 'myfunc', func)
print(hasattr(mc, 'myfunc'))  # 打印结果为True
delattr(mc, 'myfunc')
print(hasattr(mc, 'myfunc'))  # 打印结果为False

运行上面的代码,第一个print打印出来是True,第二个print打印出来是False。我们通过setattr方法为mc这个对象动态添加了一个叫myfunc的方法,然后又通过delattr方法动态删除了这个方法,这看起来似乎没什么问题,一切正常。

然后,我们再来看看下面这段代码:

class MyClass:
    def myfunc():
        pass
mc = MyClass()
print(hasattr(mc, 'myfunc'))  # 打印结果为True
delattr(mc, 'myfunc')
print(hasattr(mc, 'myfunc'))  # 打印结果为False

运行这段代码,发现报错了。

watermark,image_bG9nby9jc2RuXzEucG5nP3gtb3NzLXByb2Nlc3M9aW1hZ2UvcmVzaXplLGhfNjA=,g_se,x_0,y_0,t_100

提示属性错误,意思就是mc这个对象中没有myfunc这个属性。myfunc是mc这个对象的一个方法,这个报错没毛病。

但问题来了,为什么前面我们可以用delattr删除一个方法,而现在我们却不行了?

难道是因为只有动态添加的方法才能被删除,对象自身的方法就不行吗?这看起来有点奇怪,如果能删除方法的话应该都能删除才对。我们再来尝试下删除对象自身的属性,假设刚刚这个结论是正确的话,那么我们使用delattr来删除对象自身的属性应该也会失败。我们用代码来实践一下。

class MyClass:
    
    def __init__(self):
        self.name = 'test'
    def myfunc(self):
        pass
mc = MyClass()
print(hasattr(mc, 'name'))  # 打印结果为True
delattr(mc, 'name')
print(hasattr(mc, 'name'))  # 打印结果为False

运行上面这段代码,操作成功了,没有任何的报错。这说明一个问题,delattr并不仅仅只能操作动态添加的属性,也能操作对象本身的属性。

那么问题出在哪里呢?

其实仔细一看我们就会明白,真正的问题出在,不管是setattr和delattr,其实都只能针对对象的属性进行操作。

前面我们看到的通过delattr能够删除通过setattr动态添加的方法,其实也是一个假象。真相是通过setattr添加的一个方法并不是真的给这个对象添加了一个方法,而是添加了一个属性,setattr方法的第二个参数就是这个属性的名字,然后这个属性的值是一个指向外部函数的引用地址,所以当我们调用这个对象的属性时,实际上是间接调用了这个函数,看起来就像是这个对象添加了一个方法一样,但本质上仍然是添加的一个属性。

至此,前面的疑问全部解决了,大家记住,不管是setattr和delattr,其实都只能针对对象的属性进行操作,它们对对象的方法是无法直接操作的。

注:本文为蜗牛学院资深讲师卿淳俊老师原创,首发链接mp.weixin.qq.com/s/SPtS,切勿擅自盗用,如需转载请私聊我处获得授权并注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值