Adding attributes stored in a list to a class dynamically.

  • Thread starter Nathan Harmston
  • Start date
N

Nathan Harmston

Hi,

Sorry if the subject line of post is wrong, but I think that is what
this is called. I want to create objects with

class Coconuts(object):
def __init__(self, a, b, *args, **kwargs):
self.a = a
self.b = b

def spam( l )
return Coconuts( l.a, l.b, l.attributes )

l in a parse line of a file which is a tuple wrapped with
attrcol......with attributes a, b and attributes (which is a list of
strings in the format key=value ie...
[ "id=bar", "test=1234", "doh=qwerty" ] ).

I want to add attributes to Coconuts so that I can do
print c.id, c.test, c.doh

HOwever I m not sure how to do this:

how can i assign args, kwargs within the constructor of coconuts and
how can I deconstruct the list to form the correct syntax to be able
to be used for args, kwargs.

HOpe this makes sense,

Thanks in advance,

Nathan
 
A

Alex Martelli

Nathan Harmston said:
Hi,

Sorry if the subject line of post is wrong, but I think that is what
this is called. I want to create objects with

class Coconuts(object):
def __init__(self, a, b, *args, **kwargs):
self.a = a
self.b = b

def spam( l )
return Coconuts( l.a, l.b, l.attributes )

l in a parse line of a file which is a tuple wrapped with
attrcol......with attributes a, b and attributes (which is a list of
strings in the format key=value ie...
[ "id=bar", "test=1234", "doh=qwerty" ] ).

I want to add attributes to Coconuts so that I can do
print c.id, c.test, c.doh

HOwever I m not sure how to do this:

how can i assign args, kwargs within the constructor of coconuts and
how can I deconstruct the list to form the correct syntax to be able
to be used for args, kwargs.

If you want to pass the attributes list it's simpler to do that
directly, avoiding *a and **k constructs. E.g.:

def __init__(self, a, b, attrs):
self.a = a
self.b = b
for attr in attrs:
name, value = attr.split('=')
setattr(self, name, value)

You may want to add some better error-handling (this code just raises
exceptions if any item in attrs has !=1 occurrences of the '=' sign,
etc, etc), but I hope this gives you the general idea.

Note that you'll have trouble accessing attributes that just happen to
be named like a Python keyword, e.g. if you have "yield=23" as one of
your attributes you will NOT be able to just say c.yield to get at that
attribute. Also, I'm assuming it's OK for all of these attributes'
values to be strings, etc, etc.


Alex
 
B

Brian Munroe

If you want to pass the attributes list it's simpler to do that
directly, avoiding *a and **k constructs. E.g.:

def __init__(self, a, b, attrs):
self.a = a
self.b = b
for attr in attrs:
name, value = attr.split('=')
setattr(self, name, value)

Alex:

Thanks for the example. I too had been wondering about this for a
while.

One question though, which I haven't been able to find the answer from
scouring the internet. What is the difference between calling
__setattr__ and setattr or __getattr__ and getattr, for that matter?
From my example that follows, it doesn't seem to make a difference?

thanks

-- brian

class Person(object):

def __init__(self):
pass

def newAttribute(self,name,value=None):
setattr(self,name, value)

def newAttribute2(self,name,value=None):
self.__setattr__(name, value)

def dump(self):
for self.y in self.__dict__.keys():
yield self.y + "=" + getattr(self,self.y)

p1 = Person()
p1.newAttribute('fname','Brian')
p1.newAttribute('lname','Munroe')
p1.newAttribute2("mi","E")

for x in p1.dump():
print x
 
S

Steven D'Aprano

One question though, which I haven't been able to find the answer from
scouring the internet. What is the difference between calling
__setattr__ and setattr or __getattr__ and getattr, for that matter?

Have you read the following?

# setattr, getattr, delattr:
http://www.python.org/doc/lib/built-in-funcs.html

# __setattr__ etc.
http://www.python.org/doc/ref/attribute-access.html

If there is anything unclear about the descriptions, please ask.

In a nutshell, like all double-underscore methods, __setattr__ are for
overriding behaviour in your own classes. With very few exceptions, you
shouldn't need to directly call double-underscore methods (although you
often may _write_ double-underscore methods).
 
B

Brian Munroe

In a nutshell, like all double-underscore methods, __setattr__ are for
overriding behaviour in your own classes. With very few exceptions, you
shouldn't need to directly call double-underscore methods (although you
often may _write_ double-underscore methods).

I think I understand. You are saying that if I wanted to override the
normal behavior when doing something like

p1.firstName = "Brian"

then I'd override __setattr__()?

But if I am doing something like creating dynamic attributes, the more
'correct' way is to use setattr? Even though they both appear to do
the same thing, the more Pythonic way is to never directly call magic
methods (if you can help it)?

thanks

-- brian
 
B

Bruno Desthuilliers

Brian Munroe a écrit :
I think I understand. You are saying that if I wanted to override the
normal behavior when doing something like

p1.firstName = "Brian"

then I'd override __setattr__()?

That's one possible solution. Another one is to use a property object or
a custom descriptor (you should find relevant documentation on python.org).
But if I am doing something like creating dynamic attributes, the more
'correct' way is to use setattr? Even though they both appear to do
the same thing, the more Pythonic way is to never directly call magic
methods (if you can help it)?

Mainly, yes.
 
S

Steven D'Aprano

I think I understand. You are saying that if I wanted to override the
normal behavior when doing something like

p1.firstName = "Brian"

then I'd override __setattr__()?

But if I am doing something like creating dynamic attributes, the more
'correct' way is to use setattr? Even though they both appear to do the
same thing, the more Pythonic way is to never directly call magic
methods (if you can help it)?


No, they don't do the same thing.

The normal way of accessing an object attribute is with the dot operator:

obj.name

Behind the scenes, Python does a whole lot of magic to make that work.
Under *normal* circumstances, when you write "obj.name" Python looks for
an attribute called "name", and returns whatever it finds. The *details*
of the lookup process itself can be as simple as "look in obj.__dict__"
or it can be significantly more complicated if obj has slots and super-
classes and properties. But don't worry about the complications, just
think of "look up an attribute" as a single operation for now.

What if you don't know the name of the attribute when you are writing
your code, but only at runtime? You want something like this:

s = "na" + "me" # We don't know this until runtime.
obj.s

but that doesn't work, because Python looks up an attribute called s.

That's where getattr(), setattr() and delattr() come into play: you can
give the name of the attribute as a string at runtime, not hard coded in
your source code: getattr(obj, s) evaluates s as the string "name", then
looks up the attribute called "name" just as if you had written obj.name.

Now, what about __getattr__ __setattr__ and __delattr__? They too take
the name of the attribute as a string, but that's about the only
similarity with the non-underscore versions. They exist for a completely
different reason.

The underscore versions are for customizing the lookup process, not for
dynamically looking up names. If your class needs to do something non-
standard when you write obj.name, you might need to write methods
__getattr__ etc.

Regardless of whether your attribute lookup was from obj.name or from
getattr(obj, "name"), when Python goes to do the actual lookup, it will
call on the double-underscore versions if needed:

if the __getattr__ method exists, it is ONLY called if the lookup fails;

if the __getattribute__ method exists, it is called for EVERY lookup;

if the __setattr__ method exists, it is called when you try to assign to
an attribute;

if the __delattr__ method exists, it is called when you try to delete an
attribute.


In a nutshell: getattr() etc. are for looking up attributes dynamically
when you don't know the name of the attribute until runtime. __getattr__
etc. are for looking up attributes when you need to compute the value on
the fly. (But an easier, less troublesome way of doing that is with
properties.)
 
B

Brian Munroe

The underscore versions are for customizing the lookup process, not for
dynamically looking up names. If your class needs to do something non-
standard when you write obj.name, you might need to write methods
__getattr__ etc.

I absolutely understand that much.
In a nutshell: getattr() etc. are for looking up attributes dynamically
when you don't know the name of the attribute until runtime. __getattr__
etc. are for looking up attributes when you need to compute the value on
the fly. (But an easier, less troublesome way of doing that
is with properties.)

If I think about this in the context of a property, which in my newbie
mind gives you the ability to 'override' the standard behavior when
getting, setting or I suppose deleting a specific attribute. I think
I understand what you meant by 'compute the value on the fly', the
keyword being *compute*?

thanks for taking the time to explain this (over and over, heh!)

-- brian
 

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
473,774
Messages
2,569,596
Members
45,135
Latest member
VeronaShap
Top