开发者

List attributes of an object [duplicate]

开发者 https://www.devze.com 2022-12-28 00:57 出处:网络
This question already has answers here: Is there a built-in function to print all the current properties and values of an object?
This question already has answers here: Is there a built-in function to print all the current properties and values of an object? (30 answers) Closed last year.

Is there a way to grab a list of attributes that exist on instances of a class?

class new_class():
    def 开发者_如何学Go__init__(self, number):
        self.multi = int(number) * 2
        self.str = str(number)

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

The desired result is that "multi, str" will be output. I want this to see the current attributes from various parts of a script.


>>> 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'])

You may also find pprint helpful.


dir(instance)
# or (same value)
instance.__dir__()
# or
instance.__dict__

Then you can test what type is with type() or if is a method with callable().


All previous answers are correct, you have three options for what you are asking

  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(obj) returns the attributes of an object.


Inspect module:

The inspect module provides several useful functions to help get information about live objects such as modules, classes, methods, functions, tracebacks, frame objects, and code objects.


Using getmembers() you can see all attributes of your class, along with their value. To exclude private or protected attributes use .startswith('_'). To exclude methods or functions use inspect.ismethod() or 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


inst = NewClass(2)

for i in inspect.getmembers(inst):
    # 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)

Note that ismethod() is used on the second element of i since the first is simply a string (its name).

Offtopic: Use CamelCase for class names.


>>> ', '.join(i for i in dir(a) if not i.startswith('__'))
'multi, str'

This of course will print any methods or attributes in the class definition. You can exclude "private" methods by changing i.startwith('__') to i.startwith('_')


You can use dir(your_object) to get the attributes and getattr(your_object, your_object_attr) to get the values

usage :

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

This is particularly useful if your object have no __dict__. If that is not the case you can try var(your_object) also


It's often mentioned that to list a complete list of attributes you should use dir(). Note however that contrary to popular belief dir() does not bring out all attributes. For example you might notice that __name__ might be missing from a class's dir() listing even though you can access it from the class itself. From the doc on dir() (Python 2, Python 3):

Because dir() is supplied primarily as a convenience for use at an interactive prompt, it tries to supply an interesting set of names more than it tries to supply a rigorously or consistently defined set of names, and its detailed behavior may change across releases. For example, metaclass attributes are not in the result list when the argument is a class.

A function like the following tends to be more complete, although there's no guarantee of completeness since the list returned by dir() can be affected by many factors including implementing the __dir__() method, or customizing __getattr__() or __getattribute__() on the class or one of its parents. See provided links for more details.

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


There is more than one way to do it:

#! /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) )

When run, this code produces:

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$


What do you want this for? It may be hard to get you the best answer without knowing your exact intent.

  • It is almost always better to do this manually if you want to display an instance of your class in a specific way. This will include exactly what you want and not include what you don't want, and the order will be predictable.

    If you are looking for a way to display the content of a class, manually format the attributes you care about and provide this as the __str__ or __repr__ method for your class.

  • If you want to learn about what methods and such exist for an object to understand how it works, use help. help(a) will show you a formatted output about the object's class based on its docstrings.

  • dir exists for programatically getting all the attributes of an object. (Accessing __dict__ does something I would group as the same but that I wouldn't use myself.) However, this may not include things you want and it may include things you do not want. It is unreliable and people think they want it a lot more often than they do.

  • On a somewhat orthogonal note, there is very little support for Python 3 at the current time. If you are interested in writing real software you are going to want third-party stuff like numpy, lxml, Twisted, PIL, or any number of web frameworks that do not yet support Python 3 and do not have plans to any time too soon. The differences between 2.6 and the 3.x branch are small, but the difference in library support is huge.


Please see the python shell script which has been executed in sequence, here you will get the attributes of a class in string format separated by comma.

>>> 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/>

I am using python 3.4


In addition to these answers, I'll include a function (python 3) for spewing out virtually the entire structure of any value. It uses dir to establish the full list of property names, then uses getattr with each name. It displays the type of every member of the value, and when possible also displays the entire member:

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

Now any of the following should give insight:

get_info(None)
get_info('hello')

import numpy
get_info(numpy)
# ... etc.


Get attributes of an object

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)

Output

['__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


As written before using obj.__dict__ can handle common cases but some classes do not have the __dict__ attribute and use __slots__ (mostly for memory efficiency).

example for a more resilient way of doing this:

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))

this code's output:

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

Note1:
Python is a dynamic language and it is always better knowing the classes you trying to get the attributes from as even this code can miss some cases.

Note2:
this code outputs only instance variables meaning class variables are not provided. for example:

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

print(A('/questions').__dict__)

code outputs:

{'path': '/questions'}

This code does not print the url class attribute and might omit wanted class attributes.
Sometimes we might think an attribute is an instance member but it is not and won't be shown using this example.


  • Using __dict__ or vars does not work because it misses out __slots__.
  • Using __dict__ and __slots__ does not work because it misses out __slots__ from base classes.
  • Using dir does not work because it includes class attributes, such as methods or properties, as well as the object attributes.
  • Using vars is equivalent to using __dict__.

This is the best I have:

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


Please see the following Python shell scripting execution in sequence, it will give the solution from creation of class to extracting the field names of instances.

>>> 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']
>>>


attributes_list = [attribute for attribute in dir(obj) if attribute[0].islower()]


__attrs__ gives the list of attributes of an instance.

>>> 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/'
>>>
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号