Python 在没有实例的类对象上设置魔术方法?

Python 在没有实例的类对象上设置魔术方法?,python,Python,假设我有一个简单的对象: class Providers: Apple = "Apple" Banana = "Banana" Cherries = "Seedless Cherries" 我希望能够在提供者中执行类似于“Apple”的。,我相信这需要我设置两个神奇的方法,\uuuu len\uuu和\uuu getitem\uuuu 我试了一些简单的方法 @classmethod def __len__(cls): return 3 但是当我运行len(Pr

假设我有一个简单的对象:

class Providers:
    Apple = "Apple"
    Banana = "Banana"
    Cherries = "Seedless Cherries"
我希望能够在提供者中执行类似于“Apple”的
,我相信这需要我设置两个神奇的方法,
\uuuu len\uuu
\uuu getitem\uuuu

我试了一些简单的方法

@classmethod
def __len__(cls):
    return 3
但是当我运行
len(Providers)
时,我得到
TypeError:type'type'的对象没有len()

但是
提供程序。\uu len\uuu()
返回3

如何在不实例化类的情况下获取类的
len
?或者它们是否需要始终使用
\uu init\uuu
self.Apple='Apple'进行实例化?
使用元类:

class FooMeta(type):
    def __len__(self):
        return 10

class Foo(metaclass=FooMeta):
    pass

print(len(Foo)) # 10

这是因为类实际上是对象,也就是说,它们是元类的实例。您需要使用
metclass
,因为当您使用
len(提供者)
时,就像您使用
type(提供者)
就你而言:

       type(Providers) ==  <class 'type'>   # no __len__ method here 

这是python解释器处理dunder(魔法方法)方法的方式:
type(SomeObject)。\udunder\uuuuuuuuuuuuuuuuuuuoSomeObject)

如果您已经创建了一个类对象,如果您想在类对象中实现这些方法,那么您需要在类对象的类中,即在元类中实现它。或者,更合理地说,不要试图使用像容器这样的类。祝贺你,你已经重新发明了。这是有道理的。我在Airflow对遗嘱执行人的定义中看到了类似的代码:我认为这是一个很好的实践。我来看看enum。@pedram看起来他们并不像您的用例那样试图使用那个类,您似乎想要一个简单的记录/容器。这看起来像是命名间隔常量/枚举,比如classyeah,但这完全是一个过度工程化的解决方案,解决了一个本来就不应该存在的问题我同意,他们正确的方法是扩展容器类,通常来说,我更喜欢组合而不是继承,特别是在这种情况下,它不是任何容器类的自然扩展。OP似乎几乎想要一个枚举,但这只是我的猜测。我更喜欢FP而不是OOP。组合会减少代码的耦合,但我认为元类太令人兴奋了,需要展示出来。这是一个元类使用不当的好例子,但仍然是一个好例子。我只是想验证传入的数据是否与提供者定义的常量之一相匹配。我想我可以做一些类似于
的事情,比如在提供者中使用var.\uu dict\uu.values()
,但这看起来很难看。@Martijn Pieters的一个很好的解释是: