我有一个类“Duck”和“Dog”,如下所示:
class Duck:
def quack(self):
print("quack")
class Dog:
def bark(self):
print("I just bark")
以两种方式定义了另一个类并启动:
case:1
class ItQuacks:
def __init__(self, animal):
**animal.quack()**
如果我将其启动为
ItQuacks(Duck)
,则不会打印任何事物。我期待着“嘎嘎”被打印出来。而
ItQuacks(Duck())
打印“quack”。
case:2
class ItQuacks:
def __init__(self, animal):
**animal.quack(self)**
但是如果我将其启动为
ItQuacks(Duck)
,它会按预期打印“quack”
我可以知道
Duck()
默认情况下是否有 self 。有人可以解释一下这个概念吗?
当然,让我们分解一下 Python 代码中的类方法和实例化。
核心概念
- 类: 类就像蓝图,它定义了对象(如 Duck 和 Dog)的结构和行为。它们本身并不是对象。
-
实例:
实例是根据类蓝图创建的实际对象。例如,
Duck()
创建了一个 Duck 类的实例。 -
self
:self
是实例方法中的一个特殊参数,它指的是该方法所属的实例。它不是由你直接传递的,而是在你调用实例方法时由 Python 自动传递。
对你的代码的解释
-
案例 1:
ItQuacks(Duck)
vs.ItQuacks(Duck())
-
ItQuacks(Duck)
:这里,你将类Duck
本身传递给了ItQuacks
构造函数。你没有创建Duck
的实例。由于你没有Duck
的实例,因此没有可供animal.quack()
操作的对象,因此没有任何内容被打印出来。 -
ItQuacks(Duck())
:在这种情况下,Duck()
创建了一个Duck
的新实例。这个实例被传递给ItQuacks
的构造函数。在ItQuacks
的__init__
中,animal.quack()
现在指的是Duck
实例上的quack
方法,因此 "嘎嘎" 被打印出来。 -
案例 2:
animal.quack(self)
-
此代码不正确,并且如果在
ItQuacks
类中像这样使用,则会引发错误。Duck
类中的quack
方法定义为:python def quack(self): print("quack")
-
它只需要
self
参数(由 Python 自动提供)。通过调用animal.quack(self)
,你试图传递一个额外的参数,这会导致错误。
简而言之
-
要使用
quack
方法等实例方法,你需要一个Duck
的实例(例如,Duck()
)。 -
self
由 Python 在实例方法中处理。你不必也不应该在调用实例方法时明确地传递它。
改进后的代码
要使
ItQuacks
类更加健壮,你可以修改它以接受一个
animal
实例,并检查它是否具有
quack
方法:
class ItQuacks:
def __init__(self, animal):
if hasattr(animal, 'quack'):
animal.quack()
else:
print("This animal can't quack!")
my_duck = Duck()
it_quacks = ItQuacks(my_duck) # 这将打印 "嘎嘎"
这确保了仅当传入的对象实际具有
quack
方法时,才会调用该方法,从而防止了潜在的错误。