类的实例作为同一类的类成员
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>
(至于这是否是一个好主意是一个完全不同的问题!)
【讨论】:
是的,我也想过这个,但是成员实例只有在另一个实例创建后才可用。以上是关于类的实例作为同一类的类成员的主要内容,如果未能解决你的问题,请参考以下文章