通过标识符反向查找Python类

2024-09-22 14:25:40 发布

您现在位置:Python中文网/ 问答频道 /正文

我有几个“model”类(ModelFoo、ModelBar、ModelBaz、ModelQux),它们可以由具有不同标识符的客户机实例化。为了将标识符映射到正确的模型类,我创建了一个映射类:

class ModelTypes(object):
  """ Enumeration of supported class types, mapping userland identifier to constructor.
  """
  # Multiple names per model type enable us to run several instances in parallel
  FooModel = ModelFoo
  fooMod = ModelFoo
  foo = Foo
  ff = Foo

  Bar = ModelBar
  bar = ModelBar

  Baz = ModelBaz
  baz = ModelBaz

  Qux = ModelQux
  qux = ModelQux


  @classmethod
  def getTypes(cls):
    """ Return the names of the attributes explicitly defined above.
    """
    for attrName in dir(cls):
      attrValue = getattr(cls, attrName)
      if (isinstance(attrValue, type) and
          issubclass(attrValue, acceptableClassImplementations)):
        yield attrName # attrName is an acceptable model name

也就是说,我使用ModelTypes类进行反向查找,其中我需要将一个简单标识符(例如qux)映射回相应的类(ModelQux)。但是添加客户机可能使用的所有标识符会变得单调乏味。是否有标准/建议的方法将关键字映射到类?你知道吗


Tags: ofto客户机modelnames标识符classcls
1条回答
网友
1楼 · 发布于 2024-09-22 14:25:40

如果您只想少写将多个变量定义为同一个值的代码,那么可以使用以下语法:

x = y = z = 0
print(x,y,z)

所以你可以:

  FooModel = fooModel = ModelFoo
  foo = ff = Foo

  Bar = bar = ModelBar
  Baz = baz = ModelBaz
  Qux = quz = ModelQux

但是如果您想要更自动化的东西,那么您需要一个dict,它是唯一的内置映射对象,但是它可以实现为以与项相同的方式响应属性:

class ModelTypes(dict):
    __slots__ = ()#otherwise each object would have a second dict used for attributes

    #this will mean d.x acts the same as d['x']
    __getattr__ = dict.__getitem__
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__
    #would you still need this or would you just use .keys() instead?
    def getTypes(self): #maybe take an optional argument to use in issubclass()?
        return [name for name,cls in self.items() \
                 if (isinstance(cls,type) and 
                     issubclass(cls, acceptableClassImplementations))]

同样,dict的任何子类都可以定义一个__missing__方法,如果您试图获取一个不存在的键,则会调用该方法,因此您可以实现它来再次检查dict,忽略大小写并检查类的文档名:

    def __missing__(self,key):
        #if the user uses different case this will check again with generic case
        #also checks against name attribute of types
        if not isinstance(key,str) or key=="":
            raise KeyError(key)

        key = key.lower()
        for name,cls in self.items():
            if key == name.lower()):
                return cls
            if key == getattr(cls,"__name__","").lower():
                return cls
        raise KeyError(key)

然后,您可以定义一个与一个类相对应的名称,并将处理所有变体:

class FooModel:pass
class FooBar:pass
class ModelQux:pass

#other then added commas this is just as clean as inside a class
models = ModelTypes(foo=FooModel,
                    bar=FooBar,
                    qux=ModelQux)

print(models.foo is models["foo"])   #.foo works from overriding __getattr__
print(models.foo is models.Foo)      #'Foo' works because __missing__ checked it again with lower case
print(models.foo is models.FooModel) #'FooModel' works because __missing__ also checks class names
print(models.foo is models.foomodel) #it checks the .lower() of key against .lower() of class name

相关问题 更多 >