我知道关于这个问题已经写了很多。但是,我不能吸收其中的大部分内容。也许是因为我是一个完整的新手,在没有任何计算机科学培训的情况下自学。无论如何,如果你们中的一些大脑在这个具体的例子中引用,你会帮助像我这样的其他初学者。
所以,我编写了以下函数,当我调用它(作为模块?)时,它的工作正常,因为它的文件名为'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):
将函数放在需要使用“self”的类中是什么意思?我明白'自我'只是一种惯例。那么,为什么需要任何论证呢?当函数从类中调用时,函数的行为会不同吗?
此外,这几乎更重要,为什么我的班级没有使用 init 的好处?使用 init 为我的班级做什么?
基本上,如果有人有时间向我解释,就像我6岁,这会有所帮助。提前感谢您的帮助。
答案 0 :(得分:3)
在类定义中定义一个函数会调用一些魔法,将其转换为方法描述符。当您访问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>,) {}
答案 1 :(得分: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
的局部变量 - 这不存在,接下来检查更高一级,并找到一个名为{{1}的实例方法(如果这不存在,它将检查具有正确名称的全局变量)
这没关系,但是不清楚shuffle
是否引用了某个局部变量或实例方法。为了解决这种歧义,还可以通过shuffle
:
this
...
load_deck() {
// ...
return this->shuffle(full_deck)
}
几乎与Python的自身完全相同,除了它不作为参数传递。
为什么将this
作为参数有用是否有用? The FAQ lists several good reasons - 这些可以通过"The Zen of Python"中的一行汇总:
self
中的帖子支持的
我决定放弃对实例变量的隐式引用的想法。像C ++这样的语言允许你编写this-&gt; foo来显式引用实例变量foo(如果有一个单独的局部变量foo)。因此,我决定将这种显式引用作为引用实例变量的唯一方法。另外,我决定不将当前对象(“this”)作为特殊关键字,而是简单地将“this”(或其等价物)作为方法的第一个命名参数。实例变量将始终作为该参数的属性引用。
使用显式引用,不需要为方法定义提供特殊语法,也不必担心有关变量查找的复杂语义。相反,只需定义一个函数,其第一个参数对应于实例,按惯例,该实例名为“self”。
答案 2 :(得分:0)
如果您不打算使用 self ,则应该将该方法声明为 staticmethod 。
class Game:
@staticmethod
def load_deck():
....
这会撤消自动默认打包,通常会将类范围内的函数转换为以实例作为参数的方法。
传递您不会使用的参数会让那些试图阅读您的代码的人感到不安。
大多数班级都有会员。你没有,所以它的所有方法都应该是静态的。随着项目的开发,您可能会发现其中所有功能都可以访问的数据,您可以将这些数据放入 self 中,并将其传递给所有这些数据。
在此上下文中,应用程序本身是您的主要对象, __ init __ 只是初始化所有这些共享值的函数。
这是面向对象风格的第一步,其中较小的数据片段被用作对象本身。但这是从直接编写脚本到OO编程的正常阶段。