Variable interpolation with getattr

Jp Calderone exarkun at intarweb.us
Wed Feb 19 12:35:56 EST 2003


On Wed, Feb 19, 2003 at 07:32:49AM -0800, Rich wrote:
> Andrew,
> 
>    This looks interesting, but doesn't work for me inside the class,
> such as within the constructor which can be use for initialization.  I
> think the post from Alex Martelli may have the key with __slots__ and
> setattr, but this stuff isn't covered in detail in my "Learning
> Python" book.
> 
> Thanks,
> Rich
> 
>    class C:
>      self.attr = ['city','state','zip']
>      def __init__(address)
>        for a in self.attr:
>          self.a = address[a]
>              ^^          
> 

   Ahhhhh but it *does*, you see.  Except, not with the code you have above
(since it doesn't work at all ;).


    class C:
        attr = ['city', 'state', 'zip']

        def __init__(self, address):
            for a in self.attr:
                setattr(self, a, address[a])


  So, what's changed?  Well, "self.attr" became "attr" in one place. 
Notice that "self" is not some magic word - it's just an identifier,
sometimes it is bound, sometimes not.  In the block that "class C:" starts,
it is *not* bound, so trying to set an attribute on it is going to fail. 
Simply binding the name "attr" works great though, and in fact any names
bound in this scope will eventually become attributes of the class C. 
Notice the symmetry!  "def" binds a name to a function object, so "def
__init__" does nothing more magical than make "__init__" an attribute of the
class C!

  The __init__ method has also had a parameter added to it - "self".  This
is require of *all* instance methods (There are a couple other kinds of
methods, don't worry about them for now).  When a bound instance method is
called, for example:

    s = 'hello, WoRld.'
    s.capitalize()

  Python turns the second line, very roughly, into:

    s.__class__.capitalize(s)

  So you can see that "self" will always be the object itself.  Any other
arguments are passed after the object parameter.  This works the same way
for __init__.  When a new instance of C is created, *that instance* is
passed to the __init__ method, followed by any other arguments passed.

    addrDict = {'city': 'Springfield', 'state': 'XX', 'zip': 12345}
    address = C(addrDict)

  The newly created C instance is passed in to C.__init__ - not the
implication, __init__ is not a constructor, only an initializer (there is a
constructor method, but you can also ignore it safely for a while yet).

  Last trick, what's with that "self.attr" in the for loop in C.__init__? 
Well, self has no attr attribute, so the lookup fails.  However, when a
lookup on an instance object fails, that lookup proceeds to the object's
class object, in this case class C.  Remember when we defined "attr" on
class C?  Now that attribute is found and used for the loop.  This is the
same way method lookup works (all attribute lookups, really).  String
instances have no method "capitalize" on them, but their type, "str", does
(try it - dir('a string') vs dir(str) or dir(types.StringType) after you
import types).

  Hope this helps clear things up.

  Jp

-- 
"Pascal is Pascal is Pascal is dog meat."
                -- M. Devine and P. Larson, Computer Science 340
-- 
 up 10 days, 22:28, 2 users, load average: 0.00, 0.00, 0.00
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 196 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/python-list/attachments/20030219/13735d9b/attachment.sig>


More information about the Python-list mailing list