Discover instance variables

J

JonathanB

Ok, I know there has to be a way to do this, but my google-fu fails me
(once more). I have a class with instance variables (or should they be
called attributes, I'm newish to programming and get really confused
with OO sometimes), like the one in this example:

class Foo():
self.a = "bar"
self.z = "test"
self.var = 2

foo = Foo()

I want to print a list of the variables (strings, integers, etc) in
Foo, without knowing their names. So that the user who needs to change
a peice of information can view the variable list, enter the name of
the variable they need to change and then make the change. This is
what I'd like a sample run to look like:

Attributes for foo:
a = bar
z = test
var = 2

Change: a
New value: foobar
Change made!

I can handle the formatting and changing the variable itself, no
problem, but how do I get a list of all the variables in a class
instance? I almost put a list in there called vars and appended all
the variables to it so I could iterate the list, but this sounds like
something useful enough that someone has come up with a better way to
do it than that. It almost looks like self.__dir__() is what I want,
but that returns methods as well, correct? I only want variables, but
I can't think of how to do a list comprehension that would remove the
methods.

JonathanB
 
B

Bjoern Schliessmann

JonathanB said:
Ok, I know there has to be a way to do this, but my google-fu
fails me (once more). I have a class with instance variables (or
should they be called attributes, I'm newish to programming and
get really confused with OO sometimes),

To complete confusion, those terms vary with languages :)
like the one in this example:

class Foo():
self.a = "bar"
self.z = "test"
self.var = 2

This will not work. Please use working code for examples.
I can handle the formatting and changing the variable itself, no
problem, but how do I get a list of all the variables in a class
instance? I almost put a list in there called vars and appended
all the variables to it so I could iterate the list, but this
sounds like something useful enough that someone has come up with
a better way to do it than that.

I'd use exactly this, since there may be attributes you don't want
to be changed from outside (perhaps __class__).
It almost looks like self.__dir__() is what I want, but that
returns methods as well, correct? I only want variables, but I
can't think of how to do a list comprehension that would remove
the methods.

That's quite a problem with your concept. There are no variables and
methods. There are only attributes. Attributes may be objects. Some
objects may be callable (like function objects).

If you know exactly what you want to be accessible like this, you
could filter __dir__() output with name/callable/isinstance tests.

Regards,


Björn
 
G

Gabriel Genellina

Ok, I know there has to be a way to do this, but my google-fu fails me
(once more). I have a class with instance variables (or should they be
called attributes, I'm newish to programming and get really confused
with OO sometimes), like the one in this example:

class Foo():
self.a = "bar"
self.z = "test"
self.var = 2

foo = Foo()

I want to print a list of the variables (strings, integers, etc) in
Foo, without knowing their names. So that the user who needs to change
a peice of information can view the variable list, enter the name of
the variable they need to change and then make the change. This is

You should define more precisely *which* attributes do you actually want
in the list, but I think this may serve as a starting point:

py> def get_attributes(obj):
.... return [attr for attr in dir(obj) if not attr.startswith('_') and
.... type(getattr(obj,attr)) in (
.... int,str,unicode,float,dict,list,tuple)]
....
py> f=open("c:\\test.py")
py> get_attributes(f)
['mode', 'name', 'softspace']

The list keeps only the types explicitely enumerated. Other types are
excluded, as well as names starting with "_". Another criterion would be
`not attr.startswith('_') and not callable(getattr(obj,attr))`
 
S

Steve Holden

JonathanB said:
Ok, I know there has to be a way to do this, but my google-fu fails me
(once more). I have a class with instance variables (or should they be
called attributes, I'm newish to programming and get really confused
with OO sometimes), like the one in this example:
Instance variable are indeed attributes, but you are doing fine with the
language so don't worry about it.
class Foo():
self.a = "bar"
self.z = "test"
self.var = 2
That's unlikely to work, though: the code is in the context of the
class, not one of its methods, so unless you happen to be declaring a
class inside another class's method it's unlikely that there's going to
be a "self" around when those three lines execute.

What you probably want is something like what follows (I am running it
interactively so I know I am telling the truth: it keeps me honest :).
You should get used to using the interpreter to check your hypotheses -
it would have told you you were making a mistake above as soon as you
tried to create a Foo.
.... a = "bar"
.... z = "test"
.... var = 2
....

You can check that Foo (the class) has these attributes:
'bar'

foo = Foo()
Now foo is an instance of the Foo class. Class attributes can also be
accessed through instances:

Binding an instance attribute, however, doesn't change the class, so you
can use class attributes as a kind of "default" for instance.
I want to print a list of the variables (strings, integers, etc) in
Foo, without knowing their names. So that the user who needs to change
a peice of information can view the variable list, enter the name of
the variable they need to change and then make the change. This is
what I'd like a sample run to look like:

Attributes for foo:
a = bar
z = test
var = 2

Change: a
New value: foobar
Change made!

I can handle the formatting and changing the variable itself, no
problem, but how do I get a list of all the variables in a class
instance? I almost put a list in there called vars and appended all
the variables to it so I could iterate the list, but this sounds like
something useful enough that someone has come up with a better way to
do it than that. It almost looks like self.__dir__() is what I want,
but that returns methods as well, correct? I only want variables, but
I can't think of how to do a list comprehension that would remove the
methods.
[name for name in dir(x) if not callable(name) and not
name.startswith("__")]

might come close - I presume you don't want __doc__ and the like.

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC/Ltd http://www.holdenweb.com
Skype: holdenweb http://del.icio.us/steve.holden
--------------- Asciimercial ------------------
Get on the web: Blog, lens and tag the Internet
Many services currently offer free registration
----------- Thank You for Reading -------------
 
J

JonathanB

That's unlikely to work, though: the code is in the context of the
class, not one of its methods, so unless you happen to be declaring a
class inside another class's method it's unlikely that there's going to
be a "self" around when those three lines execute.

Ah, I see. Trouble is I write most of my code on a computer that
doesn't have python (shared computer and I don't have permissions to
install). So I code it here, email it to myself, and test it at home.
I had my debugged code at home so I couldn't post a working example.
Here's working example.

class World():
def __init__(self, name, WTN, Ag, Na, Ex, In, Ni, Al, Port, Type,
Dia, Grav, Atmosphere, Hyd, Climate, Pop, Gov, CR, TL, Wealth,
Trade=None, notes=None):
self.name = name
self.WTN = WTN
self.Ag = Ag
self.Na = Na
self.Ex = Ex
self.In = In
self.Ni = Ni
self.Al = Al
self.Port = Port
self.Trade = Trade
self.Type = Type
self.Dia = Dia
self.Grav = Grav
self.Atmosphere = Atmosphere
self.Hyd = Hyd
self.Climate = Climate
self.Pop = Pop
self.Gov = Gov
self.CR = CR
self.TL = TL
self.Wealth = Wealth
self.notes = notes

The code to execute this is:

def world_info():
# code to prompt for each variable
world = World(name, WTN, Ag, Na, Ex, In, Ni, Al, Port, Type, Dia,
Grav, Atmosphere, Hyd, Climate, Pop, Gov, CR, TL, Wealth)

So given that example, is there a clean way to get this output:

Data for Earth:
Name = Earth
WTN = 5.0
Ag = 0
Na = 0
....
....
Notes = None
[name for name in dir(x) if not callable(name) and not
name.startswith("__")]

That does looks almost exactly like what I want I think (I'm still
learning to read code to learn what it does, but from what it looks
like this does a list comprehension that removes everything callable
and that starts with "__")
[name for name in dir(x) if not callable(name) and not
name.startswith("__")]

might come close - I presume you don't want __doc__ and the like.
 
L

Lawrence Oluyede

Gabriel Genellina said:
The list keeps only the types explicitely enumerated. Other types are
excluded, as well as names starting with "_". Another criterion would be
`not attr.startswith('_') and not callable(getattr(obj,attr))`

Why not:

In [1]: class Foo(object):
...: a = 3
...:
...:

In [2]: import inspect

In [4]: inspect.getmembers(Foo())
Out[4]:
[('__class__', <class '__main__.Foo'>),
('__delattr__', <method-wrapper '__delattr__' of Foo object at
0x12bf350>),
('__dict__', {}),
('__doc__', None),
('__getattribute__',
<method-wrapper '__getattribute__' of Foo object at 0x12bf350>),
('__hash__', <method-wrapper '__hash__' of Foo object at 0x12bf350>),
('__init__', <method-wrapper '__init__' of Foo object at 0x12bf350>),
('__module__', '__main__'),
('__new__', <built-in method __new__ of type object at 0x307860>),
('__reduce__', <built-in method __reduce__ of Foo object at
0x12bf350>),
('__reduce_ex__', <built-in method __reduce_ex__ of Foo object at
0x12bf350>),
('__repr__', <method-wrapper '__repr__' of Foo object at 0x12bf350>),
('__setattr__', <method-wrapper '__setattr__' of Foo object at
0x12bf350>),
('__str__', <method-wrapper '__str__' of Foo object at 0x12bf350>),
('__weakref__', None),
('a', 3)]

and then filter out __xyz__ methods?
 
D

Dave Baum

JonathanB said:
I can handle the formatting and changing the variable itself, no
problem, but how do I get a list of all the variables in a class
instance? I almost put a list in there called vars and appended all
the variables to it so I could iterate the list, but this sounds like
something useful enough that someone has come up with a better way to
do it than that. It almost looks like self.__dir__() is what I want,
but that returns methods as well, correct? I only want variables, but
I can't think of how to do a list comprehension that would remove the
methods.

For simple cases, the object's __dict__ will probably give you what you
want. By default, that's where an object's instance variables are
stored, and you can just examine the keys, etc:

class Foo(object):
def __init__(self):
self.a = "bar"
self.z = "test"
self.var = 2

foo = Foo()
print foo.__dict__

-> {'a': 'bar', 'var': 2, 'z': 'test'}

However, there are lots of ways to bypass using the __dict__ to hold
attributes. If the class uses any of these techniques, __dict__ either
will not exist or may not be complete. A few of the techniques that
come to mind are:

* custom __getattr__/__setattr__ methods (or __getattribute__ in a new
style class)

* descriptors (http://docs.python.org/ref/descriptors.html)

* using __slots__ in a new style class


Dave
 
B

Bjoern Schliessmann

JonathanB said:
So given that example, is there a clean way to get this output:

Data for Earth:
Name = Earth
WTN = 5.0
Ag = 0
Na = 0
...
...
Notes = None

Sure, save the __init__ parameters explicitly in a dict.

self.data = {"Name": name,
"WTN": WTN,
"Ag": Ag,
...
}

To display them, you can iterate through the dict:

print "Data for Earth:"
for field, content in self.data.items():
print "%s = %r" % field, content

Hope that helps.

Regards,


Björn
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,430
Messages
2,571,676
Members
48,796
Latest member
Greg L.

Latest Threads

Top