Идиоматический Python для создания нового объекта изнутри класса
У меня есть метод на одном из моих объектов, который возвращает новый экземпляр этого же класса. Я пытаюсь найти самый идиоматический способ написать этот метод, чтобы он генерировал новый объект того же типа без дублирования кода.
Поскольку этот метод использует данные из экземпляра, мой первый проход:
class Foo(object):
def get_new(self):
data = # Do interesting things
return Foo(data)
Однако, если я подкласс Foo и не переопределяю get_new, вызов get_new на SubFoo вернет Foo! Итак, я мог бы написать classmethod:
class Foo(object):
@classmethod
def get_new(cls, obj):
data = # Munge about in objects internals
return cls(data)
Тем не менее, данные, к которым я обращаюсь, специфичны для объекта, поэтому он, кажется, нарушает инкапсуляцию, чтобы это не было "нормальным" (неразделенным) методом. Кроме того, вы должны называть его как SubFoo.get_new(sub_foo_inst)
, что кажется излишним. Я хотел бы, чтобы объект просто "знал", какой тип возвращает - тот же тип, что и сам!
Я полагаю, что также возможно добавить метод factory в класс и переопределить возвращаемый тип везде, не дублируя логику, но, похоже, он много работает над подклассами.
Итак, мой вопрос: какой лучший способ написать метод, который дает гибкость в типе класса без необходимости комментировать тип повсюду?
Ответы
Ответ 1
Если вы хотите сделать его более гибким для подкласса, вы можете просто использовать специальный атрибут self.__class__
:
class Foo(object):
def __init__(self, data):
self.data = data
def get_new(self):
data = # Do interesting things
return self.__class__(data)
Обратите внимание, что использование подхода @classmethod
не позволит вам получить доступ к данным в одном экземпляре, удалив его как жизнеспособное решение в случаях, когда #Do interesting things
полагается на данные, хранящиеся в экземпляре.
Для Python 2 я не рекомендую использовать type(self)
, так как это вернет недопустимое значение для классических классов (т.е. те, которые не подклассифицированы из базы object
):
>>> class Foo:
... pass
...
>>> f = Foo()
>>> type(f)
<type 'instance'>
>>> f.__class__ # Note that the __class__ attribute still works
<class '__main__.Foo'>
Для Python 3 это не такая уж большая проблема, так как все классы получены из object
, однако, я считаю, что self.__class__
считается более питонической идиомой.
Ответ 2
Вы можете использовать встроенный тип '.
type(instance)
- это класс экземпляра.