[Edu-sig] Fw: Python sequences by reference - how to make clear

Kirby Urner urnerk@qwest.net
Thu, 19 Sep 2002 15:53:26 -0700


If copy and deepcopy *were* to be incorporated into the built-in domain,
perhaps where they'd logically appear is as methods in the new base
class (object).

   >>> newobj = object()
   >>> dir(newobj)
   ['__class__', '__delattr__', '__doc__', '__getattribute__', '__hash__',
   '__init__', '__new__', '__reduce__', '__repr__', '__setattr__',
   '__str__']

In this hypothetical future, the above list would have included __copy__
and __deepcopy__ as well (except I'm not sure we need the underlines).

Then the syntax would imitate hash(), which also appears as a builtin:

   >>> hash(newobj)
   10746256
   >>> newobj.__hash__()
   10746256

Note:  I'm aware that builtin functions don't always invoke object
methods.  For example id() doesn't trigger an __id__ method (probably
because Python needs to control this directly -- can't have users
messing with it by overriding it).  However, in the case of hash, it
does seem to trigger whatever has been defined for that object, as
show by this experiement:

   >>> class Myobj(object):
   	  def __hash__(self):
	      return 42
	
   >>> obj = Myobj()
   >>> hash(obj)
   42
   >>> id(obj)   # no __id__ method
   30306080

copy(obj) would work this same way, by triggering obj's __copy__ method.

So then, when wanting a copy of a list, say, you could just go:

   >>> a = [1,2,3,4]
   >>> b = copy(a)    # invokes a.copy() (or a.__copy__() ?)

   >>> c = a
   >>> c[2]=5
   >>> a        # <---- is is the kind of thing that confuses newbies
   [1, 2, 5, 4]

instead of:

   >>> import copy       # <--- makes copying more remote than hashing
   >>> a = [1,2,3,4]
   >>> b = copy.copy(a)

But of course, currently a user needn't import copy in order to copy
a list:

   >>> a = [1,2,3]
   >>> b = a[:]       # this works -- but is syntax specific to lists

When we use dictionaries, we find something interesting:

   >>> a = {'a':1,'b':2}
   >>> dir(a)
   ['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__',
   '__doc__', '__eq__', '__ge__', '__getattribute__', '__getitem__', '__gt__',
   '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', 
'__ne__',
   '__new__', '__reduce__', '__repr__', '__setattr__', '__setitem__', 
'__str__',
   'clear', 'copy', 'get', 'has_key', 'items', 'iteritems', 'iterkeys',
   'itervalues', 'keys', 'popitem', 'setdefault', 'update', 'values']

A copy method appears in the list of methods which dictionaries natively
support.  However, this doesn't mean you can use copy(a) the way you'd
go hash(a).  You have to go b = a.copy().  But were this new feature
implemented, copy(a) would make sense, without importing the copy module.

To summarize, one way of implementing Arthur's suggestion would be to
move copy and deepcopy to the top of the class hierarchy, and to have
the builtin copy(obj) invoke whatever's been defined inside obj's class
definition.

I don't think this model is too far-fetched by the way.  Doesn't Java
define the clonable interface as part of the base class, or somewhere
high up in the hierarchy?

That foundation objects should know how to copy themselves (either
shallowly or deeply) seems a pretty intrinsic ability that it wouldn't
hurt to have, or at least think about having.

Kirby