我知道PHP或Java的虚拟方法。
如何在Python中实现它们?
还是我要在抽象类中定义一个空方法并覆盖它?
Answers:
当然,您甚至不必在基类中定义方法。在Python中,方法要比虚拟方法更好-它们是完全动态的,因为Python中的输入是鸭子输入。
class Dog:
def say(self):
print "hau"
class Cat:
def say(self):
print "meow"
pet = Dog()
pet.say() # prints "hau"
another_pet = Cat()
another_pet.say() # prints "meow"
my_pets = [pet, another_pet]
for a_pet in my_pets:
a_pet.say()
Cat
而且Dog
在Python中,甚至不必从通用基类派生该行为即可-您可以免费获得它。就是说,一些程序员更喜欢以更严格的方式定义其类层次结构,以更好地对其进行记录并施加一定的键入严格性。这也是可能的,例如参见abc
标准模块。
raise NotImplementedError()
建议对未实现方法的“抽象”基类的“纯虚方法”引发异常。
https://docs.python.org/3.5/library/exceptions.html#NotImplementedError说:
此异常源自
RuntimeError
。在用户定义的基类中,抽象方法要求派生类重写该方法时,应引发此异常。
正如其他人所说,这主要是文档惯例,不是必需的,但是通过这种方式,您可以获得比缺少属性错误更有意义的异常。
例如:
class Base(object):
def virtualMethod(self):
raise NotImplementedError()
def usesVirtualMethod(self):
return self.virtualMethod() + 1
class Derived(Base):
def virtualMethod(self):
return 1
print Derived().usesVirtualMethod()
Base().usesVirtualMethod()
给出:
2
Traceback (most recent call last):
File "./a.py", line 13, in <module>
Base().usesVirtualMethod()
File "./a.py", line 6, in usesVirtualMethod
return self.virtualMethod() + 1
File "./a.py", line 4, in virtualMethod
raise NotImplementedError()
NotImplementedError
实际上,在2.6版中,python提供了一种称为抽象基类的东西,您可以像这样显式设置虚拟方法:
from abc import ABCMeta
from abc import abstractmethod
...
class C:
__metaclass__ = ABCMeta
@abstractmethod
def my_abstract_method(self, ...):
只要该类不继承自已经使用元类的类,它就可以很好地工作。
Python方法始终是虚拟的
就像伊格纳西奥(Ignacio)所说的那样,以某种方式,类继承可能是实现所需内容的更好方法。
class Animal:
def __init__(self,name,legs):
self.name = name
self.legs = legs
def getLegs(self):
return "{0} has {1} legs".format(self.name, self.legs)
def says(self):
return "I am an unknown animal"
class Dog(Animal): # <Dog inherits from Animal here (all methods as well)
def says(self): # <Called instead of Animal says method
return "I am a dog named {0}".format(self.name)
def somethingOnlyADogCanDo(self):
return "be loyal"
formless = Animal("Animal", 0)
rover = Dog("Rover", 4) #<calls initialization method from animal
print(formless.says()) # <calls animal say method
print(rover.says()) #<calls Dog says method
print(rover.getLegs()) #<calls getLegs method from animal class
结果应为:
I am an unknown animal
I am a dog named Rover
Rover has 4 legs
像C ++中的虚方法(通过对基类的引用或指针调用派生类的方法实现)之类的东西在Python中没有意义,因为Python没有类型。(不过,我不知道虚拟方法如何在Java和PHP中工作。)
但是,如果您说“虚拟”是指在继承层次结构中调用最底层的实现,那么这就是您在Python中总能得到的,正如几个答案所指出的那样。
好吧,几乎总是...
正如dplamp指出的那样,并非Python中的所有方法都具有这种行为。Dunder方法不行。我认为这不是一个众所周知的功能。
考虑这个人为的例子
class A:
def prop_a(self):
return 1
def prop_b(self):
return 10 * self.prop_a()
class B(A):
def prop_a(self):
return 2
现在
>>> B().prop_b()
20
>>> A().prob_b()
10
但是,考虑这一点
class A:
def __prop_a(self):
return 1
def prop_b(self):
return 10 * self.__prop_a()
class B(A):
def __prop_a(self):
return 2
现在
>>> B().prop_b()
10
>>> A().prob_b()
10
我们唯一更改的是制作prop_a()
dunder方法。
第一种行为的问题可能是,您不能prop_a()
在不影响的行为的情况下更改派生类中的行为prop_b()
。Raymond Hettinger的这个很好的演讲提供了一个用例的例子,其中用例不方便。