如何 "fool" 回避输入 Python

How to "fool" duck typing in Python

假设我有一个 class A:

 class A:

     def __init__(self, x, y):
         self.x = x
         self.y = y

     def sum(self):
         return self.x + self.y

然后我定义了一个名为 factory 的工厂方法:

def factory(x, y):

    class B: pass

    b = B()
    setattr(b, 'x', x)
    setattr(b, 'y', y)
    B.__name__ = 'A'
    return b

现在,如果我执行 print(type(A(1, 2)))print(type(factory(1, 2))),它们将显示它们是不同的类型。如果我尝试做 factory(1, 2).sum() 我会得到一个例外。但是,type(A).__name__type(factory(1, 2)).__name__ 是等效的,如果我这样做 A.sum(factory(1, 2)),我会得到 3,就像我使用 A 调用它一样。所以,我的问题是:

如果不在 B 上定义 sum 或不进行继承,我需要在这里做什么才能使 factory(1, 2).sum() 工作?

我认为您从根本上误解了工厂模式,并且可能对接口在 Python 中的工作方式感到困惑。要么,要么 I 从根本上对这个问题感到困惑。无论哪种方式,我们都需要做一些整理。

What would I need to do here to make factory(1, 2).sum() work without defining sum on B or doing inheritance?

只需 return 一个 A 而不是其他类型:

def factory(x, y):
    return A(x, y)

然后

print(factory(1,2).sum())

将按预期输出 3。但那是一个无用的工厂......可以做 A(x, y) 并完成它!

一些注意事项:

  1. 当您很容易地拥有 "nameable" 类型,而这些类型可能很难构造时,您通常会使用 "factory"(或工厂模式)。考虑一下当您使用 scipy.interpolate.interp1d(参见 here)时如何有一个 kind 的选项,它基本上是您可能用于进行插值的所有不同策略的枚举。这在本质上是一个工厂(但隐藏在函数内部以便于使用)。你可以想象这可能是独立的,所以你会调用你的 "strategy" 工厂,然后将它传递给 interp1d 调用。但是,内联是 Python 中的常见模式。观察:这些策略很容易"name",但一般来说有点难以构建(你可以想象必须传入一个进行线性插值的函数而不是只做kind='linear'会很烦人)。这就是工厂模式有用的原因...

  2. 如果你不知道前面的A是什么,那么它绝对不是你想要应用的工厂模式。此外,如果您不知道自己是什么 serializing/deserializing,则无法调用或使用它。你必须知道这一点,或者有一些推断它的方法。

  3. Python 中的接口 不是 像 Java/C++ 等其他语言中那样强制执行。这就是鸭子打字的精神。如果一个接口做了类似调用 x.sum() 的事情,那么 x 实际上是什么类型并不重要,它只需要有一个名为 sum() 的方法。如果它的行为像 "sum" 鸭子,叫声像 "sum" 鸭子,那么它 就是 来自 Python 的 "sum" 鸭子看法。 xnumpy 数组还是 A 都没有关系,它都可以正常工作。在 Java/C++ 中,像这样的东西 不会编译 除非编译器绝对确定 x 有方法 sum定义。幸运的是 Python 不是那样的,所以你甚至可以动态定义它(也许你正试图用 B 来做)。无论哪种方式,接口在 Python 中的概念与其他主流语言中的概念大不相同。

P.S。

But, type(A).__name__ and type(factory(1, 2)).__name__ are equivalent

课程中,当你说B.__name__ = 'A'时,你明确地这样做了。所以我不确定你想在那里得到什么...

HTH!