6

如何从函数中获取类函数列表__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

4 回答 4

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}
于 2012-12-13T18:46:07.460 回答
2

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

names = dir(self.__class__)

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

如果你只想要你已经实现的方法,没有列出内置函数,你也可以试试这个:

names = [prop for prop in dir(self.__class__) if prop[1] != "_"]
于 2012-12-13T18:50:39.637 回答
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()
于 2012-12-13T18:56:53.237 回答
0

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

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

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

names = dir(self.__class__)

不管你得到名字,过滤方法,有一些事情要做。

首先,您可以使用isinstanceongetattr(self, name)并确保它是一个方法包装器(或获取绑定版本的类型并确保它是一个实例方法)。如果您直接从 中获取值self.__class__.__dict__,则与以您最喜欢的方式获取名称并调用getattr(self, name)or的结果完全不同getattr(self.__class__, name)。特别是,实例方法将显示为function,这比方法包装器更容易测试。尽管其他一些案例现在变得更难被发现。

无论如何,任何基于类型的东西都不会找到像方法一样但不是的东西(例如,因为您已经将内置函数直接分配给对象,将某些东西包装在某些类型的装饰器中,编写自定义描述符,使用将__callable__方法作为函数的类等)。如果您正在做任何花哨的事情(或担心有人以后可能会添加一些花哨的东西),您确实需要测试您是否可以显式绑定成员(或将其假绑定到None),然后检查结果是否为callable,然后可能会做进一步的测试以确保它可以正确调用(因为否则你会被@staticmethods 和类似的东西)。真的,如果出现这种情况(并且您真的仔细考虑了您的设计,并说服自己和至少其他人相信这并不疯狂……),您应该针对您拥有的每个案例测试您能想到的一切……</ p>

如果您想知道方法是否定义在Hal实例中,而不是object另一个基类中,有几种方法可以做到这一点,但最简单的方法是减去基类的成员。(当然,如果您不关心实例中定义的方法,那么Hal.__dict__已经有了您想要的。)

于 2012-12-13T19:01:10.183 回答