在选项卡补全中隐藏弃用方法
我想控制一下,当用户在ipython中对一个自定义对象使用Tab键补全时,哪些方法会显示出来。特别是,我想隐藏那些我已经不推荐使用的函数。我还是希望这些方法可以被调用,但我不想让用户在查看这个对象时看到它们并开始使用。请问这有可能做到吗?
4 个回答
DeprecationWarning
这个警告只有在你调用某个方法的时候才会出现,所以你需要在类里面单独加一个属性,用来存储那些被弃用的方法的名字,然后在建议补全之前先检查一下这个属性。
另外,你也可以遍历这个方法的抽象语法树(AST),去寻找 DeprecationWarning
,但如果这个类是用C语言定义的,或者这个方法可能会根据参数的类型或值发出 DeprecationWarning
,那么这种方法就会失败。
看起来有一个特别的“魔法方法”,它是用来查看对象信息的,这个方法是通过 dir() 调用的,叫做 __dir__()
。这不就是你想要的吗?
这是一个部分答案。我会先给你示例代码,然后解释为什么这只是部分答案。
代码如下:
class hidden(object): # or whatever its parent class is
def __init__(self):
self.value = 4
def show(self):
return self.value
def change(self,n):
self.value = n
def __getattr__(self, attrname):
# put the dep'd method/attribute names here
deprecateds = ['dep_show','dep_change']
if attrname in deprecateds:
print("These aren't the methods you're looking for.")
def dep_change(n):
self.value = n
def dep_show():
return self.value
return eval(attrname)
else:
raise AttributeError, attrname
现在有个注意事项:这些不是方法(注意第一个变量没有self)。如果你希望用户(或者你的代码)能够在任何被弃用的方法上调用im_class、im_func或im_self,那么这个方法就不适用了。而且,我很确定这样做会影响性能,因为你是在__getattr__
里面定义每个被弃用的函数。这不会影响你其他属性的查找(如果我把它们放在__getattribute__
里面,那就另当别论了),但会让访问这些被弃用的方法变慢。通过把每个函数定义放在自己的if块里面,而不是做列表检查,可以在很大程度上(但不是完全)减轻这个问题,不过,这样做可能会让维护变得很麻烦,尤其是当你的函数比较大时。
更新:
1) 如果你想把被弃用的函数变成方法(你确实应该这样做),只需在上面的代码片段中使用:
import types
return types.MethodType(eval(attrname), self)
而不是:
return eval(attrname)
并在函数定义中把self作为第一个参数。这样它们就变成实例方法了(你可以随心所欲地使用im_class、im_func和im_self)。
2) 如果__getattr__
这个方法让你不太满意,还有另一种选择(我知道的),虽然也有自己的注意事项,我们稍后会提到:把被弃用的函数定义放在__init__
里面,并用自定义的__dir__
来隐藏它们。这样,上面的代码就可以改成:
class hidden(object):
def __init__(self):
self.value = 4
from types import MethodType
def dep_show(self):
return self.value
self.__setattr__('dep_show', MethodType(dep_show, self))
def dep_change(self, n):
self.value = n
self.__setattr__('dep_change', MethodType(dep_change, self))
def show(self):
return self.value
def change(self, n):
self.value = n
def __dir__(self):
heritage = dir(super(self.__class__, self)) # inherited attributes
hide = ['dep_show', 'dep_change']
show = [k for k in self.__class__.__dict__.keys() + self.__dict__.keys() if not k in heritage + private]
return sorted(heritage + show)
这样做的好处是你不会在每次查找时重新定义函数,这样可以提高速度。缺点是,因为你不是在每次查找时重新定义函数,它们必须“持续存在”。所以,虽然自定义的__dir__
方法可以把你的被弃用方法从dir(hiddenObj)
中隐藏起来,从而也隐藏在IPython的自动补全中,但它们仍然存在于实例的__dict__
属性中,用户可以找到它们。