我是一个Python新手,试图理解继承方法背后的哲学/逻辑。问题最终会考虑为什么以及何时必须在子类中使用__init__
方法。例如:
似乎从超类继承的子类不需要自己的构造函数(__init__
)方法。下面,狗继承了哺乳动物的属性(名称,年龄)和方法(makenoise)。你甚至可以添加一个方法(do_a_trick
)似乎所有东西都是“应该”的。
但是,如果我想在Cats类中尝试在子类中添加新属性,则会收到错误,指出“self”未定义。然而我在狗类的定义中使用了“自我”。差异的本质是什么?
它似乎定义了Cats,因为我希望我需要使用__init__(self,name)
和super()__init__(name)
。为什么不同?
class Mammals(object):
def __init__(self,name):
self.name = name
print("I am a new-born "+ self.name)
self.age = 0
def makenoise(self):
print(self.name + " says Hello")
class Dogs(Mammals):
def do_a_trick(self):
print(self.name + " can roll over")
class Cats(Mammals):
self.furry = "True" #results in error `self' is not defined
mymammal = Mammals("zebra") #output "I am a new-born zebra"
mymammal.makenoise() #output "zebra says hello"
print(mymmmal.age) #output 0
mydog = Dogs("family pet") #output "I am a new-born family pet"
mydog.makenoise() #output "family pet says hello"
print(mydog.age) # output 0
mydog.do_a_trick() #output "family pet can roll over"
答案 0 :(得分:3)
但是,你可以在下面做:
DictWriter.writerow()
或
class Dogs(Mammals):
def __init__(self):
#add new attribute
self.someattribute = 'value'
Mammals.__init__(self)
答案 1 :(得分:2)
如果我想在子类中添加一个新属性,就像我尝试的那样 在Cats类中,我收到错误说" self"没有定义。然而,我 用过" self"在狗类的定义中。
在您的超类Mammal中,您有一个__init__
函数,它会使用您已选择的参数*来调用self
。当你在__init__
函数的主体中时,这个参数就在范围内 - 它是一个局部变量,就像任何局部变量一样,并且在它包含之后它不可能引用它功能终止。
Dog类do_a_trick
上定义的函数也接受一个名为self
的参数,它也是该函数的本地参数。
这些变量的特殊之处不在于它们的名称(你可以将它们称为任何你想要的东西),但事实上,作为python中实例方法的第一个参数,它们获得了对它们被称为它们的对象的引用。值。 (再次阅读最后一句话,这是理解这一点的关键,你可能第一次没有得到它。)
现在,在Cat
中,您有一行根本不在函数中的代码。此时没有任何内容,包括self
,这就是失败的原因。如果要在Cat
中定义一个带有self
参数的函数,则可以引用该参数。如果该参数碰巧是Cat
上实例方法的第一个参数,那么它将具有调用它的Cat
实例的值。否则,它将传递给它的任何东西。
*你明智地选择了!
答案 2 :(得分:2)
Python类顶层的声明成为类属性。如果您来自C ++或Java背景,这类似于声明静态成员变量。您无法在该级别分配实例属性。
变量self
通常是指类的特定实例,即从中调用该方法的类。当使用语法inst.method()
进行方法调用时,函数的第一个参数是调用该方法的对象inst
。在您的情况下,通常按照惯例,该参数在方法的函数体中命名为self
。您可以认为self
只是方法体中的有效标识符。您的作业self.furry = True
不会在某个方法中发生,因此我们不会在那里定义。
您基本上有两种方法可以实现您的目标。第一种是将furry
正确定义为cat类的属性:
class Cat(Mammals):
furry = True
# Rest of Cat implementation ...
或者您可以在cat构造函数中设置实例变量furry
的值:
class Cat(Mammals):
def __init__(self):
super(Mammals, self).__init__(self)
self.furry = True
# Rest of Cat implementation ...
如果您正在使用Python,我强烈建议您阅读Python文档的这两部分:
答案 3 :(得分:1)
你可以通过启动构造函数方法中的所有变量来完成Chankey的答案,例如a = 11111, length = 5
但是你也可以做这样的事情
__init__
然后
class Cats(Mammals):
furry = "True"
您无法在函数外使用cat = Cats("Tom")
cat.furry # Returns "True"
的原因是因为self
仅显式用于类的实例。如果你在外面使用它,会导致歧义。如果我的答案不清楚,请在评论中告诉我。
答案 4 :(得分:1)
__init__
方法在创建类的实例时运行一次。因此,如果您想在实例创建时设置属性,那就是您执行此操作的位置。 self
是一个特殊的关键字,它作为第一个参数传递给每个方法,它引用实例本身。 __init__
与此方面的其他方法没有什么不同。
"差异的本质是什么":您定义方法Dog.do_a_trick
,并且像往常一样接收self
作为方法的参数。但是在Cat
中,您无意中(可能是下意识地!)尝试在类范围内工作 - 这就是您设置类属性的方式,其值相同对于所有的猫:
class Cat(object):
sound = "meow"
它有所不同,因此您可以同时使用这两个选项。有时(不是所有的时间,但偶尔),类属性是一个有用的东西。所有的猫都有相同的声音。但是大多数时候你会使用实例属性 - 不同的猫有不同的名字;如果需要,请使用__init__
。
答案 5 :(得分:1)
假设您有一个名为Person
的类,其名为get_name
的方法定义为:
class Person():
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
def get_name(self):
return self.first_name + ' ' + self.last_name
并且,您将Person
的实例创建为p1
。现在,当您使用此实例调用函数get_name()
时,它将在内部转换
Person.get_name(p1)
所以,自我就是实例本身。
如果没有self
,您可以将上面的代码写为:
class Person():
first_name = None
last_name = None
def get_name(personobject):
return personobject.first_name + ' ' + personobject.last_name
我想说的是名称self
只是一种惯例。
对于继承,如果您希望在子类中有额外的属性,则需要首先启动超类并根据需要添加参数。
例如,如果要创建名为Person
的{{1}}子类,并使用新属性Boy
,则可以将其定义为:
height
答案 6 :(得分:0)
正如其他答案中所指出的那样,你在另一个答案中看到self
函数实际上是一个参数。通过Python约定,第一个参数
实例方法始终为self
。
类Cats
从其基类继承__init__
函数,
Mammals
。您可以覆盖__init__
,也可以拨打电话或不拨打电话
类实现。
如果Cats
__init__
想要调用基本实现,但不想关心参数,则可以使用Python变量参数。这显示在以下代码中。
班级声明:
class Cats(Mammals):
def __init__(self, *args):
super().__init__(*args)
self.furry = "True"
例如,请参阅此Stack Overflow问题,了解有关该星的信息 可变数量参数的表示法: Can a variable number of arguments be passed to a function?
附加测试代码:
cat = Cats("cat")
print(vars(cat))
输出:
I am a new-born cat
{'name': 'cat', 'age': 0, 'furry': 'True'}