首页 > 解决方案 > 这是对元类的有效使用吗

问题描述

我一直在看一些关于装饰器和元类的视频,我想我现在对它们有了更好的理解。我拿走的一个格言是“如果你可以在不使用元类的情况下更简单地做到这一点,就不要使用元类”。前段时间我写了一个元类,但并没有真正理解我在做什么,我回去复习了它。我很确定我在这里做了一些明智的事情,但我想我会检查....

PS 我有点担心在Metaclass定义中使用了 Color 类,我觉得它应该在Class级别使用,但这会使代码复杂化。

import webcolors

# This is a holding class for demo purposes
# actual code allows much more, eg 0.3*c0 + 0.7*c1
class Colour(list):
    def __init__(self,*arg):
        super().__init__(arg)

# define a metaclass to implement Class.name
class MetaColour(type):
    def __getattr__(cls,name):
        try:
            _ = webcolors.name_to_rgb(name)
            return Colour(_.blue,_.green,_.red)
        except ValueError as e:
            raise ValueError(f"{name} is not a valid name for a colour ({e})")
        return f"name({name})"

# a class based on the metaclass MetaColour
class Colours(metaclass=MetaColour):
    pass


print("blue = ",Colours.blue)
print("green = ",Colours.green)
print("lime = ",Colours.lime)
print("orange = ",Colours.orange)
print()
print("lilac = ",Colours.lilac)

编辑:我意识到我可以编写 Color 类,以便 Colour("red") 等同于 Colours.red 但当时觉得使用 Colours.red 更优雅,并添加了 Color 'red' 是恒定的,而不是必须查找并且可以变化的东西。

标签: pythonmetaclass

解决方案


如果你真的需要Colours成为一个类,那么这个元类就可以完成它的工作——而且看起来还不错。在Colour里面使用完全没有问题——没有“元类代码不能使用任何‘普通’类”之类的东西——它像往常一样是 Python 代码。

我要说的是,也许您不需要将其Colours用作类,而只需创建Colours具有您需要的所有功能的类,并创建它的单个实例。其余代码将使用此实例而不是 Colors 类。

是的,单个实例是“单例模式”——但与一些复杂的代码不同,您可以找到有关如何使您的类“成为单例”的信息(包括一些广泛传播的关于需要元类在 Python 中具有单例的不良做法) ),您可以只创建实例,为其分配一个名称,然后完成它。就像在您的示例中一样,您拥有正在使用的“webcolors”对象。

为了获得额外的单例奖励,您可以将 Colors 的单个实例命名为Colours,并隐藏该类,以防止意外使用该类而不是该实例。

(而且,虽然这可能很明显,但为了完整起见:在“使用颜色作为实例”的情况下,根本不需要这个元类 - 相同的__getattr__方法进入类主体)

当然,同样,如果您将 Colors 用作一个类,那么这种设计没有问题。


推荐阅读