Переопределение метода Python, имеет ли значение подпись? - PullRequest
41 голосов
/ 17 мая 2011

Допустим, у меня есть

class Super():
  def method1():
    pass

class Sub(Super):
  def method1(param1, param2, param3):
      stuff

Это правильно? Будут ли вызовы method1 всегда идти в подкласс? Мой план состоит в том, чтобы иметь 2 подкласса каждый переопределенный метод1 с разными параметрами

Ответы [ 6 ]

33 голосов
/ 17 мая 2011

Python разрешит это, но если method1() предназначено для выполнения из внешнего кода, то вы можете пересмотреть это, поскольку оно нарушает LSP и поэтому не всегда будет работать должным образом.

11 голосов
/ 12 января 2019

Python разрешает «переопределять» методы с разными сигнатурами, но вы никогда не можете иметь два метода с одинаковыми именами в одном классе, даже если их сигнатуры различны (то есть перегрузка методов отсутствует). В случае переопределения метода, если вы вызываете методы с неправильным числом параметров, определенных для объекта, вы получите ошибку. Помните, что методы Python - это просто пары «ключ-значение» в словаре, присоединенном к объекту, и «переопределение» означает просто замену значения в этом словаре, изначально скопированного из словаря базового класса для того же ключа.

В некоторых случаях требуется, чтобы метод производного класса имел дополнительных параметров, чем базовый класс. Чтобы сделать это в Python, сохранив также LSP , вы можете использовать следующую технику:

class Base:
    def hello(self, name, *kargs, **kwargs):
        print("Hello", name)

class Derived(Base):
      def hello(self, name, age=None, *kargs, **kwargs):
          super(Derived, self).hello(name, age, *kargs, **kwargs) 
          print('Your age is ', age)

b = Base()
d = Derived()

b.hello('Alice')
b.hello('Bob', age=24)
d.hello('Rick')
d.hello('John', age=30)

Выше будет напечатано:

Hello Alice
Hello Bob
Hello Rick
Your age is  None
Hello John
Your age is  30

Играть с этим кодом

1 голос
/ 12 августа 2016

Вы могли бы сделать что-то вроде этого, если можно использовать аргументы по умолчанию:

>>> class Super():
...   def method1(self):
...     print("Super")
...
>>> class Sub(Super):
...   def method1(self, param1="X"):
...     super(Sub, self).method1()
...     print("Sub" + param1)
...
>>> sup = Super()
>>> sub = Sub()
>>> sup.method1()
Super
>>> sub.method1()
Super
SubX
1 голос
/ 17 мая 2011

Это будет работать:

>>> class Foo(object):
...   def Bar(self):
...     print 'Foo'
...   def Baz(self):
...     self.Bar()
... 
>>> class Foo2(Foo):
...   def Bar(self):
...     print 'Foo2'
... 
>>> foo = Foo()
>>> foo.Baz()
Foo
>>> 
>>> foo2 = Foo2()
>>> foo2.Baz()
Foo2

Однако это обычно не рекомендуется.Взгляните на ответ S.Lott : Методы с одинаковыми именами и разными аргументами - это запах кода .

1 голос
/ 17 мая 2011

В python все методы класса являются «виртуальными» (в терминах C ++). Итак, в случае вашего кода, если вы хотите вызвать method1() в суперклассе, это должно быть:

class Super():
    def method1(self):
        pass

class Sub(Super):
    def method1(self, param1, param2, param3):
       super(Sub, self).method1() # a proxy object, see http://docs.python.org/library/functions.html#super
       pass

И сигнатура метода имеет значение. Вы не можете вызвать метод, подобный этому:

sub = Sub()
sub.method1() 
0 голосов
/ 17 мая 2011

Да. Вызовы «method1» всегда будут переходить в подкласс. Подпись метода в Python состоит только из имени, а не списка аргументов.

...