在类内生成新对象的惯用Python方式

17 投票
2 回答
9158 浏览
提问于 2025-04-16 11:49

我有一个对象的方法,这个方法会返回一个该类的新实例。我想找出一种最合适的写法,让这个方法能生成同类型的新对象,而不需要重复代码。

因为这个方法使用了实例中的数据,我的初步想法是:

class Foo(object):
    def get_new(self):
        data = # Do interesting things
        return Foo(data)

但是,如果我创建了一个Foo的子类,而没有重写get_new方法,那么在SubFoo上调用get_new时,返回的还是Foo对象!所以,我可以写一个类方法:

class Foo(object):

    @classmethod
    def get_new(cls, obj):
        data = # Munge about in objects internals
        return cls(data)

不过,我访问的数据是特定于对象的,这样做似乎会破坏封装性,不应该是一个“普通的”(没有装饰的)方法。此外,这样调用时就得像 SubFoo.get_new(sub_foo_inst) 这样,感觉有点多余。我希望对象能“知道”自己应该返回哪种类型——就是和它自己一样的类型!

我想也可以给类添加一个工厂方法,然后在各个地方重写返回类型,而不需要重复逻辑,但这似乎会给子类带来很多工作。

所以,我的问题是,怎么写一个方法,既能灵活处理类的类型,又不用到处标注类型呢?

2 个回答

3

你可以使用内置的'type'。

type(instance)

这就是这个实例的类。

24

如果你想让子类更灵活一点,可以简单地使用 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__ 更符合 Python 的风格。

撰写回答