这是元类的有效使用吗
Is this a valid use of metaclasses
我一直在看一些关于装饰器和元classes 的视频,我想我现在更了解它们了。我带走的一条格言是“如果你可以在不使用它们的情况下更简单地做到这一点,就不要使用 metaclasses”。前段时间我写了一个 metaclass 并没有真正理解我在做什么,然后我回去审查了它。我很确定我在这里做了一些明智的事情,但我想我会检查....
PS 我有点担心 Metaclass 定义中使用了颜色 class,我觉得它应该在 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 class 以便 Colour("red") 等同于 Colours.red 但当时觉得使用 Colours.red 更合适优雅并添加了颜色 'red' 是一个常量的含义,而不是必须查找并且可以变化的东西。
如果你真的需要 Colours
成为 class,那么这个 metaclass 就可以了——而且看起来不错。在其中使用 Colour
完全没有问题 - 没有“元 class 代码不能使用任何 'ordinary' class” - 它Python 代码照常。
我想说的是,也许您不需要将 Colours
用作 class,而只需创建 Colours
class ,具有您需要的所有功能,并创建它的单个实例。代码的其余部分将使用此实例而不是 Colors class.
是的,单个实例是“单例模式”——但与一些复杂的代码不同,您可以找到有关如何使 class“成为单例”的代码(包括一些广泛传播的关于需要元 class 在 Python 中有一个单例),您可以创建实例,将其分配给一个名称,然后完成它。就像在您的示例中一样,您拥有正在使用的“webcolors”对象。
对于额外的单例奖励,您可以将 Colors 的单个实例命名为 Colours
,并隐藏 class,以防止意外使用 class 而不是实例。
(而且,虽然这可能很明显,但为了完整起见:在“使用颜色作为实例”的情况下根本不需要这个元class - 相同的__getattr__
方法进入 class 主体)
当然,再说一遍,如果你把Colors用作class,这个设计是没有问题的。
我一直在看一些关于装饰器和元classes 的视频,我想我现在更了解它们了。我带走的一条格言是“如果你可以在不使用它们的情况下更简单地做到这一点,就不要使用 metaclasses”。前段时间我写了一个 metaclass 并没有真正理解我在做什么,然后我回去审查了它。我很确定我在这里做了一些明智的事情,但我想我会检查....
PS 我有点担心 Metaclass 定义中使用了颜色 class,我觉得它应该在 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 class 以便 Colour("red") 等同于 Colours.red 但当时觉得使用 Colours.red 更合适优雅并添加了颜色 'red' 是一个常量的含义,而不是必须查找并且可以变化的东西。
如果你真的需要 Colours
成为 class,那么这个 metaclass 就可以了——而且看起来不错。在其中使用 Colour
完全没有问题 - 没有“元 class 代码不能使用任何 'ordinary' class” - 它Python 代码照常。
我想说的是,也许您不需要将 Colours
用作 class,而只需创建 Colours
class ,具有您需要的所有功能,并创建它的单个实例。代码的其余部分将使用此实例而不是 Colors class.
是的,单个实例是“单例模式”——但与一些复杂的代码不同,您可以找到有关如何使 class“成为单例”的代码(包括一些广泛传播的关于需要元 class 在 Python 中有一个单例),您可以创建实例,将其分配给一个名称,然后完成它。就像在您的示例中一样,您拥有正在使用的“webcolors”对象。
对于额外的单例奖励,您可以将 Colors 的单个实例命名为 Colours
,并隐藏 class,以防止意外使用 class 而不是实例。
(而且,虽然这可能很明显,但为了完整起见:在“使用颜色作为实例”的情况下根本不需要这个元class - 相同的__getattr__
方法进入 class 主体)
当然,再说一遍,如果你把Colors用作class,这个设计是没有问题的。