Best practise implementation for equal by value objects

Steven D'Aprano steven at REMOVE.THIS.cybersource.com.au
Fri Aug 8 06:25:43 EDT 2008


On Fri, 08 Aug 2008 00:28:02 -0700, Slaunger wrote:

> OK, i am encouraged to carry on my quest with the eval(repr)) for my
> 'nice' classes.
> I just revisited the documentation for eval and noticed that there are
> optional globals
> and locals name space variables, that one could specify:
> 
> http://docs.python.org/lib/built-in-funcs.html
> 
> Quite frankly I do not understand how to make use of these parameters,
> but it is my feeling
> that if I enforce a convention of always specifying the globals/locals
> parameter in a specific
> manner:
> assert eval(repr(x), globals, locals) == x would work independent of how
> I have imported the module under test.
> 
> Now, I just need to figure out if this is right and how to specify the
> globals and locals if that is not too cumbersome... or maybe I am just
> over-engineering...


I think it is infeasible for the repr() of an object to know where it was 
imported from. Including the globals and locals in the call to eval() 
won't help you, because they can have changed between the time you 
created the instance and the time you call repr(). Consider:


>>> import datetime
>>> x = datetime.time(20, 21, 22)
>>> x
datetime.time(20, 21, 22)
>>> eval(repr(x)) == x
True

So far so good! But now watch this, starting in a fresh session:

>>> import datetime as timedate
>>> t = timedate.time
>>> timedate.tttime = timedate.time
>>> del timedate.time
>>> assert t is timedate.tttime
>>> 
>>> x1 = t(20, 21, 22)
>>> x2 = timedate.tttime(20, 21, 22)
>>> assert x1 == x2

What should repr(x1) and repr(x2) be, for your invariant eval(repr(x))==x 
to hold?

It gets better (or worse):

>>> alist = [None, t, None]
>>> del t, timedate
>>> x3 = alist[1](20, 21, 22)
>>> assert x1 == x2 == x3

What should the repr() of x1, x2, x3 be now?


Bringing this back to the unittests... as I see it, there's an easy way 
to solve your problem. In the unittest, just do something like the 
following:

# repr(x) looks like "module.class(arg)", 
# but we actually import it as package.module.submodule.class
module = package.module.submodule
assert eval(repr(x)) == x

I think that is all you need to do.


-- 
Steven



More information about the Python-list mailing list