Copy constructors
Roeland Rengelink
r.b.rigilink at chello.nl
Sun Aug 12 03:30:11 EDT 2001
Guido van Rossum wrote:
>
> Glyph Lefkowitz <glyph at twistedmatrix.com> writes:
>
> > Am I correct in understanding from this thread that there is an intent to
> > remove the ability to assign an instance's __class__ attribute?
>
> Yes, I'd like to remove this. See my previous post in this thread for
> more of an explanation of the problem. But I haven't decided yet!
> This thread will help me figure out how big of a deal it will be.
>
One idiom where I use __class__ assignment is the following
class State:
def __init__(self):
self.state = 1
def do_something(self):
if self.state:
...do something...
else:
...do something else...
def change_state(self):
if self.state:
self.state = 0
else:
self.state = 1
refactor:
class State1:
def do_something(self):
...do something...
def change_state(self):
self.__class__ = State2
class State2:
def do_something(self):
...do something else...
def change_state(self):
self.__class__ = State1
Now, I can't imagine wanting to use this with something like:
class State1(list):
...
class State2(dict):
...
But I can imagine wanting to use this with:
class State1(object):
class State2(object):
I could imagine one of several restrictions on assignment to __class__,
all based on comparing the object that is currently assigned to
__class__
(old) with the one that is going to replace it (new).
1. Make it illegal to assign to class if either old or new defines a
__slots__
attribute
2. Make it illegal to assign to class if old.__slots__ != new.__slots__
3. Make it illegal to assign to class if old.__bases__ != new.__bases__
[snip]
>
> If you know the type it's going to be eventually, you can use
> C.__new__() to create an uninitialized C instance.
>
Speaking of __new__. Would it be an idea to give __new__() the
responsibility
for calling __init__ on the new instance. Now we have:
class Singleton(object):
_instances = {}
def __new__(object_type, *args, **kwargs):
return Singleton._instances.setdefault(object_type,
object.__new__(object_type))
class A(Singleton):
def __init__(self):
print 'A.__init__', self
a, b = A(), A()
giving:
A.__init__ <A object at 0x810f6b0>
A.__init__ <A object at 0x810f6b0>
While I would have loved to be able to do (and it was I mild surprise
that I couldn't):
class Singleton(object):
_instances = {}
def __new__(object_type, *args, **kwargs):
if object_type in Singleton._instances:
return Singleton._instances[object_type]
new_instance = object.__new__(object_type)
try:
new_instance.__init__(*args, **kwargs)
except AttributeError:
pass
return new_instance
With object.__new__ defined something like:
class object:
def __new__(cls, *args, **kwargs):
if cls.__new__ == object.__new__:
# if I have responsibility I'll call __init__
new_instance = create_new_instance(cls)
new_instance.__init__(*args, **kwargs) # but catch AttrErr
else:
# If you have your own new, you take responsibility
new_instance = create_new_instance(cls)
return new_instance
and the instantiation process only calling cls.__new__()
BTW, I managed to build a Singleton class, using metaclasses, that gave
me the right behaviour. This process has become slightly less painfull
in 2.2, but only slightly ;)
The Singleton pattern is a rather trivial example of course. I think one
of things I'm looking for here is the ability to fold functionality,
that I would traditionally put in factory functions, into a base class.
__new__ seems to be ideally suited for that, but I would need to have
control over calling __init__ too. Having said that, being able to play
these tricks with metaclasses, is fun too. In a perverse sort of way...
Anyway,
Thanks for another set of great improvements to Python
Groeten,
Roeland
--
r.b.rigilink at chello.nl
"Half of what I say is nonsense. Unfortunately I don't know which half"
More information about the Python-list
mailing list