【问题标题】:List attributes of an object [duplicate]列出对象的属性[重复]
【发布时间】:2011-02-10 03:04:11
【问题描述】:

有没有办法获取类实例中存在的属性列表?

class new_class():
    def __init__(self, number):
        self.multi = int(number) * 2
        self.str = str(number)

a = new_class(2)
print(', '.join(a.SOMETHING))

期望的结果是输出“multi, str”。我希望它可以查看脚本各个部分的当前属性。

【问题讨论】:

  • 实际上 Python 中的每个人都将他们的类命名为 NewClass。如果您使用像 new_class 这样的命名约定,您可能会违背人们的期望。
  • 尽管它是人机交互的并且不能以编程方式使用,help() 函数有助于获取有关类、函数、内置函数、模块等的信息

标签: python class python-3.x


【解决方案1】:
>>> class new_class():
...   def __init__(self, number):
...     self.multi = int(number) * 2
...     self.str = str(number)
... 
>>> a = new_class(2)
>>> a.__dict__
{'multi': 4, 'str': '2'}
>>> a.__dict__.keys()
dict_keys(['multi', 'str'])

您可能还会发现pprint 很有帮助。

【讨论】:

  • dict 使用问题刚刚出现在 r/python 上。有人指出 vars(a) 等价于 a.__dict__
  • 如果有人想知道,这也适用于 Python 2.7
  • 具体来说,pprint.pprint(a.__dict__) 对属性进行了漂亮的打印。
  • 请注意,这仅适用于用户定义的类,不适用于内置或扩展类型。
  • 如果类有 __slots__ 而不是 __dict__,这将不起作用,如果两者都有,则将部分起作用。
【解决方案2】:
dir(instance)
# or (same value)
instance.__dir__()
# or
instance.__dict__

然后你可以用type()测试什么类型或者callable()是否是一个方法。

【讨论】:

  • dir 在具有重载属性 get/set 的类上效果更好
  • dir(instance) 列出了很多你可能不感兴趣的东西
  • 这是唯一让我在 sklearn 的 boston 数据集上获得所有可用属性的函数 - __dict__ 是空的,而实际上有 5 个可用属性
  • dir() 正是我在谷歌上搜索“Python 对象列表属性”时所寻找的——一种检查不熟悉对象的实例并找出它的样子的方法。
【解决方案3】:

前面的所有答案都是正确的,你有三个选项来回答你的问题

  1. dir()

  2. vars()

  3. __dict__

>>> dir(a)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'multi', 'str']
>>> vars(a)
{'multi': 4, 'str': '2'}
>>> a.__dict__
{'multi': 4, 'str': '2'}

【讨论】:

  • vars(foo) 返回foo.__dict__
  • 但它的可读性更强
【解决方案4】:

vars(obj) 返回对象的属性。

【讨论】:

    【解决方案5】:

    Inspect module:

    inspect 模块提供了几个有用的函数来帮助获取 有关活动对象的信息,例如模块、类、方法、 函数、回溯、框架对象和代码对象。


    使用getmembers(),您可以查看类的所有属性及其值。要排除私有或受保护的属性,请使用.startswith('_')。要排除方法或函数,请使用inspect.ismethod()inspect.isfunction()

    import inspect
    
    
    class NewClass(object):
        def __init__(self, number):
            self.multi = int(number) * 2
            self.str = str(number)
    
        def func_1(self):
            pass
    
    
    a = NewClass(2)
    
    for i in inspect.getmembers(a):
        # Ignores anything starting with underscore 
        # (that is, private and protected attributes)
        if not i[0].startswith('_'):
            # Ignores methods
            if not inspect.ismethod(i[1]):
                print(i)
    

    请注意ismethod() 用于i 的第二个元素,因为第一个元素只是一个字符串(其名称)。

    题外话:使用CamelCase 作为类名。

    【讨论】:

      【解决方案6】:
      >>> ', '.join(i for i in dir(a) if not i.startswith('__'))
      'multi, str'
      

      这当然会打印类定义中的任何方法或属性。您可以通过将i.startwith('__') 更改为i.startwith('_') 来排除“私有”方法

      【讨论】:

        【解决方案7】:

        您可以使用dir(your_object) 获取属性,使用getattr(your_object, your_object_attr) 获取值

        用法:

        for att in dir(your_object):
            print (att, getattr(your_object,att))
        

        如果您的对象没有 __dict__,这将特别有用。如果不是这种情况,您也可以尝试 var(your_object)

        【讨论】:

          【解决方案8】:

          经常提到要列出完整的属性列表,您应该使用dir()。但是请注意,与流行的看法相反,dir() 并没有带出 所有 属性。例如,您可能会注意到类的dir() 列表中可能缺少__name__,即使您可以从类本身访问它。来自dir() (Python 2, Python 3) 上的文档:

          因为提供 dir() 主要是为了方便在 交互式提示,它尝试提供一组有趣的名称 不仅仅是它试图提供一个严格或一致定义的集合 名称,其详细行为可能会因版本而异。为了 例如,当元类属性不在结果列表中时 参数是一个类。

          像下面这样的函数往往更完整,尽管不能保证完整性,因为dir() 返回的列表可能会受到许多因素的影响,包括实现__dir__() 方法,或自定义__getattr__() 或@987654331 @ 在班级或其父母之一上。有关详细信息,请参阅提供的链接。

          def dirmore(instance):
              visible = dir(instance)
              visible += [a for a in set(dir(type)).difference(visible)
                          if hasattr(instance, a)]
              return sorted(visible)
          

          【讨论】:

            【解决方案9】:

            有不止一种方法可以做到:

            #! /usr/bin/env python3
            #
            # This demonstrates how to pick the attiributes of an object
            
            class C(object) :
            
              def __init__ (self, name="q" ):
                self.q = name
                self.m = "y?"
            
            c = C()
            
            print ( dir(c) )
            

            运行时,此代码产生:

            jeffs@jeff-desktop:~/skyset$ python3 attributes.py 
            ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__',      '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'm', 'q']
            
            jeffs@jeff-desktop:~/skyset$
            

            【讨论】:

              【解决方案10】:

              你要这个干什么?如果不知道您的确切意图,可能很难为您提供最佳答案。

              • 如果您想以特定方式显示类的实例,手动执行此操作几乎总是更好。这将准确包括您想要的内容,而不包括您不想要的内容,并且顺序将是可预测的。

                如果您正在寻找一种显示类内容的方法,请手动格式化您关心的属性并将其作为__str____repr__ 方法提供给您的类。

              • 如果您想了解对象存在哪些方法等以了解其工作原理,请使用helphelp(a) 将根据其文档字符串向您显示有关对象类的格式化输出。

              • dir 用于以编程方式获取对象的所有属性。 (访问__dict__ 会做一些我认为相同但我不会使用自己的事情。)但是,这可能不包括你想要的东西,它可能包括你不想要的东西。它不可靠,人们认为他们想要它的次数比实际要多得多。

              • 在有些正交的注释中,目前对 Python 3 的支持很少。如果你对编写真正的软件感兴趣,你会想要第三方的东西,比如 numpy、lxml、Twisted、PIL,或者任何数量的还不支持 Python 3 并且没有计划很快推出的 Web 框架。 2.6 和 3.x 分支的差别很小,但是库支持的差别很大。

              【讨论】:

              • 我只想指出,五年后(现在),我相信你提到的所有第三方模块都支持python3。来源:python3wos.appspot.com
              【解决方案11】:

              请看已经按顺序执行的python shell脚本,这里会得到一个以逗号分隔的字符串格式的类的属性。

              >>> class new_class():
              ...     def __init__(self, number):
              ...         self.multi = int(number)*2
              ...         self.str = str(number)
              ... 
              >>> a = new_class(4)
              >>> ",".join(a.__dict__.keys())
              'str,multi'<br/>
              

              我正在使用 python 3.4

              【讨论】:

              • 如果你只想要列表可以使用a.__dict__.keys()。但是,如果您想知道一个对象是否具有特定属性,您可以使用hasattr
              【解决方案12】:

              除了这些答案之外,我还将包含一个函数(python 3),用于几乎吐出任何值的整个结构。它使用dir 建立完整的属性名称列表,然后对每个名称使用getattr。它显示值的每个成员的类型,并在可能的情况下还显示整个成员:

              import json
              
              def get_info(obj):
              
                type_name = type(obj).__name__
                print('Value is of type {}!'.format(type_name))
                prop_names = dir(obj)
              
                for prop_name in prop_names:
                  prop_val = getattr(obj, prop_name)
                  prop_val_type_name = type(prop_val).__name__
                  print('{} has property "{}" of type "{}"'.format(type_name, prop_name, prop_val_type_name))
              
                  try:
                    val_as_str = json.dumps([ prop_val ], indent=2)[1:-1]
                    print('  Here\'s the {} value: {}'.format(prop_name, val_as_str))
                  except:
                    pass
              

              现在以下任何一项都应该提供洞察力:

              get_info(None)
              get_info('hello')
              
              import numpy
              get_info(numpy)
              # ... etc.
              

              【讨论】:

              • 是的,这是一个救星。无法弄清楚为什么我无法轻松解压缩这些列表,并且确实足够类型具有“元组”类型的属性“slots”这是 slots 值:[“nsname ", "hostmaster", "serial", "refresh", "retry", "expires", "minttl", "ttl" ]
              【解决方案13】:

              获取对象的属性

              class new_class():
                  def __init__(self, number):
                  self.multi = int(number) * 2
                  self.str = str(number)
              
              new_object = new_class(2)                
              print(dir(new_object))                   #total list attributes of new_object
              attr_value = new_object.__dict__         
              print(attr_value)                        #Dictionary of attribute and value for new_class                   
              
              for attr in attr_value:                  #attributes on  new_class
                  print(attr)
              
              

              输出

              ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__','__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'multi', 'str']
              
              {'multi': 4, 'str': '2'}
              
              multi
              str
              

              【讨论】:

                【解决方案14】:

                如前所述,使用obj.__dict__ 可以处理常见情况,但某些类没有__dict__ 属性并使用__slots__(主要是为了提高内存效率)。

                一个更有弹性的方法示例:

                class A(object):
                    __slots__ = ('x', 'y', )
                    def __init__(self, x, y):
                        self.x = x
                        self.y = y
                
                
                class B(object):
                    def __init__(self, x, y):
                        self.x = x
                        self.y = y
                
                
                def get_object_attrs(obj):
                    try:
                        return obj.__dict__
                    except AttributeError:
                        return {attr: getattr(obj, attr) for attr in obj.__slots__}
                
                
                a = A(1,2)
                b = B(1,2)
                assert not hasattr(a, '__dict__')
                
                print(get_object_attrs(a))
                print(get_object_attrs(b))
                

                这段代码的输出:

                {'x': 1, 'y': 2}
                {'x': 1, 'y': 2}
                

                注意1:
                Python 是一种动态语言,最好了解您尝试从中获取属性的类,因为即使此代码也可能会遗漏某些情况。

                注意2:
                此代码仅输出实例变量,这意味着未提供类变量。例如:

                class A(object):
                    url = 'http://stackoverflow.com'
                    def __init__(self, path):
                        self.path = path
                
                print(A('/questions').__dict__)
                

                代码输出:

                {'path': '/questions'}
                

                此代码不会打印 url 类属性,并且可能会省略想要的类属性。
                有时我们可能认为一个属性是一个实例成员,但它不是,也不会在这个例子中显示出来。

                【讨论】:

                • 一个类可以有__dict__ __slots__,所以你可能想尝试两者而不仅仅是dict。
                【解决方案15】:
                • 使用__dict__vars 不起作用,因为它错过了__slots__
                • 使用__dict____slots__ 不起作用,因为它错过了基类中的__slots__
                • 使用dir不起作用,因为它包括类属性,例如方法或属性,以及对象属性。
                • 使用vars等同于使用__dict__

                这是我最好的:

                from typing import Dict
                
                def get_attrs( x : object ) -> Dict[str, object]:
                    mro      = type( x ).mro()
                    attrs    = { }
                    has_dict = False
                    sentinel = object()
                
                    for klass in mro:
                        for slot in getattr( klass, "__slots__", () ):
                            v = getattr( x, slot, sentinel )
                
                            if v is sentinel:
                                continue
                
                            if slot == "__dict__":
                                assert not has_dict, "Multiple __dicts__?"
                                attrs.update( v )
                                has_dict = True
                            else:
                                attrs[slot] = v
                
                    if not has_dict:
                        attrs.update( getattr( x, "__dict__", { } ) )
                
                    return attrs
                

                【讨论】:

                • 让我们把这个函数应用到一个简单的类中: class C: def __init__(self): print("created") i = 42 为什么你的代码为这样的类提供了空列表? (我的意思是如果 o = C() 则 get_attrs(o) 为空)它也适用于 get_attrs("mystr")
                • @ged 因为您的简单类不包含 instance 字段(根据问题),所以结果为空。我不确定我是否理解您希望看到的内容。
                【解决方案16】:

                请依次看下面的Python shell脚本执行,它会给出从创建类到提取实例字段名的解决方案。

                >>> class Details:
                ...       def __init__(self,name,age):
                ...           self.name=name
                ...           self.age =age
                ...       def show_details(self):
                ...           if self.name:
                ...              print "Name : ",self.name
                ...           else:
                ...              print "Name : ","_"
                ...           if self.age:
                ...              if self.age>0:
                ...                 print "Age  : ",self.age
                ...              else:
                ...                 print "Age can't be -ve"
                ...           else:
                ...              print "Age  : ","_"
                ... 
                >>> my_details = Details("Rishikesh",24)
                >>> 
                >>> print my_details
                <__main__.Details instance at 0x10e2e77e8>
                >>> 
                >>> print my_details.name
                Rishikesh
                >>> print my_details.age
                24
                >>> 
                >>> my_details.show_details()
                Name :  Rishikesh
                Age  :  24
                >>> 
                >>> person1 = Details("",34)
                >>> person1.name
                ''
                >>> person1.age
                34
                >>> person1.show_details
                <bound method Details.show_details of <__main__.Details instance at 0x10e2e7758>>
                >>> 
                >>> person1.show_details()
                Name :  _
                Age  :  34
                >>>
                >>> person2 = Details("Rob Pike",0)
                >>> person2.name
                'Rob Pike'
                >>> 
                >>> person2.age
                0
                >>> 
                >>> person2.show_details()
                Name :  Rob Pike
                Age  :  _
                >>> 
                >>> person3 = Details("Rob Pike",-45)
                >>> 
                >>> person3.name
                'Rob Pike'
                >>> 
                >>> person3.age
                -45
                >>> 
                >>> person3.show_details()
                Name :  Rob Pike
                Age can't be -ve
                >>>
                >>> person3.__dict__
                {'age': -45, 'name': 'Rob Pike'}
                >>>
                >>> person3.__dict__.keys()
                ['age', 'name']
                >>>
                >>> person3.__dict__.values()
                [-45, 'Rob Pike']
                >>>
                

                【讨论】:

                【解决方案17】:
                attributes_list = [attribute for attribute in dir(obj) if attribute[0].islower()]
                

                【讨论】:

                • 它不适用于以大写字母或单下划线开头的类属性名称。
                【解决方案18】:

                __attrs__ 给出实例的属性列表。

                >>> import requests
                >>> r=requests.get('http://www.google.com')
                >>> r.__attrs__
                ['_content', 'status_code', 'headers', 'url', 'history', 'encoding', 'reason', 'cookies', 'elapsed', 'request']
                >>> r.url
                'http://www.google.com/'
                >>>
                

                【讨论】:

                • 并不总是有效。此外,您在描述中写了__attr__,但在代码中使用了__attrs__。都不适合我(werkzeug.datastructures.FileStorage)
                猜你喜欢
                • 2017-03-31
                • 2016-09-09
                • 2019-02-04
                • 2012-09-29
                • 2012-11-11
                • 2022-01-24
                • 1970-01-01
                • 1970-01-01
                • 2011-09-12
                相关资源
                最近更新 更多