我正在阅读python源代码:
https://hg.python.org/cpython/file/2.7/Lib/collections.py#l621
def __repr__(self):
if not self:
return '%s()' % self.__class__.__name__
items = ', '.join(map('%r: %r'.__mod__, self.most_common()))
return '%s({%s})' % (self.__class__.__name__, items)
形成文件:
operator.mod(a, b)
operator.__mod__(a, b)¶
Return a % b.
我认为这是对的,
但是为什么
'%r: %r'.__mod__
是正确的?
为什么字符串具有__mod__
__mod__
在Python中实现%
运算符的行为。对于字符串,%
运算符为overloaded,可为我们提供字符串格式设置选项。如果a % b
和a mod b
是数字,通常a
会强制对b
求值,对于字符串,我们可以更改%
的行为,以便a % b
实际上将b
的元素插入到a
如果a
是字符串。
运算符重载在Python中的工作方式是每个中缀运算符-+
,-
,*
,/
等(从Python 3.5开始,matrix multiplication operator @
)-对应到被调用的类的基本定义中的特定方法。例如,对于+
,它是__add__()
。对于%
,它是__mod__()
。我们可以通过在类中简单地重新定义这些方法来重载这些方法。
如果我有类Foo
,并且Foo
实现了成员函数__add__(self, other)
,则可能使Foo() + bar
的行为与+
的常规定义大不相同。
换句话说,字符串格式化技术
'%s: %s' % (5,2)
在Python中实际调用
'%s: %s'.__mod__((5,2))
在幕后,其中为属于类
__mod__
的对象定义了
string
。在这种情况下,为字符串产生
__mod__()
的方式只是
5: 2
,而不是
'%s : %s' mod (5,2)
的荒谬解释。
为什么在
__mod__
中而不在
map
中使用
__mod__()
在
map('%r: %r'.__mod__, self.most_common())
的特定情况下,正在发生的事情是函数指针(需要一个更好的词-请注意,Python没有指针,但是暂时以这种方式思考也无妨) >应用于
__mod__
中的每个元素,而不是函数
self.most_common()
。
这与
__mod__()
一样。我们没有传递函数调用
map(int, "52")
,而是以
int()
的形式传递了对该函数的引用,并期望该函数由
int
以及
map
的第二个参数调用。即
map
将在“ 52”的每个元素上调用。
正是由于这个原因,我们不能执行
int()
。函数
map('%r: %r'.__mod__(), self.most_common())
将在没有传入适当参数的情况下被调用并返回错误-我们想要的是对函数
'%r: %r'.__mod__()
的引用,而不是我们可以随时随地引用和调用,这是通过调用
__mod__()
完成的。
C ++类比
__mod__
与
__mod__
的行为实际上与C ++中的函数指针的工作方式没有什么不同:
__mod__()
的函数指针仅由
foo()
表示,即不带括号。类似的事情-但不完全相同-在这里发生。我在这里介绍它是因为它可以使区分更加清晰,因为从表面上看,指针看起来与正在发生的事情非常相似,而引入指针会导致一种相当熟悉的思维方式,足以满足此特定目的。
在C ++中,我们可以将函数指针传递给其他函数,并引入一种currying形式-例如,您可以通过另一个函数内部的常规
foo
语法在元素上调用函数指针。在Python中,我们没有指针-我们有包装器对象,这些包装器对象可以引用底层的内存位置(但可以防止对其进行原始访问)。但是,出于我们的目的,最终效果是相同的。 @Bukuriu探索了注释中的差异。
基本上,
foo()
强制执行不带参数的评估。
__mod__()
返回一个指向
__mod__
的指针,然后该指针可以被另一个函数在适当的参数上调用。在内部,这就是
__mod__()
的作用:获取一个函数指针(同样,这是一个类比),然后引用并在另一个元素上对其求值。
您可以自己看到:调用
map
返回
<method-wrapper '__mod__' of str object at 0x7f92ed464690>
即包装对象,该包装对象引用了该函数的内存地址。同时,调用
'%s'.__mod__
会返回错误:
TypeError: expected 1 arguments, got 0
因为多余的括号调用了
'%s'.__mod__()
的求值,但发现没有参数。
我是一名优秀的程序员,十分优秀!