如何 "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)
并完成它!
一些注意事项:
当您很容易地拥有 "nameable" 类型,而这些类型可能很难构造时,您通常会使用 "factory"(或工厂模式)。考虑一下当您使用 scipy.interpolate.interp1d
(参见 here)时如何有一个 kind
的选项,它基本上是您可能用于进行插值的所有不同策略的枚举。这在本质上是一个工厂(但隐藏在函数内部以便于使用)。你可以想象这可能是独立的,所以你会调用你的 "strategy" 工厂,然后将它传递给 interp1d
调用。但是,内联是 Python 中的常见模式。观察:这些策略很容易"name",但一般来说有点难以构建(你可以想象必须传入一个进行线性插值的函数而不是只做kind='linear'
会很烦人)。这就是工厂模式有用的原因...
如果你不知道前面的A
是什么,那么它绝对不是你想要应用的工厂模式。此外,如果您不知道自己是什么 serializing/deserializing,则无法调用或使用它。你必须知道这一点,或者有一些推断它的方法。
Python 中的接口 不是 像 Java/C++ 等其他语言中那样强制执行。这就是鸭子打字的精神。如果一个接口做了类似调用 x.sum()
的事情,那么 x
实际上是什么类型并不重要,它只需要有一个名为 sum()
的方法。如果它的行为像 "sum" 鸭子,叫声像 "sum" 鸭子,那么它 就是 来自 Python 的 "sum" 鸭子看法。 x
是 numpy
数组还是 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!
假设我有一个 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)
并完成它!
一些注意事项:
当您很容易地拥有 "nameable" 类型,而这些类型可能很难构造时,您通常会使用 "factory"(或工厂模式)。考虑一下当您使用
scipy.interpolate.interp1d
(参见 here)时如何有一个kind
的选项,它基本上是您可能用于进行插值的所有不同策略的枚举。这在本质上是一个工厂(但隐藏在函数内部以便于使用)。你可以想象这可能是独立的,所以你会调用你的 "strategy" 工厂,然后将它传递给interp1d
调用。但是,内联是 Python 中的常见模式。观察:这些策略很容易"name",但一般来说有点难以构建(你可以想象必须传入一个进行线性插值的函数而不是只做kind='linear'
会很烦人)。这就是工厂模式有用的原因...如果你不知道前面的
A
是什么,那么它绝对不是你想要应用的工厂模式。此外,如果您不知道自己是什么 serializing/deserializing,则无法调用或使用它。你必须知道这一点,或者有一些推断它的方法。Python 中的接口 不是 像 Java/C++ 等其他语言中那样强制执行。这就是鸭子打字的精神。如果一个接口做了类似调用
x.sum()
的事情,那么x
实际上是什么类型并不重要,它只需要有一个名为sum()
的方法。如果它的行为像 "sum" 鸭子,叫声像 "sum" 鸭子,那么它 就是 来自 Python 的 "sum" 鸭子看法。x
是numpy
数组还是A
都没有关系,它都可以正常工作。在 Java/C++ 中,像这样的东西 不会编译 除非编译器绝对确定x
有方法sum
定义。幸运的是 Python 不是那样的,所以你甚至可以动态定义它(也许你正试图用B
来做)。无论哪种方式,接口在 Python 中的概念与其他主流语言中的概念大不相同。
P.S。
But,
type(A).__name__
andtype(factory(1, 2)).__name__
are equivalent
在课程中,当你说B.__name__ = 'A'
时,你明确地这样做了。所以我不确定你想在那里得到什么...
HTH!