[Baypiggies] A properties and obj.__dict__ question

Mark Voorhies mvoorhie at yahoo.com
Fri Sep 9 06:23:19 CEST 2011


On Thursday, September 08, 2011 09:18:44 pm Mark Voorhies wrote:
> On Thursday, September 08, 2011 08:51:05 pm Glen Jarvis wrote:
> > I have a question that is hard to ask without involving code. I reduced my
> > project down to a tiny test case (as follows).
> > 
> > As you see, the following code will work and access the variables within the
> > class successfully. However, it's a cheat, using the internal attributes
> > instead of the properties (as properties don't show in __dict__).
> > 
> > The objective is to have a large string with different fields. The fields
> > happen to all be members of my class.  So, I could hard code things like
> > this:
> > 
> > message = """
> >     Name: %s
> >     Address: %s
> >     %s, %s  %s
> >  """ % {obj.name, obj.address, obj.city, obj.state, obj.postal_code}
> > 
> > But, as each of the items are properties of the class, I'd like to be more
> > dynamic, like this:
> > 
> > message = """
> >     Name: %(obj.name)s
> >     Address: %(obj.address)s
> >     %(obj.city)s, %(obj.state)s  %(obj.postal_code)s
> >  """ % obj
> > 
> > I can do this with normal attributes, like the following:
> > 
> > message = """
> >     Name: %(name)s
> >     Address: %(address)s
> >     %(city)s, %(state)s  %(postal_code)s
> >  """ % obj.__dict__
> > 
> > However, these attributes in my case are properties and don't show in the
> > __dict__.
> > 
> > Here's a runnable piece of code to demonstrate:
> > 
> > 
> > =-=-=-=-=-=-=-  Start of Working Code -=-=-=-=-=-=-=-=-=-
> > class Piggie(object):
> >     def __init__(self):
> >         """A demo for a BayPIGgies question"""
> >         self._name = None
> >         self._address = None
> > 
> >     @property
> >     def name(self):
> >         return self._name
> > 
> >     @name.setter
> >     def name(self, value):
> >         if isinstance(value, basestring):
> >             value = value.strip()
> >         self._name = value
> > 
> >     @property
> >     def address(self):
> >         return self._address
> > 
> >     @address.setter
> >     def address(self, value):
> >         if isinstance(value, basestring):
> >             value = value.strip()
> >         self._address = value
> > 
> >     def __unicode__(self):
> >         if self.name is None:
> >             return u"Nameless Person"
> >         else:
> >             return self.name
> >     __str__ = __unicode__
> > 
> > 
> > f = Piggie()
> > f.name = 'Glen'
> > 
> > 
> > message = """
> >     Obviously, this is silly for only two fields like this.
> > 
> >     But, it's a very reduced test case to demo a problem from a
> >     much larger project.
> > 
> >     Name: %(_name)s
> >     Address:  %(_address)s
> >  """ %  f.__dict__
> > 
> > print message
> > =-=-=-=-=-=-=-  Start of Working Code -=-=-=-=-=-=-=-=-=-
> > 
> > 
> > This works, as the output below shows. However, only by accessing the
> > internal attributes of the class directly, not using the property accessors.
> > How can I do something like this, but with property accessors. Something
> > like dir(f) or f.__property_dict__ that just has the properties.
> > 
> > Run:
> > 
> > 
> >     Obviously, this is silly for only two fields like this.
> > 
> >     But, it's a very reduced test case to demo a problem from a
> >     much larger project.
> > 
> >     Name: Glen
> >     Address:  None
> > 
> > 
> > 
> > Run with the properties used:
> > 
> > Traceback (most recent call last):
> >   File "x.py", line 48, in <module>
> >     """ %  f.__dict__
> > KeyError: 'name'
> > 
> > 
> > Thanks, for letting me share :)
> > 
> > 
> > 
> > Glen
> > 
> 
> What about:
> 
> message = """
>      Name: %(obj.name)s
>      Address: %(obj.address)s
>      %(obj.city)s, %(obj.state)s  %(obj.postal_code)s
>   """ % dict((i,getattr(obj,i)) for i in dir(obj))
> 
> ?
> 
> (obviously, this is dangerous if any attribute of obj has side effects)
> 
> If this is a string to be modified at run time, would it be reasonable
> to just use eval or have the client supply an importable module?
> (i.e., if you want dynamic behavior, can you take advantage of the
>  fact that Python is already a dynamic language?)
> 
> --Mark 
> 

oops -- that code snippet should have been:
 message = """
      Name: %(name)s
      Address: %(address)s
      %(city)s, %(state)s  %(postal_code)s
   """ % dict((i,getattr(obj,i)) for i in dir(obj))

--Mark


More information about the Baypiggies mailing list