PHP 또는 Java의 가상 방법을 알고 있습니다.
파이썬에서 어떻게 구현할 수 있습니까?
아니면 추상 클래스에서 빈 메서드를 정의하고 재정의해야합니까?
답변:
물론, 기본 클래스에서 메서드를 정의 할 필요조차 없습니다. 파이썬에서 메서드는 가상보다 낫습니다 . 파이썬에서 타이핑하는 것이 오리 타이핑 이기 때문에 완전히 동적 입니다.
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
파이썬에서도이 동작을 할 수 있도록 공통 기본 클래스에서 파생 필요가 없습니다 - 당신은 무료로 얻을 수 있습니다. 즉 어떤 프로그래머가 더 잘 문서화하고 부과하는 더 엄격한 방법으로 자신의 클래스 계층을 정의하는 것을 선호했다 일부 입력의 엄격합니다. 이것은 또한 가능합니다-예를 들어 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
Python 메서드는 항상 가상입니다.
실제로 버전 2.6에서 파이썬은 추상 기본 클래스 라는 것을 제공하며 다음 과 같이 명시 적으로 가상 메서드를 설정할 수 있습니다.
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의 모든 메소드가 그렇게 작동하는 것은 아닙니다. 던더 방법은하지 않습니다. 그다지 잘 알려지지 않은 기능이라고 생각합니다.
이 인공적인 예를 고려하십시오
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 의이 멋진 강연은 이것이 불편한 사용 사례에 대한 예를 제공합니다.