“<<" left shift operator when assigning multiple values to QBarSet in PyQt

问题描述 投票:0回答:1

在下面链接的视频教程中,作者为 QBarSet 分配了多个值。

    set1 = QBarSet("Bob")
    set2 = QBarSet("Tom")

    set1 << 5 << 0 << 0 << 4 << 0 << 3
    set2 << 3 << 5 << 8 << 4 << 8 << 5

我不太明白“<<" . In python, this is a left shift operator. In c++ example (see the link), it was just like what is seen in the python code.

做了什么”

谁能解释一下什么是多个“<<" doing in this python code? Can python directly translate c++ code here?

@29:32

https://www.youtube.com/watch?v=p0xlfqBWrl8&t=822s

https://doc.qt.io/qt-6/qtcharts-barchart-example.html

python c++ qt pyqt6 pychart
1个回答
1
投票

tl;博士

在 Python 中,与 C++ 和许多其他语言一样,运算符可以并且经常被重写,以便从通常不支持它们的类中获得特殊行为。

PyQt(如 PySide)只是重写了 C++ API 中也被重写的运算符,以提供一致的语法。

当您使用

set0 << 1
时,您实际上并不是进行位移位,而是使用与 C++ 中重写运算符中发生的操作相同的操作,即将值附加到条形集合中。

说明

Python 并不“直接翻译 C++ 代码”。 Qt 绑定只是为了使其语法与官方 C++ API 一致而实现的。

具体来说,

<<
对应于
__lshift__
方法,这意味着如果您创建一个子类并重写该方法,结果是每当该类的实例后面跟着
<<
时,就会调用该重写使用以下对象,而不是使用默认的数字行为。

例如:

class Test(object):
    def __init__(self, value):
        self.value = value

    def __lshift__(self, other):
        # "other" is the object on the right hand of the operator
        return Test(int(str(self.value) + str(other.value)))

    def __repr__(self):
        return 'Test({})'.format(self.value)


>>> a = 2
>>> b = 3
>>> print(a << b) # same as 2 << 3
16
>>> a = Test(2)
>>> b = Test(3)
>>> print(a << b)
Test(23)
>>> c = Test(9)
>>> print(a << b << c)
Test(239)

上面的例子显然没有多大意义,但重写运算符是很常见的,以便提供语法糖,可以使语法更简洁,同时保持足够清晰。

巧合的是,最简单的例子是用于字符串连接的

+
运算符,上面的例子中也使用了它:文本显然不支持数学加法,但是
'a' + 'b'
可以工作,因为,在内部,
__add__
是重写以返回两个字符串的串联。

Python 实现中也存在类似情况,也涉及按位运算符,例如从 3.9 开始为

|
引入的
|=
dict

dict_a |= dict_b

(几乎)相当于:

dict_a.update(dict_b)

通常,特定运算符的使用遵循其实现背后的逻辑,就像上面的 dict 情况一样,或用于

set()
的类似运算符:为集合中的项目维护按位运算
|
&
的逻辑.

但有时,用法更“图形化”,就像手头的例子一样。例如,某些模块重写

>>
(
__rshift__
) 和其他运算符来创建“对象链”,这些对象比使用更详细的语法更容易编写和读取,例如创建一个以各种方式处理信号的过滤器链。返回结果之前的方法。

在Qt(C++)中,

&QBarSet::operator<<(const qreal &value)
将右手写的值附加到条形集合中(相当于
append()
<<
的含义主要是说“将一个值放入该对象”) ”.
Python 绑定只是通过覆盖该类的
__lshift__
并获得相同的行为来遵循相同的概念。

考虑完整语法之间的差异:

set0.append(1)
set0.append(2)
set0.append(3)
set0.append(4)
set0.append(5)
set0.append(6)

甚至更“优雅”的比如:

values = 1, 2, 3, 4, 5, 6
for v in values:
    set0.append(v)

以及以下语法,使用方便的运算符覆盖:

set0 << 1 << 2 << 3 << 4 << 5 << 6

即使不知道类和运算符的底层行为,语法仍然足够清晰。

许多其他 Qt 类都覆盖了运算符。例如,

QRect::operator|=(QRect)
相当于
united()
,它返回包含两个矩形的边界矩形:

full = QRect()
for other in listOfRectangles:
    full = full.united(other)
    # or
    full |= other

PyQt 还自己实现了一些运算符(其中许多在 PySide 中未使用)。例如,它

QRect.contains()
使用
__contains__
覆盖,这是有道理的,因为它是在使用语法
x in y
:

时调用的
p = QPoint(2, 5)
r = QRect(0, 0, 10, 10)
print(r.contains(p))
# equivalent to
print(p in r)

阅读有关 Python 数据模型和所有“神奇方法”(也称为 dunder 方法,如双下划线)的更多信息,并考虑并非所有 Qt 运算符在 Python 中始终可用,反之亦然(检查官方 Qt C++ API、PyQt/PySide 文档 交互式 Python shell 中的

help()
)。

© www.soinside.com 2019 - 2024. All rights reserved.