在选项卡补全中隐藏弃用方法

3 投票
4 回答
1188 浏览
提问于 2025-04-15 20:56

我想控制一下,当用户在ipython中对一个自定义对象使用Tab键补全时,哪些方法会显示出来。特别是,我想隐藏那些我已经不推荐使用的函数。我还是希望这些方法可以被调用,但我不想让用户在查看这个对象时看到它们并开始使用。请问这有可能做到吗?

4 个回答

0

DeprecationWarning 这个警告只有在你调用某个方法的时候才会出现,所以你需要在类里面单独加一个属性,用来存储那些被弃用的方法的名字,然后在建议补全之前先检查一下这个属性。

另外,你也可以遍历这个方法的抽象语法树(AST),去寻找 DeprecationWarning,但如果这个类是用C语言定义的,或者这个方法可能会根据参数的类型或值发出 DeprecationWarning,那么这种方法就会失败。

1

看起来有一个特别的“魔法方法”,它是用来查看对象信息的,这个方法是通过 dir() 调用的,叫做 __dir__()。这不就是你想要的吗?

4

这是一个部分答案。我会先给你示例代码,然后解释为什么这只是部分答案。
代码如下:

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__属性中,用户可以找到它们。

撰写回答