0

I just want to ask if I can assign an instance of a class to itself in a method.

For example, is the following valid python code?

class O(object):
  def __init__(self,value):
    self.value = value
  def do_something(self):
    self = O(1)

Does this lead to any unexpected behaviour?

Obviously, the code can be run. But when I do

A = O(2)
A.do_something()
A.value 

the output is 2, when I expect it to be 1.

Martijn Pieters
  • 889,049
  • 245
  • 3,507
  • 2,997
Dschoni
  • 3,192
  • 3
  • 34
  • 61

3 Answers3

3

self is just another local variable. You can assign something else to it just like you can assign something to any variable. To begin with, self points to the same object A points to in your example.

When you then execute self = O(1), that statement rebinds the name self. It was previously referencing an instance of O(), and now you point it to another, different instance of O(). Those two objects are otherwise independent, doing this doesn't make anything else happen. A still references the first instance, self now references a different one.

So assigning O(2) to self doesn't do anything to the previous object that self pointed to. It certainly won't alter the value of the value attribute of that previous object. A still points to the first instance, where the value attribute is pointing to the integer 2.

You may want to read this article on Python names, by Ned Batchelder: Facts and myths about Python names and values, which lays out what happens when you assign something to a Python variable. self is nothing special here.

Martijn Pieters
  • 889,049
  • 245
  • 3,507
  • 2,997
  • So short answer: I'm rebinding self to a new instance locally. So returning the inner self would lead to the desired effect but also returning a new instance. – Dschoni Oct 10 '16 at 16:21
  • 1
    @Dschoni: yes, and that would only then rebind `A` if you assign the return value of `do_something` back to that name: `A = A.do_something()`. Any *other references* would not follow suit. So `B = A`, then `A = A.do_something()` would leave `B` still referencing the first instance. – Martijn Pieters Oct 10 '16 at 16:22
  • Perfect. No I can go back to my original, more complex question without feeling stupid. Thanks! – Dschoni Oct 10 '16 at 16:30
0

As Marcin answered, it is feasible, but it is not an advisable pattern.

Why would you like to do something like that? If you'd like instances of your class to have a settable property after instantiation, you shouldn't do it with a constructor. A simple solution for your proposal:

class O(object):
  def __init__(self,value):
    self.value = value
  def do_something(self):
    self.value = 1

There would be alternative options depending on your intentions. Perhaps a default value?

class O(object):
  def __init__(self,value):
    self.value = value
  def do_something(self, value=1):
    self.value = value

o = O(2)
// o.value == 2
o.do_something()
// o.value == 1

I think the key here is: Try to be explicit instead of smart. It may look to you that the solution you're looking for is clever, but nothing beats clarity when you're coding.

Caio Tomazelli
  • 453
  • 5
  • 12
-1

self is a local variable. So, it will make your code confusing in that method, and will prevent modifications on (or calls to) the original self object.

Marcin
  • 44,601
  • 17
  • 110
  • 191