tags:

views:

119

answers:

6

Hi. I am new to Python so please don't flame me if I ask something too noobish :)

1.

Consider I have a class:

class Test:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def wow():
        print 5 * 5

Now I try to create an object of the class:

x = Test(3, 4)

This works as expected. However, when I try to call the method wow(), it returns an error, which is fixed by changing wow() to:

def wow(self)

Why do I need to include self and if I don't, what does the method mean?

2. In the definition of __init__:

def __init__(self, x, y):
   self.x = x
   self.y = y

Why do I need to declare x and y, when I can do this:

def __init__(self):
    self.x = x
    self.y = y

I hope I am being clear...

Thanks for your time.

A: 

The instance reference in Python is explicit. That way it can be manipulated by e.g. decorators before finally being passed to the method.

We need to declare x and y as arguments to the function so that we can use their names within the function, bound to the arguments passed in the corresponding function call.

Ignacio Vazquez-Abrams
Suppose if I have an attribute that I don't want to be instantiated immediately, is it ok if I do this: def __init__(self, x): try: self.y = foo // do something here except: if the condition is not met, don't create it
Andy
Sure, but it will have to be a global. And don't use a bare except.
Ignacio Vazquez-Abrams
Nothing in that makes `y` dependent on `x`...
Ignacio Vazquez-Abrams
I don't see any such conflict in the code you pasted. And don't shadow `file`.
Ignacio Vazquez-Abrams
So is the approach ok?
Andy
Of course. Python's dynamic nature means that symbol lookups aren't done until the code is actually executed.
Ignacio Vazquez-Abrams
Thanks for the help. I am gonna accept this.
Andy
A: 
  1. In Python, methods should always take "one extra" argument, which is the reference to the instance the method is being called on. This is automatic in other languages such as Java, C#, etc. but Python is verbose about it.

  2. That doesn't make sense. Where are x and y in that example? If you want the constructor to take two arguments which populate the object, define it as such. Otherwise, you're doing something else.

Deniz Dogan
A: 

Python is different from languages like C++ and Java in that the object instance reference is passed explicitly.

That is, if you have an object which is an instance of the class and you want to invoke a method that operates on that instance (e.g., reads its fields), you use the self references as the object.

In c++ and Java, you have an implicit "this" reference that is present in the compiled version of your program but not in the source code. You use the static keyword to make it into a class method that does not have a "this".

Uri
+1  A: 

Just to be clear

Why do I need to declare x and y, when I can do this:

def __init__(self):
    self.x = x
    self.y = y

This ^ will only work if x and y can be found at runtime - if they haven't been passed in then they must have been set elsewhere (globally) or it will generate an error.

>>> class c:
    def __init__(self):
        self.x = x

>>> x = 1
>>> q = c()
>>> q.x
1
>>> del x
>>> q.x
1
>>> w = c()

Traceback (most recent call last):
  File "<pyshell#24>", line 1, in <module>
    w = c()
  File "<pyshell#14>", line 3, in __init__
    self.x = x
NameError: global name 'x' is not defined
>>> 
>>> w = c(2)

Traceback (most recent call last):
  File "<pyshell#19>", line 1, in <module>
    w = c(2)
TypeError: __init__() takes exactly 1 argument (2 given)

This is why you want / need to specify them as parameters - it might work with the global lookup but it would probably violate the "principle of least astonishment"

pycruft
+3  A: 

If you do that :

def __init__(self):
  self.x = x
  self.y = y

you assign the gobal vars x and y (it they exists ) to your instance

with :

def __init__(self, x, y):
      self.x = x
      self.y = y

you assign what you give as parameter to the constructor

and that is a lot more flexible :-)

Blauohr
Thanks. Much clearer now.
Andy
+1  A: 

self is a "magic" name - it can really be anything, but self is used for consistency and clarity. To answer your question, each class method/function requires an explicit reference to the class as the first parameter. Using Ipython:

In [66]: class Test:
   ....:     def __init__(self):
   ....:         pass
   ....:     def wow(self):
   ....:         print self
   ....:
   ....:

In [67]: x = Test()

In [68]: x.wow()
<__main__.Test instance at 0x0159FDF0>

Your second example won't actually work unless you already have an x and y in your namespace.

For instance, if you defined your class:

class Test:
    def __init__(self):
        self.x = x
        self.y = y

and tried

x = Test()

it will throw a NameError.

However if you write:

x = 3
y = 4
test = Test()

then it will work. However, it's not a good idea to do such a thing. For the reason why read line 2:

In [72]: import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
Wayne Werner
Thanks for this answer :) Truly!
Andy
``self`` is most definitely not a magic name: it is quite simply a name adopted by convention.
krawyoti
"self" is not magic because of the letters it is comprised of, but because of where it appears. `</restate>`
Wayne Werner