专栏首页Crossin的编程教室Python 中的神秘运算符

Python 中的神秘运算符

今天我们来讲讲 Python 里一个不为众人所知的运算符。你可能会觉得疑惑:还有我不知道的运算符?别急着下结论,先往下看看再说。

在 Python3.5 中通过 PEP465

(https://www.python.org/dev/peps/pep-0465)加入了 @运算符,也就是矩阵相乘运算符。虽然目前没有任何内置的 Python 类型实现了这个运算符的逻辑(就只是挖了个坑),但是如果你用过 numpy,大概对这个运算符的逻辑并不陌生:

>>> a = numpy.array([1, 2, 3])
>>> b = numpy.array([10, 20, 30])
>>> a @ b
140
>>> c = numpy.array([[10, 15], [20, 25], [30, 35]])
>>> d = numpy.array([[4, 5, 6], [7, 8, 9]])
>>> c @ d
array([[145, 170, 195],
       [255, 300, 345],
       [365, 430, 495]])

如今,在原生的 Python 代码中,你也可以使用这个运算符。但前提是,你得自己实现具体的运算规则,也就是实现 __matmul__()__rmatmul__() __imatmul__() 这3个方法。

在看实例之前,我们先来了解下这种特殊的类方法。

在官方文档中,我们看到与 __matmul__ 方法一起介绍的还有 __add____sub__ 等等(注意前后都是2个下划线),这些方法都是用来定义此类型的运算符号。

假设现在有一个类叫 A,我们在其 class 中实现了加法方法 __add__

def __add__(self, value):
    # 具体实现代码(略)

那么我们就可以在代码中对 A 的实例进行加法运算:

a = A()
b = A()
c = a + b

此种情况下,__add__ 函数会被调用,self 对应的是 a 变量,而 value 对应的则是 b 变量。

__matmul__ 与之类似,唯一的不同就是它会在使用 @ 操作符而不是 + 时被调用。

同样的道理,__rmatmul__ 对应操作数不支持相关运算或者类型不同的情况,__imatmul__ 则对应复合赋值运算符的情况:

a = A()
b = A()
c = a @ b  # __matmul__
d = a @ 1  # __rmatmul__
a @= 1  #__imatmul__

接下来我们来创建一个继承 list 的类并实现矩阵乘法:

class NewList(list):
    def __matmul__(self, v):
        result = []
        for i in range(len(self)):
            result.append([])
            for j in range(len(v[0])):
                result[i].append(0)

        for i in range(len(self)):
            for j in range(len(v[0])):
                for k in range(len(v)):
                    result[i][j] += self[i][k] * v[k][j]
        return result

# 测试
x = NewList([[7, 7, 3],
    [4, 5, 6],
    [6, 4, 3]])

y = NewList([[5, 4, 1, 2],
    [6, 2, 3, 0],
    [4, 5, 6, 1]])

z = x @ y
for i in z:
    print(i)

输出结果:

[89, 57, 46, 17]
[74, 56, 55, 14]
[66, 47, 36, 15]

虽然这个符号的设定是用于矩阵乘法,但实际上可以自定义为任何操作。比如我们可以用它来计算直角坐标系上两个点之间的距离

from math import sqrt

class Point:
    def __init__(self, x, y):
        self.x = x   # x坐标
        self.y = y   # y坐标

    def __matmul__(self, value):
        x_sub = self.x - value.x
        y_sub = self.y - value.y
        return sqrt(x_sub**2 + y_sub**2)

a = Point(1, 3)
b = Point(4, 7)
print(a @ b)

以上便是我今天跟大家分享的 Python 神秘操作符。

注:本文来自编程教室的读者 @pynickle 即将发布的 GitChat 的一部分。此次 GitChat 中,他将会介绍一些 Python 的冷知识(但不适合零基础小白,明天截止预订),如果你感兴趣的话,欢迎加入一起讨论交流。

(点击文末 阅读原文 可直达)

作者:pynickle


本文分享自微信公众号 - Crossin的编程教室(crossincode),作者:pynickle

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-12-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 用 Python 跟自己下棋

    今天,李世乭终于在与 AlphaGo 的人机大战中扳回一局。但计算机 AI 可以在围棋上战胜人类顶尖棋手的时代已经到来。可以预见,人工智能和机器人将会在更多领域...

    Crossin先生
  • #PY小贴士# 别弄错了 Python 里的这几个运算符

    会出现这样问题的同学,多半是之前用过其他的编程语言,所以习惯性地认为 ^ 是表示次方,& 是表示逻辑与(同时满足条件)、| 是表示逻辑或(满足条件之一)。

    Crossin先生
  • 【Python 第35课】 continue

    break是彻底地跳出循环,而continue只是略过本次循环的余下内容,直接进入下一次循环。 在我们前面写的那个统计分数的程序里,如果发现有成绩不足60分,...

    Crossin先生
  • JavaScript中的比较运算符

    最后一个null >= 0的结果为true。 刚看到这个代码的时候,下意识地会认为结果应该也是false,毕竟上边标明了三种情况都为false。 然而这个就露出...

    贾顺名
  • JavaScript中的比较运算符

    JavaScript中的比较运算符 JavaScript中的比较运算符粗略的可以分为两种: 相等运算符(==、===、!==)这些 ...

    贾顺名
  • 《挑战30天C++入门极限》C++运算符重载赋值运算符

    landv
  • [linux][network]ICMP协议分析

    前言: ICMP比较基础,说简单不简单,说难不难。 简单在于字段少,不能携带用户数据,没什么地方可以玩出太多花样;一般和它相关的就是ping和tracerout...

    皮振伟
  • Dimple在左耳听风ARTS打卡(二十)

    今天的内容干货满满,还烦请大家仔细观看。首先真是一个值得纪念的日子,历时5个月,终于把《Head First设计模式》这本书给二刷完成了。想起第一次看的时候,也...

    程序员小跃
  • 视觉问答:VQA经典模型Up-Down以及VQA 2017challenge 冠军方案解读

    DeepAction七期飞跃计划还剩3个名额,联系小编,获取你的专属算法工程师学习计划(联系小编SIGAI_NO1)

    SIGAI学习与实践平台
  • [翻译]CentOS7 下Samba 服务器搭建1

    [翻译前]:严格来说,这篇文章不算翻译,因为不算是全盘直接翻译的。而是加入了自己的理解的。当然时间有限,也就弄了个匿名的(也就是不需要密码的。)如果英文够好,可...

    用户2353021

扫码关注云+社区

领取腾讯云代金券