如何获得对象的方法和属性的完整列表?

问题:如何获得对象的方法和属性的完整列表?

dir(re.compile(pattern)) 

不返回pattern作为列表的元素之一。即它返回:

['__copy__', '__deepcopy__', 'findall', 'finditer', 'match', 'scanner', 'search', 'split', 'sub', 'subn']

根据手册,它应该包含

对象的属性名称,其类的属性名称,以及递归其类的基类的属性。

它也说

该列表不一定完整。

有没有办法获得完整的清单?我一直以为dir返回一个完整的列表,但显然并没有…

另外:有没有办法只列出属性?还是只有方法?

编辑:这实际上是python中的错误->据称它已在3.0分支中修复(也许在2.6中也已修复)

dir(re.compile(pattern)) 

does not return pattern as one of the lists’s elements. Namely it returns:

['__copy__', '__deepcopy__', 'findall', 'finditer', 'match', 'scanner', 'search', 'split', 'sub', 'subn']

According to the manual, it is supposed to contain

the object’s attributes’ names, the names of its class’s attributes, and recursively of the attributes of its class’s base classes.

It says also that

The list is not necessarily complete.

Is there a way to get the complete list? I always assumed that dir returns a complete list but apparently it does not…

Also: is there a way to list only attributes? Or only methods?

Edit: this is actually a bug in python -> supposedly it is fixed in the 3.0 branch (and perhaps also in 2.6)


回答 0

对于属性的完整列表,简短的答案是:否。问题在于属性实际上定义为getattr内置函数接受的参数。由于用户可以重新实现__getattr__,突然允许任何类型的属性,因此没有可能的通用方法来生成该列表。该dir函数返回__dict__属性中的键,即,如果__getattr__未重新实现该方法,则所有可访问的属性。

对于第二个问题,这没有任何意义。实际上,方法是可调用的属性,仅此而已。但是,您可以过滤可调用的属性,并使用该inspect模块确定类的方法,方法或函数。

For the complete list of attributes, the short answer is: no. The problem is that the attributes are actually defined as the arguments accepted by the getattr built-in function. As the user can reimplement __getattr__, suddenly allowing any kind of attribute, there is no possible generic way to generate that list. The dir function returns the keys in the __dict__ attribute, i.e. all the attributes accessible if the __getattr__ method is not reimplemented.

For the second question, it does not really make sense. Actually, methods are callable attributes, nothing more. You could though filter callable attributes, and, using the inspect module determine the class methods, methods or functions.


回答 1

这就是为什么__dir__()在python 2.6中添加了新方法的原因

看到:

That is why the new __dir__() method has been added in python 2.6

see:


回答 2

这是PierreBdR和Moe的答案的实用补充:

  • 对于Python> = 2.6和新型类dir()似乎就足够了。
  • 对于老式类,我们至少可以做一个标准模块来支持制表符补全:除了dir(),查找__class__,然后继续__bases__

    # code borrowed from the rlcompleter module
    # tested under Python 2.6 ( sys.version = '2.6.5 (r265:79063, Apr 16 2010, 13:09:56) \n[GCC 4.4.3]' )
    
    # or: from rlcompleter import get_class_members
    def get_class_members(klass):
        ret = dir(klass)
        if hasattr(klass,'__bases__'):
            for base in klass.__bases__:
                ret = ret + get_class_members(base)
        return ret
    
    
    def uniq( seq ): 
        """ the 'set()' way ( use dict when there's no set ) """
        return list(set(seq))
    
    
    def get_object_attrs( obj ):
        # code borrowed from the rlcompleter module ( see the code for Completer::attr_matches() )
        ret = dir( obj )
        ## if "__builtins__" in ret:
        ##    ret.remove("__builtins__")
    
        if hasattr( obj, '__class__'):
            ret.append('__class__')
            ret.extend( get_class_members(obj.__class__) )
    
            ret = uniq( ret )
    
        return ret

(测试代码和输出都被删除了简洁,但基本上对新风格的对象,我们似乎有相同的结果get_object_attrs()dir(),对于老式类主要除了dir()输出似乎是__class__属性。)

Here is a practical addition to the answers of PierreBdR and Moe:

  • For Python >= 2.6 and new-style classes, dir() seems to be enough.
  • For old-style classes, we can at least do what a standard module does to support tab completion: in addition to dir(), look for __class__, and then to go for its __bases__:

    # code borrowed from the rlcompleter module
    # tested under Python 2.6 ( sys.version = '2.6.5 (r265:79063, Apr 16 2010, 13:09:56) \n[GCC 4.4.3]' )
    
    # or: from rlcompleter import get_class_members
    def get_class_members(klass):
        ret = dir(klass)
        if hasattr(klass,'__bases__'):
            for base in klass.__bases__:
                ret = ret + get_class_members(base)
        return ret
    
    
    def uniq( seq ): 
        """ the 'set()' way ( use dict when there's no set ) """
        return list(set(seq))
    
    
    def get_object_attrs( obj ):
        # code borrowed from the rlcompleter module ( see the code for Completer::attr_matches() )
        ret = dir( obj )
        ## if "__builtins__" in ret:
        ##    ret.remove("__builtins__")
    
        if hasattr( obj, '__class__'):
            ret.append('__class__')
            ret.extend( get_class_members(obj.__class__) )
    
            ret = uniq( ret )
    
        return ret
    

(Test code and output are deleted for brevity, but basically for new-style objects we seem to have the same results for get_object_attrs() as for dir(), and for old-style classes the main addition to the dir() output seem to be the __class__ attribute.)


回答 3

仅补充:

  1. dir()强大/最基本的工具。(最推荐
  2. 比其他解决方案dir()只是提供自己的方式处理的输出dir()

    是否列出第二级属性,重要的是您自己进行筛选,因为有时您可能希望筛选出带有前划线的内部变量__,但有时您很可能需要__doc__文档字符串。

  3. __dir__()dir()返回相同的内容。
  4. __dict__并且dir()是不同的。__dict__返回不完整的内容。
  5. 重要提示__dir__()有时作者可能出于某种目的用函数,值或类型覆盖它。

    这是一个例子:

    \\...\\torchfun.py in traverse(self, mod, search_attributes)
    445             if prefix in traversed_mod_names:
    446                 continue
    447             names = dir(m)
    448             for name in names:
    449                 obj = getattr(m,name)

    类型错误:描述__dir__'object'对象需要一个自变量

    PyTorch的作者将__dir__()方法修改为需要参数的东西。此修改使dir()失败。

  6. 如果要使用可靠的方案来遍历对象的所有属性,请记住,每个pythonic标准都可以被覆盖并且不成立,并且每个约定都可能不可靠。

Only to supplement:

  1. dir() is the most powerful/fundamental tool. (Most recommended)
  2. Solutions other than dir() merely provide their way of dealing the output of dir().

    Listing 2nd level attributes or not, it is important to do the sifting by yourself, because sometimes you may want to sift out internal vars with leading underscores __, but sometimes you may well need the __doc__ doc-string.

  3. __dir__() and dir() returns identical content.
  4. __dict__ and dir() are different. __dict__ returns incomplete content.
  5. IMPORTANT: __dir__() can be sometimes overwritten with a function, value or type, by the author for whatever purpose.

    Here is an example:

    \\...\\torchfun.py in traverse(self, mod, search_attributes)
    445             if prefix in traversed_mod_names:
    446                 continue
    447             names = dir(m)
    448             for name in names:
    449                 obj = getattr(m,name)
    

    TypeError: descriptor __dir__ of 'object' object needs an argument

    The author of PyTorch modified the __dir__() method to something that requires an argument. This modification makes dir() fail.

  6. If you want a reliable scheme to traverse all attributes of an object, do remember that every pythonic standard can be overridden and may not hold, and every convention may be unreliable.


回答 4

这是我的操作方式,对于您要向其添加属性的简单自定义对象很有用:

给定使用obj = type("Obj",(object,),{})或简单创建的对象:

class Obj: pass
obj = Obj()

添加一些属性:

obj.name = 'gary'
obj.age = 32

然后,获取仅具有自定义属性的字典:

{key: value for key, value in obj.__dict__.items() if not key.startswith("__")}

# {'name': 'gary', 'age': 32}

This is how I do it, useful for simple custom objects to which you keep adding attributes:

Given an object created with obj = type("Obj",(object,),{}), or by simply:

class Obj: pass
obj = Obj()

Add some attributes:

obj.name = 'gary'
obj.age = 32

then, to obtain a dictionary with only the custom attributes:

{key: value for key, value in obj.__dict__.items() if not key.startswith("__")}

# {'name': 'gary', 'age': 32}