В дальнейшем B является внешним классом, который наследуется от Bbase, а A является внутренним классом, который наследуется от Abase.
Я создаю B с переменной класса Bb = None, затем изменяю Bb Iзатем повторите процесс.В новом производном классе я обнаружил, что действительно Bb = None, поэтому я создал нетронутую копию класса B, что и было моим намерением.Пока все хорошо.
Также внутри B я создаю класс A с переменной класса Aa = None, и я тоже это изменяю.
Однако при повторении процессая подумал, что моя новая копия A имеет Aa равное ранее измененному значению, а не None, которого я ожидаю от инициализатора в базовом классе.То есть, в конце концов, я не получил нетронутую копию A, а моя копия B содержит тот же класс A (или, возможно, копию с тем же изменением), который я создал ранее.Это показано в следующем коде и выводе.
Я действительно хочу, чтобы моя в противном случае нетронутая копия B содержала нетронутую копию A, а не измененную ранее версию A. Как я могу это сделать?
Код:
class Abase():
a = None
class Bbase():
b = None
class A(Abase): pass
print('Run 1')
class B(Bbase): pass
print('B.b, B.A.a=', B.b, B.A.a, '(Expect "None None")')
B.b = 23
B.A.a = 47
print('B.b, B.A.a=', B.b, B.A.a, '(Expect "23 47")')
print()
print('Run 2')
class B(Bbase): pass
print('B.b, B.A.a=', B.b, B.A.a, '(Expect "None None")')
B.b = 23
B.A.a = 47
print('B.b, B.A.a=', B.b, B.A.a, '(Expect "23 47")')
Вывод (Python 3.7.0, MacOS 10.13.6):
Run 1
B.b, B.A.a= None None (Expect "None None")
B.b, B.A.a= 23 47 (Expect "23 47")
Run 2
B.b, B.A.a= None 47 (Expect "None None") <====
B.b, B.A.a= 23 47 (Expect "23 47")
Кстати, если я создаю A вне B, тогдавставьте его в B через B.A = A
, это даст желаемый эффект.Однако я надеялся создать его внутри B, как и другие объекты, принадлежащие классу B.
Разрешение
Во-первых, в результате этого обсуждения и обсуждения с коллегами по Hack Manhattan , я был разочарован серьезным заблуждением о том, как наследование работает в Python.Я думал, что такой вызов, как class Bbase(): pass; class B(Bbase): pass
, создал новый класс B, а затем концептуально выполнил код из Bbase в B. Но на самом деле, концептуально, он просто копирует объекты в B, которые были созданы при создании Bbase.Это был мой Ага!момент.Возможно, кто-то найдет это полезным. (Обратите внимание, что последнее объяснение также неверно. См. Обсуждение с user2357112 ниже.)
Во-вторых, хорошо работает следующее:
class Abase():
a = None
class Bbase():
b = None
@classmethod
def getA(cls):
class A(Abase): pass
cls.A = A
Тогда я могуповторяйте вызов, как class B(Bbase): pass; B.getA()
, столько раз, сколько я хотел бы, и каждый раз я получаю нетронутый B, содержащий нетронутый A. Это своего рода обезьянье пятно, удерживающее обезьяну в клетке.