gpt4 book ai didi

python - 如何从类主体中获取对当前类的引用?

转载 作者:太空狗 更新时间:2023-10-30 02:06:38 24 4
gpt4 key购买 nike

我想在基类中保留一个包含(所有,非立即包含的)子类的字典,以便我可以从字符串中实例化它们。我这样做是因为 CLSID 是通过 Web 表单发送的,所以我想将选择限制为从子类中设置的选项。 (我不想 eval()/globals() 类名)。

class BaseClass(object):
CLSID = 'base'
CLASSES = {}

def from_string(str):
return CLASSES[str]()

class Foo(BaseClass):
CLSID = 'foo'
BaseClass.CLASSES[CLSID] = Foo

class Bar(BaseClass):
CLSID = 'bar'
BaseClass.CLASSES[CLSID] = Bar

这显然行不通。但是是否有类似 @classmethod 的东西用于初始化?这个想法是这个类方法只会在读取每个类并将该类注册到基类时运行一次。像下面这样的东西就可以工作了:(还会将额外的行保存在 FooBar 中)

class BaseClass(object):
CLSID = 'base'
CLASSES = {}

@classmethod
def __init__(cls):
BaseClass.CLASSES[cls.CLSID] = cls

def from_string(str):
return CLASSES[str]()

我考虑过使用 __subclasses__,然后在 CLSID 上使用 filter(),但这只适用于直接子类。

所以,希望我解释了我的目的,问题是如何让它发挥作用?还是我以完全错误的方式解决了这个问题?

最佳答案

不可撤销地将其与基类绑定(bind):

class AutoRegister(type):
def __new__(mcs, name, bases, D):
self = type.__new__(mcs, name, bases, D)
if "ID" in D: # only register if has ID attribute directly
if self.ID in self._by_id:
raise ValueError("duplicate ID: %r" % self.ID)
self._by_id[self.ID] = self
return self

class Base(object):
__metaclass__ = AutoRegister
_by_id = {}
ID = "base"

@classmethod
def from_id(cls, id):
return cls._by_id[id]()

class A(Base):
ID = "A"

class B(Base):
ID = "B"

print Base.from_id("A")
print Base.from_id("B")

或者将不同的关注点分开:

class IDFactory(object):
def __init__(self):
self._by_id = {}
def register(self, cls):
self._by_id[cls.ID] = cls
return cls

def __call__(self, id, *args, **kwds):
return self._by_id[id](*args, **kwds)
# could use a from_id function instead, as above

factory = IDFactory()

@factory.register
class Base(object):
ID = "base"

@factory.register
class A(Base):
ID = "A"

@factory.register
class B(Base):
ID = "B"

print factory("A")
print factory("B")

您可能已经选出我喜欢的那一个。与类层次结构分开定义,您可以轻松扩展和修改,例如通过两个名称注册(使用 ID 属性只允许一个):

class IDFactory(object):
def __init__(self):
self._by_id = {}

def register(self, cls):
self._by_id[cls.ID] = cls
return cls

def register_as(self, name):
def wrapper(cls):
self._by_id[name] = cls
return cls
return wrapper

# ...

@factory.register_as("A") # doesn't require ID anymore
@factory.register # can still use ID, even mix and match
@factory.register_as("B") # imagine we got rid of B,
class A(object): # and A fulfills that roll now
ID = "A"

您还可以将工厂实例保留在基础“内部”,同时保持解耦:

class IDFactory(object):
#...

class Base(object):
factory = IDFactory()

@classmethod
def register(cls, subclass):
if subclass.ID in cls.factory:
raise ValueError("duplicate ID: %r" % subclass.ID)
cls.factory[subclass.ID] = subclass
return subclass

@Base.factory.register # still completely decoupled
# (it's an attribute of Base, but that can be easily
# changed without modifying the class A below)
@Base.register # alternatively more coupled, but possibly desired
class A(Base):
ID = "A"

关于python - 如何从类主体中获取对当前类的引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2191505/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com