如何在Python中自我引用一个类?

4
我希望这个模板类能够接受自身和其他类型的子类,使用type(i) in self._allowed_types进行判断。
class Template():
    _allowed_types = [str, Template, SafeHtml]

上面的代码会抛出如下错误:
NameError: name 'Template' is not defined
3个回答

8
在类被定义之后添加该类的类:
class Template():
    _allowed_types = [str, SafeHtml]

Template._allowed_types.append(Template)

必须在创建类对象之前运行类体,因此名称Template尚未定义。但是您始终可以在创建对象后更改类属性。


2
另一个选择是使用属性来对字段进行延迟处理。
class Test(object):
    @property
    def allowed(self):
        return [str, Test]

t = Test()
print Test in t.allowed

我不明白为什么要踩这个 - 这绝对是一个好的做法 - 只有在极少数情况下才不应该优先选择。 - jsbueno
我没有投反对票。只是在7年后评论说,如果所需的用法是 Test.allowed,那么这个方法就不起作用,因为它返回一个 property 对象,而不是 [str, Test]。也许这就是@jsbueno所说的“少数情况”之一,这种情况下不推荐使用这种方法? - Snake Verde

0

另一种(也许更清晰的)方式是声明一个中间类:

class BasicTemplate():
    pass

class Template(BasicTemplate):
    _allowed_types = [str, BasicTemplate]

BasicTemplate 可以完全是虚拟的,或者包含一些有用的代码。拥有一个模板,它不允许包含自身,在某些时候可能会派上用场。

当然,这将需要使用 isinstance 而不是 type() 来检查类型,但这是一个好主意。


可能对于展示“另一种方式”来说很好,但在我看来并不更“清晰”——这会弄脏类层次结构,在原本没有的情况下强制引入一个;如果已经有存在的类层次结构,那么创建需要中间类或者多重继承的第二个层次结构可能会加剧问题:正如你所看到的,事情变得非常丑陋。简单来说,只需允许带有类名的字符串,并从相关模块检查字符串和名称检索——就像 Django 所做的那样——要简单得多。 - jsbueno
2
@jsbueno:是的,这是主观的,如果没有看到整个情况,谈论起来相当无意义。在我的书中,私有成员的类外调用以及字符串标识符都是大忌。 - georg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接