类的实例作为同一类的类成员

Posted

技术标签:

【中文标题】类的实例作为同一类的类成员【英文标题】:Instance of class as class member of the same class 【发布时间】:2019-01-04 19:32:09 【问题描述】:

创建作为该类实例的类成员的最“pythonic”方式是什么? IE。像这样:

class MyClass:

    # error! (and this is to be expected as MyClass is not yet fully defined)
    instance_as_member = MyClass()

    def __init__(self):
        print("MyClass instance created!")

可以通过在类定义后添加一个成员来解决这个问题:

class MyClass:
    ...
MyClass.instance_as_member = MyClass()

但这似乎有点不对;自然,类成员应该在该类中定义

有没有更好的方法来做到这一点?

【问题讨论】:

好吧,由于类尚不存在在类体内,你必须在类体完成后找到一个点 有道理。所以我认为建议的解决方案是唯一的方法。 Related @RobertR:有otherhooksavailable,但有时在创建类之后添加它会更简单。 【参考方案1】:

这不是“有点错误”——这是一种简单而明显的方法。 一行代码,每个人都可以阅读,并且很明显“它是什么”。

它仍然没有“感觉”优雅。 因此,如果您不想仅仅为了外观而这样做,也许,如果有很多这样的类,而不是重复代码,可以使用类装饰器来完成:

def instance_as_member(attr_name='instance_as_member', *init_args, **init_kwargs):
    def decorator(cls):
        instance = cls(*init_args, **init_kwargs)
        setattr(cls, attr_name, instance)
        return cls
    return decorator

@instance_as_member()
class MyClass:
    ...

装饰器可以做到这一点,因为它们会在 cls 完全创建后将其作为参数进行修改。对于元类,这会很棘手,因为类实例化的某些步骤,例如调用__init_subclass__,是在任何可以重写的显式元类方法之后执行的,因此,尝试在其中创建实例可能会遇到问题元类初始化方法(__init____new__ 或元元类'__call__

【讨论】:

使用装饰器的好主意,但我认为您的第一条评论是准确的:为了便于阅读,最好在类定义之后进行分配。【参考方案2】:

您似乎需要setUp 类型的功能。这是从类中执行此操作的一种“稍微脏”的方法:设置一个类变量标志以表示该类的第一次使用。检查实例化标志;如果这是第一次访问,则清除标志并运行设置方法。

class MyClass:

    first_touch = True

    def __init__(self, id=0):

        if MyClass.first_touch:
            MyClass.setUp(id)
        print("MyClass instance created!", id)

    @classmethod
    def setUp(self, id):
        MyClass.first_touch = False
        MyClass.instance_as_member = MyClass(-999)


print("Start")
local_obj = MyClass(1)
local_obj = MyClass(2)
local_obj = MyClass(3)

【讨论】:

match 的回答有同样的问题:只有在创建另一个实例后才访问成员实例时,这才有效。不过感谢您的建议!【参考方案3】:

虽然类没有在正文中定义,但它__init__

中定义

但是有一个问题是在__init__里面实例化类是递归的,所以你需要跟踪instance_as_member是否已经生成了。

类似以下的工作:

class Foo:
    member_added = False
    instance_as_member = None

    def __init__(self):
        if not Foo.member_added:
            Foo.member_added = True
            Foo.instance_as_member = Foo()

print(Foo.instance_as_member)
Foo()
print(Foo.instance_as_member)

这会导致:

无<__main__.foo>

至于这是否是一个好主意是一个完全不同的问题!

【讨论】:

是的,我也想过这个,但是成员实例只有在另一个实例创建后才可用。

以上是关于类的实例作为同一类的类成员的主要内容,如果未能解决你的问题,请参考以下文章

第五周学习总结

内部类之静态内部类

包含另一个类作为成员变量的类的构造函数

关于Java问题:“内部类可作为其他类的成员,而且可访问它所在类的成员”?

在另一个类中声明具有成员初始化器的类的实例

类成员