[Baypiggies] A properties and obj.__dict__ question

Mark Voorhies mvoorhie at yahoo.com
Fri Sep 9 06:18:44 CEST 2011


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 


More information about the Baypiggies mailing list