tags:

views:

733

answers:

6

Why can't I perform an action like the following:

class Test(object):
    def __init__(self):
        self = 5

t = Test()
print t

I would expect it to print 5 since we're overwriting the instance with it, but instead it doesn't do anything at all. Doesn't even throw an error. Just ignores the assignment.

I understand that there would be hardly any situations where one would want to do that, but it still seems odd that you can't.

Update: I now understand why it doesn't work, but I'd still like to know if there is any way of replacing an instance from within the instance.

+1  A: 

Dr. Egon Spengler: It would be bad.
Dr. Peter Venkman: I'm fuzzy on the whole good/bad thing. What do you mean, "bad"?
Dr. Egon Spengler: Try to imagine all life as you know it stopping instantaneously and every molecule in your body exploding at the speed of light.

anthony
It wouldn't be *that* bad. It's a known idiom in Smalltalk, for example, and Smalltalk programmers don't routinely have every molecules in their body explode at the speed of light... I think *grin*.
itowlson
oh, i thought that's why there weren't many of them left.
anthony
Right. That's bad. Okay. All right. Important safety tip. Thanks, anthony.
Cal Jacobson
This reminds me of the dangers of using `GOTO` http://xkcd.com/292/
voyager
+27  A: 

Any simple assignment to any argument of any function behaves exactly the same way in Python: binds that name to a different value, and does nothing else whatsoever. "No special case is special enough to break the rules", as the Zen of Python says!-)

So, far from it being odd (that simply=assigning to a specific argument in a specific function has no externally visible effect whatsoever), it would be utterly astonishing if this specific case worked in any other way, just because of the names of the function and argument in question.

Should you ever want to make a class that constructs an object of a different type than itself, such behavior is of course quite possible -- but it's obtained by overriding the special method __new__, not __init__:

class Test(object):
    def __new__(cls):
        return 5

t = Test()
print t

This does emit 5. The __new__ / __init__ behavior in Python is an example of the "two-step construction" design pattern: the "constructor" proper is __new__ (it builds and returns a (normally uninitialized) object (normally a new one of the type/class in question); __init__ is the "initializer" which properly initializes the new object.

This allows, for example, the construction of objects that are immutable once constructed: in this case everything must be done in __new__, before the immutable object is constructed, since, given that the object is immutable, __init__ cannot mutate it in order to initialize it.

Alex Martelli
Ah, makes sense. Do you know how I'd accomplish what I intended to, by any chance?
Evan Fosmark
already edited the answer to explain: with __new__, the "constructor proper", not with __init__, the "initializer".
Alex Martelli
+3  A: 

It doesnt "ignore" the assignment. The assignment works just fine, you created a local name that points to the data 5.

If you really want to do what you are doing...

class Test(object):
    def __new__(*args):
        return 5
truppo
Good idea! Seems to work, too: http://codepad.org/8sgInhvO
Greg Hewgill
Indeed. But the real task at hand is to replace the instance from within the instance, and this really doesn't do that.
Evan Fosmark
+1  A: 

I just ran a quick test, and you can assign to self. Inside your init() method, print out the value of self. You'll see that it's 5.

What you're missing here is that parameters are passed by value in Python. So, changing the value of a variable in a function or method won't change it for the outside world.

All that being said, I would strongly advise against ever changing self.

Clint Miller
I would agree that changing self is a terrible idea. BUT it would still be nice to know if there is any way of replacing an instance from within the instance.
Evan Fosmark
A: 

Sometimes you want to do this, though not with immutable types like int:

>>> class Test(list):
    ... def __init__(self):
    ...    list.__init__(self, [1,2,3])   # self = [1,2,3] seems right, but isn't

>> t = Test()
>> print t
[1, 2, 3]
scrible
A: 
class Test(object):
    def __init__(self):
        self = 5

t = Test()
print t

is like having this PHP (only other lang i know, sorry)

class Test {
    function __construct() {
            $this = 5;
        }
}

I don't see how it makes sense. replacing the instance with a value?

lyrae
How does it not make sense? It would be the same as doing: $test = new Test(); $test = 5;But from within instead of outside.
Evan Fosmark