Best practise implementation for equal by value objects

Terry Reedy tjreedy at udel.edu
Wed Aug 6 21:36:06 CEST 2008



Slaunger wrote:
> Hi,
> 
> I am new here and relatively new to Python, so be gentle:
> 
> Is there a recommended generic implementation of __repr__ for objects
> equal by value to assure that eval(repr(x)) == x independet of which
> module the call is made from?

The CPython implementation gives up on that goal and simply prints 
<modname.classname object at address> for at least two reasons ;-).

1. In general, it require fairly sophisticated analysis of __init__ to 
decide what representation of what attributes to include and decide if 
the goal is even possible.  If an attribute is an instance of a user 
class, then *its* __init__ needs to be analyzed.  If an attribute is a 
module, class, or function, there is no generic evaluable representation.

2. Whether eval(repr(x)) even works (returns an answer) depends on 
whether the name bindings in the globals and locals passed to eval 
(which by default are the globals and locals of the context of the eval 
call) match the names used in the repr.  You discovered that to a first 
approximation, this depends on whether the call to repr comes from 
within or without the module containing the class definition.  But the 
situation is far worse.  Consider 'import somemod as m'.  Even if you 
were able to introspect the call and determine that it did not come from 
somemod**, prepending 'somemod.' to the repr *still* would not work. 
Or, the call to repr could come from one context, the result saved and 
passed to another context with different name bindings, and the eval 
call made there.  So an repr that can be eval'ed in any context is hopeless.

If this is a practical rather than theoretical question, then use your 
first repr version that uses the classes definition name and only eval 
the result in a context that has that name bound to the class object.

from mymod import Age
#or
import mymod
Age = mymod.Age

#in either case
eval(repr(Age(10))) == Age(10)

> class Age:
> 
>     def __init__(self, an_age):
>         self.age = an_age
> 
>     def __eq__(self, obj):
>         self.age == obj.age
> 
>     def __repr__(self):
>         return self.__class__.__name__ + \
>                "(%r)" % self.age
**
While such introspection is not part of the language, I believe one 
could do it in CPython, but I forgot the details.  There have been 
threads like 'How do I determine the caller function' with answers to 
that question, and I presume the module of the caller is available also.

Terry Jan Reedy




More information about the Python-list mailing list