Рассмотрите эту ситуацию:
Я получаю объект типа A
который имеет функцию f
. Т.е.:
class A:
def f(self):
print 'in f'
def h(self):
print 'in h'
и я получаю экземпляр этого класса, но я хочу переопределить f
функционируйте, но сохраните остальную часть функциональности A
. Таким образом, то, что я думал, было чем-то вроде этого:
class B(A):
def __init__(self, a):
#something here
....
def f(self):
print 'in B->f'
и использование было бы:
def main(a):
b = B(a)
b.f() #prints "in B->f"
b.h() #print "in h"
То, что я хочу, является своего рода конструктором копии, который получает родителя текущего класса (A
) и возвращает экземпляр этого класса (B
).
Как дела такая вещь? Как был бы __init__
взгляд метода?
Примечание: это сообщение было отредактировано исходным плакатом для слияния изменений, предложенных, ниже которого то, почему некоторые предложения выглядят избыточными или неправильными.
То, как вы создаете объект подкласса B
«на основе» одного из класса A
, зависит исключительно от того, как последний поддерживает состояние , если оно есть, и как вам лучше всего добраться до этого состояния и скопировать его. В вашем примере экземпляры A
не имеют состояния, поэтому нет абсолютно никакой работы, которую вам нужно выполнять в B
's ' __ init __ '
. В более типичном примере, скажем:
class A(object):
def __init__(self):
self._x = 23
self._y = 45
def f(self):
print 'in f,', self._x
def h(self):
print 'in h,', self._y
состояние будет в двух атрибутах экземпляра _x
и _y
, так что это то, что вам нужно скопировать:
class B(A):
def __init__(self, a):
self._x = a._x
self._y = a._y
def f(self):
print 'in B->f,', self._x
Это - это наиболее распространенный и нормальный подход, при котором подкласс принимает и напрямую реализует свою зависимость от состояния от суперкласса - это очень простой и линейный подход.
Обычно вы ищите аспекты состояния экземпляра A
в A
'__ init __'
, потому что самый нормальный, простой код Python устанавливает состояние экземпляра в инициализация (атрибуты могут быть добавлены и удалены позже или даже из кода вне тела класса, но это не часто и обычно не рекомендуется).
Можно добавить немного «магии» (программирование на основе интроспекции), например ..:
class B1(A):
def __init__(self, a):
try: s = a.__getstate__()
except AttributeError: s = a.__dict__
try: self.__setstate__(s)
except AttributeError: self.__dict__.update(s)
getstate - это специальный метод, который классы могут определять - если они это делают, он используется (например, путем травления) для «получения состояния» их экземпляров с целью сериализации (в противном случае, __ dict __
экземпляра считается «состоянием» экземпляра). Он может вернуть dict (в этом случае .Вызов update
обновляет состояние self
), но он также может возвращать что-нибудь еще, если класс также определяет __ setstate __
, которое его принимает (так что этот код сначала пробует этот маршрут, прежде чем вернуться к возможности обновления). Обратите внимание, что в этом случае один или оба специальных метода будут унаследованы от A
- я бы не стал определять / переопределять их в B
(если нет дополнительных тонких целей для таким образом, конечно ;-).
Стоит ли использовать эти четыре строки «магии» вместо простых заданий, которые я впервые предложил? В большинстве случаев нет - предпочтительнее простота. Но если A
делает что-то особенное или подвергается воздействию внешнего кода, изменяющего его состояние, это решение может быть более мощным и универсальным (это то, что вы покупаете, принимая его усложнение). Итак, вы должны знать, применим ли последний случай (а затем «приступайте к большим пушкам» специальных методов, связанных с состоянием), или если A
и его экземпляры являются «довольно обычными ванильными», в этом случае я настоятельно рекомендую вместо этого выбирать простоту и ясность.
Попробуйте следующее:
class A:
def f(self):
print("in f")
def h(self):
print("in h")
class B(A):
def f(self):
print("in B:f")
def test(x):
x.f()
x.h()
test(A())
test(B())
Обратите внимание, я использую Python 3, что является причиной того, что print
принимает аргументы в скобках.
Output:
in f
in h
in B:f
in h
Необходимо поместить аргумент self
в список аргументов, например методов в python.
Как только вы это сделаете, он просто будет работать, потому что все методы виртуальны в python.