Унаследованная модификация переменной класса в Python
Я хотел бы, чтобы дочерний класс модифицировал переменную класса, которую он наследует от своего родителя.
Я хотел бы сделать что-то вроде:
class Parent(object):
foobar = ["hello"]
class Child(Parent):
# This does not work
foobar = foobar.extend(["world"])
и в идеале:
Child.foobar = ["hello", "world"]
Я мог бы сделать:
class Child(Parent):
def __init__(self):
type(self).foobar.extend(["world"])
но затем каждый раз, когда я создаю экземпляр Child, в список добавляется "мир", что нежелательно. Я мог бы изменить его дальше:
class Child(Parent):
def __init__(self):
if type(self).foobar.count("world") < 1:
type(self).foobar.extend(["world"])
но это все равно хак, потому что я должен создать экземпляр Child до того, как он сработает.
Есть ли лучший способ?
Ответы
Ответ 1
Предполагая, что вы хотите иметь отдельный список в подклассе, не изменяйте список родительских классов (что кажется бессмысленным, поскольку вы можете просто изменить его на месте или поместить туда ожидаемые значения):
class Child(Parent):
foobar = Parent.foobar + ['world']
Обратите внимание, что это работает независимо от наследования, что, вероятно, хорошо.
Ответ 2
Вы не должны использовать изменяемые значения в переменных класса. Задайте такие значения в экземпляре вместо этого, используя инициализатор экземпляра __init__()
:
class Parent(object):
def __init__(self):
self.foobar = ['Hello']
class Child(Parent):
def __init__(self):
super(Child, self).__init__()
self.foobar.append('world')
В противном случае происходит то, что список foobar
используется не только для экземпляров, но и для подклассов.
В любом случае вам придется избегать модификации mutables родительских классов, даже если вы хотите разделить состояние между экземплярами с помощью переменной переменной; только присваивание имени создало бы новую переменную:
class Parent(object):
foobar = ['Hello']
class Child(Parent):
foobar = Parent.foobar + ['world']
где новая переменная foobar
создается для класса Child
. Используя назначение, вы создали новый экземпляр списка, а переменная Parent.foobar
изменена.
Соблюдайте осторожность с вложенными переменными в таких случаях; используйте модуль copy
, чтобы при необходимости создать глубокие копии.