【问题标题】:Is this a valid use of metaclasses这是对元类的有效使用吗
【发布时间】:2021-02-22 10:02:44
【问题描述】:

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

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 ' 是一个常数,而不是必须查找并且可以变化的东西。

【问题讨论】:

    标签: python metaclass


    【解决方案1】:

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

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

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

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

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

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

    【讨论】:

    • 感谢您抽出宝贵的时间来回答,并向我介绍单例类的概念。
    猜你喜欢
    • 2010-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-10
    • 1970-01-01
    相关资源
    最近更新 更多