开发者

Beginner questions regarding Python classes

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
开发者_如何学C

I hope I am being clear...

Thanks for your time.


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 :-)


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.


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"


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!


  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.


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".

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜