12

我一直在阅读描述类继承、抽象基类甚至 python 接口的文档。但没有什么接缝正是我想要的。即,一种构建虚拟类的简单方法。当调用虚拟类时,我希望它根据给定的参数实例化一些更具体的类,并将其交还给调用函数。现在,我有一个总结方法,可以将对虚拟类的调用重新路由到底层类。

思路如下:

class Shape:
    def __init__(self, description):
        if   description == "It's flat":  self.underlying_class = Line(description)
        elif description == "It's spiky": self.underlying_class = Triangle(description)
        elif description == "It's big":   self.underlying_class = Rectangle(description)
    def number_of_edges(self, parameters):
        return self.underlying_class(parameters)

class Line:
    def __init__(self, description):
        self.desc = description
    def number_of_edges(self, parameters):
        return 1

class Triangle:
    def __init__(self, description):
        self.desc = description
    def number_of_edges(self, parameters):
        return 3

class Rectangle:
    def __init__(self, description):
        self.desc = description
    def number_of_edges(self, parameters):
        return 4

shape_dont_know_what_it_is = Shape("It's big")
shape_dont_know_what_it_is.number_of_edges(parameters)

我的重新路由远非最佳,因为仅传递对 number_of_edges() 函数的调用。将这样的东西添加到 Shape 也不能达到目的:

def __getattr__(self, *args):
    return underlying_class.__getattr__(*args)

我做错了什么?整个想法实施得不好?非常感谢任何帮助。

4

4 回答 4

18

我同意TooAngel的观点,但我会使用__new__ 方法

class Shape(object):
    def __new__(cls, *args, **kwargs):
        if cls is Shape:                            # <-- required because Line's
            description, args = args[0], args[1:]   #     __new__ method is the
            if description == "It's flat":          #     same as Shape's
                new_cls = Line
            else:
                raise ValueError("Invalid description: {}.".format(description))
        else:
            new_cls = cls
        return super(Shape, cls).__new__(new_cls, *args, **kwargs)

    def number_of_edges(self):
        return "A shape can have many edges…"

class Line(Shape):
    def number_of_edges(self):
        return 1

class SomeShape(Shape):
    pass

>>> l1 = Shape("It's flat")
>>> l1.number_of_edges()
1
>>> l2 = Line()
>>> l2.number_of_edges()
1
>>> u = SomeShape()
>>> u.number_of_edges()
'A shape can have many edges…'
>>> s = Shape("Hexagon")
ValueError: Invalid description: Hexagon.
于 2010-06-19T18:03:21.620 回答
15

我宁愿在工厂做这件事:

def factory(description):
    if   description == "It's flat":  return Line(description)
    elif description == "It's spiky": return Triangle(description)
    elif description == "It's big":   return Rectangle(description)

或者:

def factory(description):
    classDict = {"It's flat":Line("It's flat"), "It's spiky":Triangle("It's spiky"), "It's big":Rectangle("It's big")}
    return classDict[description]

并从 Shape 继承类

class Line(Shape):
    def __init__(self, description):
        self.desc = description
    def number_of_edges(self, parameters):
        return 1
于 2010-06-19T17:39:46.813 回答
1

Python 没有开箱即用的虚拟类。您必须自己实现它们(应该有可能,Python 的反射功能应该足够强大,可以让您做到这一点)。

但是,如果您需要虚拟课程,那么为什么不直接使用具有虚拟课程的编程语言,例如 Beta、gBeta 或 Newspeak?(顺便说一句:还有其他人吗?)

但是,在这种特殊情况下,我并没有真正看到虚拟类如何简化您的解决方案,至少在您给出的示例中没有。也许您可以详细说明为什么您认为需要虚拟课程?

不要误会我的意思:我喜欢虚拟课程,但事实上只有三种语言实现了它们,这三种语言中只有一种仍然存在,而这三种语言中恰好有 0 种被任何人实际使用,这有点说明......

于 2010-06-19T17:55:56.900 回答
0

您可以使用 更改类object.__class__,但最好只创建一个返回任意类实例的函数。

另一方面,object除非你使用 Python 3,否则所有类都应该继承自,否则你最终会得到一个旧式类:

class A(object):
    pass
于 2010-06-19T17:46:29.853 回答