Использовать наследование:
class Foo:
...
class Foo_A(Foo):
def bar(self):
do_something
class Foo_B(Foo):
def bar(self):
sth_else
Затем просто создайте экземпляр Foo_A
или Foo_B
в зависимости от ситуации.
Если вы хотите изменить «идентичность» объекта во время его тогда жизненный цикл identity
будет неправильным именем для него.
Обычно, если вам нужен объект с поведением 'A', вы создаете Foo_A
, а затем, когда вам нужен объект с поведением 'B', вы выбросить исходный объект и создать экземпляр Foo_B
. Сделайте объекты неизменяемыми, если это вообще возможно, вы будете благодарны позже, если сделаете это сейчас.
Как предлагается в комментариях, вы можете изменить тип класса, чтобы изменить поведение переопределенных методов. Это работает в Python и для некоторых проблем является самым чистым решением, но это редко. Обычно лучше объединять переменные объекты (но лучше просто не изменять исходные объекты). Вот возможное решение с использованием агрегации:
class Foo:
def __init__(self, identity):
self.identity = identity
@property
def identity(self):
return self._processor.identity
@identity.setter
def identity(self, identity):
self._processor = FooProcessor(identity, self)
def bar(self):
self._processor.bar()
class FooProcessor:
def __new__(cls, identity, foo):
for subclass in cls.__subclasses__():
if identity == subclass.identity:
return object.__new__(subclass)
raise RuntimeError(f'unknown identity {identity}')
def __init__(self, identity, foo):
assert identity == self.identity
self.foo = foo
class Foo_A(FooProcessor):
identity = 'A'
def bar(self):
print(f'do_something with {self.foo}')
class Foo_B(FooProcessor):
identity = 'B'
def bar(self):
print(f'something else with {self.foo}')
foo = Foo('A')
foo.bar()
foo.identity = 'B'
foo.bar()
assert foo.identity == 'B'
А вот версия, которая изменяет __class__
:
class Foo:
def __init__(self, identity):
self.identity = identity
@property
def identity(self):
return self._identity
@identity.setter
def identity(self, identity):
for subclass in Foo.__subclasses__():
if identity == subclass._identity:
self.__class__ = subclass
return
raise RuntimeError(f'unknown identity {identity}')
class Foo_A(Foo):
_identity = 'A'
def bar(self):
print(f'do_something with {self} {self.identity}')
class Foo_B(Foo):
_identity = 'B'
def bar(self):
print(f'something else with {self} {self.identity}')
foo = Foo('A')
foo.bar()
foo.identity = 'B'
foo.bar()
assert foo.identity == 'B'
Вывод выглядит примерно так:
do_something with <__main__.Foo_A object at 0x10c022af0> A
something else with <__main__.Foo_B object at 0x10c022af0> B