Python:如何从__getattr__函数中获取函数名列表?

时间:2012-12-13 18:44:51

标签: python

如何从__getattr__函数中获取类函数列表?

Python v2.7,如果重要的话。

尝试在dir中使用__getattr__会导致无限递归。

class Hal(object):
    def __getattr__(self, name):
        print 'I don\'t have a %s function' % name
        names = dir(self) # <-- infinite recursion happens here
        print 'My functions are: %s' % ', '.join(names)
        exit()
    def close_door(self):
        pass
x = Hal()       
x.open_door()

这是我想要的输出:

I don't have a open_door function
My functions are: close_door, __getattr__, __init__, __doc__, ...

任何其他能让我得到我想要的输出的解决方案都能正常工作。我想在一个函数不存在的情况下进行模糊字符串匹配,以试图建议用户可能有什么意思。

4 个答案:

答案 0 :(得分:2)

names = self.__class__.__dict__

可能?

>>> class A:
...   def hello(self,x):
...       print "hello ",x
...   def my_dir(self):
...       print self.__class__.__dict__
...
>>> A().my_dir()
{'__module__': '__main__', 'my_dir': <function my_dir at 0x029A5AB0>, 'hello': <
 function hello at 0x029A5CB0>, '__doc__': None}

答案 1 :(得分:2)

你有什么理由不能这样做吗?

names = dir(self.__class__)

您是否希望消费者扩展Hal的实例以获得自定义方法?

如果您只想要实现的方法,但没有列出内置插件,您也可以尝试这样做:

names = [prop for prop in dir(self.__class__) if prop[1] != "_"]

答案 2 :(得分:2)

我认为这是有效的:

import types

class Hal(object):
    def __getattr__(self, name):
        print ('I don\'t have a %s function' % name)
        funcs = (name for name,func in self.__class__.__dict__.items() if isinstance(func,types.FunctionType))

        #names = dir(self) # <-- infinite recursion happens here
        print ('My functions are: %s' % ', '.join(str(f) for f in funcs))
        exit()

    @staticmethod
    def foo():
        pass

    @classmethod
    def bar(cls):
        pass

    def qux(self):
        pass

    def close_door(self):
        pass

x = Hal()
x.foo = 'bar'
x.open_door()

答案 3 :(得分:0)

一种解决方案是在添加dir方法之前制作__getattr__的副本:

class Hal(object):
    def __init__(self):
        self._names = dir(self)
        def __getattr__(self, name):
            print self.names
        self.__getattr__ = __getattr__

但是,对于简单的情况,您只需在类对象上调用dir(以及同样getattrinspect.getmembers或其他)来解决问题。如果实例可以在构造之后添加方法,则这不起作用,但如果这不是问题,则很容易:

names = dir(self.__class__)

但是你得到名字,过滤方法,有几件事要做。

首先,您可以在isinstance上使用getattr(self, name)并确保它是方法包装器(或获取绑定版本的类型并确保它是实例方法)。如果您直接从self.__class__.__dict__获取值,则不会得到完全相同的内容,就像您以自己喜欢的方式获取名称并拨打getattr(self, name)getattr(self.__class__, name)一样。特别是,实例方法将显示为function,它比方法包装器更容易测试。虽然其他一些案件现在更难以发现。

无论如何,基于类型的任何东西都不会找到像方法那样但不是的东西(例如,因为你已经直接为对象分配了一个内置函数,在某些类型的装饰器中包装了一些东西,书面自定义描述符,使用具有__callable__方法的类作为函数,等等。如果你正在做任何花哨的事情(或担心有人可能会在以后添加一些奇特的东西),你真的需要测试你是否可以显式绑定成员(或伪造它绑定到None),然后检查是否结果是callable,然后可能进行进一步的测试以确保它可以正确调用(因为否则你会被@staticmethod和类似的东西所欺骗。真的,如果出现这种情况(并且你真的想过你的设计并且说服自己和至少一个其他人并不疯狂......),你应该测试你能想到的每一个案例......

如果你想知道方法是在Hal中定义的还是实例而不是object或其他基类,有几种方法可以做到这一点,但最简单的方法是减去基类的成员。 (当然,如果你不关心实例中定义的方法,Hal.__dict__已经拥有了你想要的东西。)