5

我知道关于这个主题已经写了很多。但是,我无法吸收其中的大部分内容。也许是因为我是一个完全的新手,在没有任何计算机科学培训的情况下自学。无论如何,也许如果你们中的一些有头脑的人在这个特定的例子中加入进来,你会帮助像我这样的其他初学者。

因此,我编写了以下函数,当我调用它(作为一个模块?)时它工作得很好,因为它是一个名为“funky.py”的文件:

我在终端中输入以下内容:

python classy.py

它运行良好。

def load_deck():
    suite = ('Spades', 'Hearts')
    rank = ('2', '3')
    full_deck = {}
    i = 0
    for s in suite:
        for r in rank:
            full_deck[i] = "%s of %s" % (r, s)
            i += 1
    return full_deck

print load_deck()

但是,当我将相同的函数放在一个类中时,我得到了一个错误。

这是我的“classy.py”代码:

class GAME():
    def load_deck():
        suite = ('Spades', 'Hearts')
        rank = ('2', '3')
        full_deck = {}
        i = 0
        for s in suite:
            for r in rank:
                full_deck[i] = "%s of %s" % (r, s)
                i += 1
        return full_deck
MyGame = GAME()
print MyGame.load_deck()

我收到以下错误:

Traceback (most recent call last):
File "classy.py", line 15, in <module>
print MyGame.load_deck()
TypeError: load_deck() takes no arguments (1 given)

因此,我将定义行更改为以下内容,它工作正常:

def load_deck(self):

将函数放在需要使用“自我”的类中是什么意思。我知道“自我”只是一个约定。那么,为什么需要任何论证呢?当从类中调用函数时,它们的行为是否不同?

另外,这几乎更重要,为什么我的课程没有使用init的好处?使用init会为我的班级做什么?

基本上,如果有人有时间像我 6 岁一样向我解释这一点,那会有所帮助。提前感谢您的帮助。

4

3 回答 3

4

在类定义中定义一个函数会调用一些将其转换为方法描述符的魔法。当您访问 foo.method 时,它将自动创建一个绑定方法并将对象实例作为第一个参数传递。您可以通过使用 @staticmethod 装饰器来避免这种情况。

__init__只是在创建类以进行可选设置时调用的方法。__new__是实际创建对象的内容。

这里有些例子

>>> class Foo(object):
    def bar(*args, **kwargs):
        print args, kwargs

>>> foo = Foo()
>>> foo.bar
<bound method Foo.bar of <__main__.Foo object at 0x01C9FEB0>>
>>> Foo.bar
<unbound method Foo.bar>
>>> foo.bar()
(<__main__.Foo object at 0x01C9FEB0>,) {}
>>> Foo.bar()

Traceback (most recent call last):
  File "<pyshell#29>", line 1, in <module>
    Foo.bar()
TypeError: unbound method bar() must be called with Foo instance as first argument (got nothing instead)
>>> Foo.bar(foo)
(<__main__.Foo object at 0x01C9FEB0>,) {}
于 2012-08-06T23:46:14.790 回答
1

那么,为什么需要任何论证呢?

访问类的当前实例的属性。

假设您有一个具有两种方法的类,load_deck并且shuffle. 最后load_deck你想洗牌(通过调用shuffle方法)

在 Python 中,你会做这样的事情:

class Game(object):
    def shuffle(self, deck):
        return random.shuffle(deck)

    def load_deck(self):
        # ...

        return self.shuffle(full_deck)

将此与大致等效的 C++ 代码进行比较:

class Game {
    shuffle(deck) {
        return random.shuffle(deck);
    }
    load_deck() {
        // ...

        return shuffle(full_deck)
    }
}

在线shuffle(full_deck)上,首先它查找一个名为的局部变量shuffle- this 不存在,然后它检查更高级别,并找到一个名为的实例方法shuffle(如果它不存在,它将检查全局变量正确的名字)

这没关系,但不清楚shuffle是指某个局部变量还是实例方法。为了解决这种歧义,实例方法或实例属性也可以通过以下方式访问this

...
load_deck() {
    // ...

    return this->shuffle(full_deck)
}

this几乎与 Python 的 self 相同,只是它没有作为参数传递。

为什么有用self的论点是有用的?FAQ 列出了几个很好的理由——这些可以用“Python 之禅”中的一句话来概括:

Explicit is better than implicit.

这得到了Python 历史博客中的一篇文章的支持,

我决定放弃隐式引用实例变量的想法。像 C++ 这样的语言允许您编写 this->foo 来显式引用实例变量 foo(以防有单独的局部变量 foo)。因此,我决定让这种显式引用成为引用实例变量的唯一方法。此外,我决定与其将当前对象(“t​​his”)设为特殊关键字,不如简单地将“this”(或其等价物)设为方法的第一个命名参数。实例变量总是作为该参数的属性被引用。

使用显式引用,不需要为方法定义使用特殊的语法,也不必担心与变量查找有关的复杂语义。相反,人们只是简单地定义一个函数,它的第一个参数对应于实例,按照惯例,它被命名为“self”。

于 2012-08-07T00:26:55.553 回答
0

如果您不打算使用self您可能应该将该方法声明为staticmethod

class Game:
    @staticmethod
    def load_deck():
        ....

这取消了自动默认打包,该打包通常将范围内的函数转换为以实例作为参数的方法。

传递你不使用的参数会让其他试图阅读你的代码的人感到不安。

大多数班级都有成员。你的没有,所以它的所有方法都应该是静态的。随着项目的发展,您可能会发现其中的所有函数都应该可以访问的数据,然后将它们放入self中,并将其传递给所有函数。

在这种情况下,应用程序本身是您的主要对象,__init__只是初始化所有这些共享值的函数。

这是迈向面向对象风格的第一步,其中较小的数据片段本身被用作对象。但这是从直接脚本转向 OO 编程的正常阶段。

于 2014-08-31T23:30:01.153 回答