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