有没有办法从类声明中引用类名?一个例子如下:
class Plan(SiloBase):
cost = DataField(int)
start = DataField(System.DateTime)
name = DataField(str)
items = DataCollection(int)
subPlan = ReferenceField(Plan)
我有一个读取此信息的元类并进行一些设置,基类实现了一些常见的保存。我希望能够创建这样的递归定义,但到目前为止,在我的实验中,我无法获得我想要的效果,通常会遇到“计划未定义”错误。我理解发生了什么,类的名称不在类的范围内。
答案 0 :(得分:23)
试试这个:
class Plan(SiloBase):
cost = DataField(int)
start = DataField(System.DateTime)
name = DataField(str)
items = DataCollection(int)
Plan.subPlan = ReferenceField(Plan)
或者像这样使用__new__
:
class Plan(SiloBase):
def __new__(cls, *args, **kwargs):
cls.cost = DataField(int)
cls.start = DataField(System.DateTime)
cls.name = DataField(str)
cls.items = DataCollection(int)
cls.subPlan = ReferenceField(cls)
return object.__new__(cls, *args, **kwargs)
答案 1 :(得分:8)
我有一个读取此信息的元类并进行一些设置
大多数使用元类的框架都提供了解决此问题的方法。例如,Django:
subplan = ForeignKey('self')
subplan = SelfReferenceProperty()
稍后使用__new__
添加附加属性等解决方案的问题在于,大多数ORM元类都希望在创建类时存在类属性。
答案 2 :(得分:2)
我明白发生了什么, 类的名称不在范围内 在课堂内。
不完全是。在定义内容(例如范围)时,类的名称尚未定义。
答案 3 :(得分:0)
不,你不能这样做。想想如果你这样做会发生什么:
OtherPlan = Plan
other_plan = OtherPlan()
在other_plan
的实例化时,该类的名称是什么?
无论如何,这种事情最好在__new__
方法中完成,该方法需要cls
参数来引用该类。
答案 4 :(得分:0)
Sine Python 3.7和PEP 563有一种方法可以实现。
添加导入
from __future__ import annotations
,以下代码将起作用
from __future__ import annotations
from typing import List
class Refer(object):
def __init__(self, x: Plan):
self.x: Plan = x
class Plan(object):
def __init__(self):
pass
subPlan: Refer(Plan())
答案 5 :(得分:0)
使用python3中的以下代码可以做到这一点。 我们使用cached_property只评估一次Player.enemyPlayer,然后返回缓存的结果。因为我们的值来自一个函数,所以在第一次加载该类时不会对其进行求值。
class cached_property(object):
# this caches the result of the function call for fn with no inputs
# use this as a decorator on function methods that you want converted
# into cached properties
def __init__(self, fn):
self._fn = fn
def __set_name__(self, owner, name):
# only works in python >= 3.6
self.name = name
self._cache_key = "_" + self.name
def __get__(self, instance, cls=None):
if self._cache_key in vars(self):
return vars(self)[self._cache_key]
else:
result = self._fn()
setattr(self, self._cache_key, result)
return result
class Player:
@cached_property
def enemyPlayer():
return Player