Copy constructors
Roeland Rengelink
r.b.rigilink at chello.nl
Mon Aug 13 02:44:51 EDT 2001
Guido van Rossum wrote:
>
> Roeland Rengelink <r.b.rigilink at chello.nl> writes:
>
> > One idiom where I use __class__ assignment is the following
> >
> > 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
>
> But you can easily do this differently -- e.g. you could do a method
> assignment, or you could represent the state by an object.
>
Sure, and if...else worked fine too ;)
I have only two arguments for using this solution, in favor of the
others. First, I think class assignment expresses the intent of the code
rather elegantly. Second, --and this is an even weaker argument-- it was
the most efficient solution in my particular application. (speed-wise
when compared with if..else or method-dispatch to a state-object,
memory-wise when compared to method assignments to all instances)
I am, of course, not qualified to make the trade-off between these
benefits, and the cost of making class-assignment available.
> > Speaking of __new__. Would it be an idea to give __new__() the
> > responsibility for calling __init__ on the new instance.
>
> I have thought about this. It would be less flexible, so I think not.
> For example, with the current set-up you can use __new__ to create an
> uninitialized instance, bypassing __init__. If __new__ called
> __init__, you couldn't do that.
>
I didn't mean to let object.__new__ call the init, which indeed looses
flexibility
What I did mean is the following change to type_call. I Have no idea
what side effects
I may have missed here, but it does exactly what I want.
staticforward PyObject *
slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
static PyObject *
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *obj;
if (type->tp_new == NULL) {
PyErr_Format(PyExc_TypeError,
"cannot create '%.100s' instances",
type->tp_name);
return NULL;
}
obj = type->tp_new(type, args, NULL);
if (obj != NULL) {
type = obj->ob_type;
/* if the user defines his own __new__,
let him call __init_ explicitly */
if (type->tp_new != slot_tp_new){
if (type->tp_init != NULL &&
type->tp_init(obj, args, kwds) < 0) {
Py_DECREF(obj);
obj = NULL;
}
}
}
return obj;
}
Usage:
class A(object):
def __new__(object_type, *args, **kwargs):
new_inst = object.__new__(object_type)
new_inst.__init__(*args, **kwargs)
return new_inst
def new(object_type):
return object.__new__(object_type)
new = classmethod(new)
def __init__(self, *args, **kwargs):
print 'Hi...'
>>> a = A()
Hi
>>> b = A.new()
>>> a
<A object at 0x81807b8>
>>> b
<A object at 0x817dd60>
>>> type(a)
<type 'A'>
>>> type(b)
<type 'A'>
I.e. the programmer can define __new__, to determine what happens with
A(), and define A.new() to give bare instances. A gain in flexibility (I
think)
Cheers,
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