How to get instance variables in Python?
Asked Answered
G

12

155

Is there a built-in method in Python to get an array of all a class' instance variables? For example, if I have this code:

class hi:
  def __init__(self):
    self.ii = "foo"
    self.kk = "bar"

Is there a way for me to do this:

>>> mystery_method(hi)
["ii", "kk"]

Edit: I originally had asked for class variables erroneously.

Grube answered 20/9, 2008 at 19:30 Comment(1)
Your example shows "instance variables". Class variables are another thing.Elum
U
194

Every object has a __dict__ variable containing all the variables and its values in it.

Try this

>>> hi_obj = hi()
>>> hi_obj.__dict__.keys()

Output

dict_keys(['ii', 'kk'])
Uraemia answered 20/9, 2008 at 19:34 Comment(9)
FWIW, the inspect module gives you a more reliable method than relying on dict, which not all instances have.Hieronymus
What kind of an instance does not have dict? I've never encountered one.Cocky
Certain built-in types, such as int. Try saying "x = 5" and then "x.__dict__" and you'll get an AttributeErrorCrus
Also, anything that uses slots.Hieronymus
Why would you want to try and get the class instance variables of an int? It's not even a class (although I could be wrong on that).Renvoi
Also re.MatchObjects ( no __dict__s )Veinule
@MartinSherburn Because someone may want to get instances' variables within knowing in advance what types will be encountered.Lammers
What does the example output look like for this code?Dachau
Also numpy ndarrays return an AttributeError when you try to access their attributes using __dict__Extinguish
C
131

Use vars()

class Foo(object):
    def __init__(self):
        self.a = 1
        self.b = 2

vars(Foo()) #==> {'a': 1, 'b': 2}
vars(Foo()).keys() #==> ['a', 'b']
Cartierbresson answered 20/9, 2008 at 20:2 Comment(5)
+1 I personally think this syntax is cleaner than using dict, since attributes with double underscores are supposed to be "private" in Python syntax.Isleen
@Martin: __method is private, __method__ is a special method, not necessarily private; I would like to say the special methods define an object's capabilites rather than methods.Overcast
__method__ is quite ugly, and I think they have been named that way to try and deter people away from using them unless absolutely necessary. In this case we have the alternative vars().Renvoi
in my case I tried calling vars(ObjName) and it returns a dict_proxy with a dictionary whose keys are the methods of the given class/object, but no sign of init elements. Any guesses why?Gogol
Double Underscore Variables __str__, __method__ are for the language itself normally. What happens when you str(something)?Gaona
H
19

You normally can't get instance attributes given just a class, at least not without instantiating the class. You can get instance attributes given an instance, though, or class attributes given a class. See the 'inspect' module. You can't get a list of instance attributes because instances really can have anything as attribute, and -- as in your example -- the normal way to create them is to just assign to them in the __init__ method.

An exception is if your class uses slots, which is a fixed list of attributes that the class allows instances to have. Slots are explained in http://www.python.org/2.2.3/descrintro.html, but there are various pitfalls with slots; they affect memory layout, so multiple inheritance may be problematic, and inheritance in general has to take slots into account, too.

Hieronymus answered 20/9, 2008 at 19:38 Comment(4)
Downvoting because "you can't get a list of instance attributes" is simply wrong: both vars() and dict give you exactly that.Cocky
I assume he meant "you can't get a list of all possible instance attributes". For example, I often use lazy generation and the @property decorator to add an instance variable the first time it's requested. Using dict would tell you about this variable once it existed but not beforehand.Crus
I didn't downvote, and please notice what I actually said: you can't get a list of instance attributes given just a class, which is what the code accompanying the question tries to do.Hieronymus
@Carl: Please educate yourself before writing false comments and downvoting based your lack of knowledge.Tycoon
S
16

You can also test if an object has a specific variable with:

>>> hi_obj = hi()
>>> hasattr(hi_obj, "some attribute")
False
>>> hasattr(hi_obj, "ii")
True
>>> hasattr(hi_obj, "kk")
True
Spectrometer answered 20/9, 2008 at 19:39 Comment(0)
T
16

Both the Vars() and dict methods will work for the example the OP posted, but they won't work for "loosely" defined objects like:

class foo:
  a = 'foo'
  b = 'bar'

To print all non-callable attributes, you can use the following function:

def printVars(object):
    for i in [v for v in dir(object) if not callable(getattr(object,v))]:
        print '\n%s:' % i
        exec('print object.%s\n\n') % i
Touchandgo answered 23/12, 2010 at 21:50 Comment(1)
exec('print object.%s\n\n') % i should be written as print getattr(object, i)Research
E
9

Your example shows "instance variables", not really class variables.

Look in hi_obj.__class__.__dict__.items() for the class variables, along with other other class members like member functions and the containing module.

class Hi( object ):
    class_var = ( 23, 'skidoo' ) # class variable
    def __init__( self ):
        self.ii = "foo" # instance variable
        self.jj = "bar"

Class variables are shared by all instances of the class.

Elum answered 20/9, 2008 at 19:42 Comment(1)
list(filter(None,[ i[0] if not i[0].startswith('_') else None for i in h.__class__.__dict__.items()])) essentiallyUxmal
S
6

Suggest

>>> print vars.__doc__
vars([object]) -> dictionary

Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.

In otherwords, it essentially just wraps __dict__

Spectrometer answered 20/9, 2008 at 20:12 Comment(0)
D
5

Although not directly an answer to the OP question, there is a pretty sweet way of finding out what variables are in scope in a function. take a look at this code:

>>> def f(x, y):
    z = x**2 + y**2
    sqrt_z = z**.5
    return sqrt_z

>>> f.func_code.co_varnames
('x', 'y', 'z', 'sqrt_z')
>>> 

The func_code attribute has all kinds of interesting things in it. It allows you todo some cool stuff. Here is an example of how I have have used this:

def exec_command(self, cmd, msg, sig):

    def message(msg):
        a = self.link.process(self.link.recieved_message(msg))
        self.exec_command(*a)

    def error(msg):
        self.printer.printInfo(msg)

    def set_usrlist(msg):
        self.client.connected_users = msg

    def chatmessage(msg):
        self.printer.printInfo(msg)

    if not locals().has_key(cmd): return
    cmd = locals()[cmd]

    try:
        if 'sig' in cmd.func_code.co_varnames and \
                       'msg' in cmd.func_code.co_varnames: 
            cmd(msg, sig)
        elif 'msg' in cmd.func_code.co_varnames: 
            cmd(msg)
        else:
            cmd()
    except Exception, e:
        print '\n-----------ERROR-----------'
        print 'error: ', e
        print 'Error proccessing: ', cmd.__name__
        print 'Message: ', msg
        print 'Sig: ', sig
        print '-----------ERROR-----------\n'
Depot answered 21/9, 2008 at 19:46 Comment(0)
T
4

Sometimes you want to filter the list based on public/private vars. E.g.

def pub_vars(self):
    """Gives the variable names of our instance we want to expose
    """
    return [k for k in vars(self) if not k.startswith('_')]
Telestich answered 26/4, 2020 at 9:11 Comment(0)
R
2

built on dmark's answer to get the following, which is useful if you want the equiv of sprintf and hopefully will help someone...

def sprint(object):
    result = ''
    for i in [v for v in dir(object) if not callable(getattr(object, v)) and v[0] != '_']:
        result += '\n%s:' % i + str(getattr(object, i, ''))
    return result
Rakia answered 5/7, 2019 at 6:42 Comment(0)
V
0

You will need to first, examine the class, next, examine the bytecode for functions, then, copy the bytecode, and finally, use the __code__.co_varnames. This is tricky because some classes create their methods using constructors like those in the types module. I will provide code for it on GitHub.

Vulpecula answered 23/12, 2020 at 16:23 Comment(0)
T
0

Based on answer of Ethan Joffe

def print_inspect(obj):
  print(f"{type(obj)}\n")
  var_names = [attr for attr in dir(obj) if not callable(getattr(obj, attr)) and not attr.startswith("__")]
  for v in var_names: 
    print(f"\tself.{v} = {getattr(obj, v)}\n")

Trehala answered 31/3, 2022 at 8:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.