文章目录
前言
第一部分是扯淡内容,主要描述这个问题是怎么碰到的。(具体需求,lambda不行,只能使用partial)可以跳过。第二部分及之后描述的就是使用lambda和partial的使用情况,也是lambda和partial的区别。(内容少但很长。)最后一部分是个人吐槽。(完全没有内容。)
一、partial的一个应用场景(和pyqt5相关)
为了使得这部分内容便于理解,我会有所改动与我的实际情况有所不同。
我需要的一个界面大概长样
最上面有30个按键,按下一个按扭之后要求在最下方的label中显示对应的字符串之后多一个字符。
Backspace的作用是从末尾去掉一个字符,Clear的作用是直接清空。
(这里可以直接使用sender()函数完成。但是在这里的目的是为了区分lambda和partial的区别,所以我们就不使用sender()完成。)
下面是文件结构
其中ccutyear.ui是QT5直接生成的
ccutyear.py的内容如下:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ccutyear.ui'
#
# Created by: PyQt5 UI code generator 5.12
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(590, 512)
self.label = QtWidgets.QLabel(Form)
self.label.setGeometry(QtCore.QRect(20, 470, 551, 16))
self.label.setStyleSheet("background:rgb(170, 255, 255)")
self.label.setText("")
self.label.setObjectName("label")
self.gridLayoutWidget = QtWidgets.QWidget(Form)
self.gridLayoutWidget.setGeometry(QtCore.QRect(20, 10, 551, 391))
self.gridLayoutWidget.setObjectName("gridLayoutWidget")
self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setObjectName("gridLayout")
self.back_space = QtWidgets.QPushButton(Form)
self.back_space.setGeometry(QtCore.QRect(20, 430, 75, 23))
self.back_space.setObjectName("back_space")
self.clear = QtWidgets.QPushButton(Form)
self.clear.setGeometry(QtCore.QRect(500, 430, 75, 23))
self.clear.setObjectName("clear")
self.retranslateUi(Form)
self.back_space.clicked.connect(Form.label_back)
self.clear.clicked.connect(self.label.clear)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "ccutyear"))
self.back_space.setText(_translate("Form", "Backspace"))
self.clear.setText(_translate("Form", "Clear"))
main.py的内容如下
from PyQt5 import QtWidgets,QtGui,QtCore
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from functools import partial
from ccutyear import *
CHAR_SET_LEN = 30
CHAR_SET = "abcdefghijklmnopqrstuvwxyz ,.?"
CHAR_ROW = 5
CHAR_COL = 6
class Main(QWidget,Ui_Form):
def __init__(self, parent=None):
super().__init__()
self.setupUi(self)
print(self.gridLayoutWidget.width(),self.gridLayoutWidget.height())
self.push_button = [QtWidgets.QPushButton(self.gridLayoutWidget) for i in range(CHAR_SET_LEN)]
button_index = 0
for i in range(CHAR_ROW):
for j in range(CHAR_COL):
c = CHAR_SET[button_index]
self.push_button[button_index].setText(c)
self.gridLayout.addWidget(self.push_button[button_index],i,j,1,1)
'''-------------------------将在此处连接槽函数-------------------------------'''
#使用lambda
#self.push_button[button_index].clicked.connect(lambda : self.addChar(c))
#使用partial
#self.push_button[button_index].clicked.connect(partial(self.addChar,c))
'''-----------------------------------------------------------------------'''
button_index += 1
def label_back(self):
s = self.label.text()
self.label.setText(s[:-1])
def addChar(self,c):
s = self.label.text()
s += c
self.label.setText(s)
if __name__ == '__main__':
if __name__ == "__main__":
import sys
import time
app = QtWidgets.QApplication(sys.argv)
draw_window = Main()
draw_window.show()
sys.exit(app.exec_())
我们很容易就能理解,在连接槽函数的时候必然还需要向槽函数中一个参数表示在label中末尾添加的是什么字符。
二、使用lambda和partial的区别
1.使用lambda的情况
我们把main.py的第32行的注释去掉,结果在使用中了出现了这个情况。不论我点击的是哪个按扭最后在label中多出来的字符都是’?’。
我们在debug中发现,不管我们按的是哪个按扭传递进来的参数永远都是’?’。
2.使用partial的情况
我们把main.py的第35行的注释去掉,结果在使用中是这个情况。
可以看到这样就可以正常使用了。
分析
在这里的分析只是我自己理解,不算是官方答案。
1.使用lambda
我们首先可以看到在使用lambda的时候不论是哪个按扭接收得到的参数永远都是’?’。我们在debug模式下跑一遍就会看到在创建了30个按扭之后c这一个变量存储的值就是’?’。而在使用lambda的时候就是单纯的调用addChar这个函数,同时往函数中传递的是c(变量中的值是’?’)这个变量,且c的值是在经过__init__ 之后就没有改变过的。于是就会出现不论我们点的是哪个按扭,都会被视作为点击的是’?’。
2.使用partial
百度一下partial我们会知道partial是"冻结"一个函数的参数,并返回"冻结"参数后的新函数。
基于这一点我们可以这样理解在初始化创建按扭并且建立连接槽函数的时候使用的partial都会返回一个将参数c"冻结"后的函数。也就是说建立连接时c的参数是多少,那么在按下对应按扭时连接的槽函数中的参数就是多少并没有改变。
3.图解
这么写感觉是越写越晕,加个图解。希望我能表述明白。
总结
希望大家能看懂吧。如果我有哪里没有表述到位或者出错换地方可以留言,只要我看到了我一定就会修改的。
本来的我只是查到了可以使用lambda和partial向槽函数传递参数,也没想到在使用的时候凑巧踩到坑了。而且貌似很少有人会说明这两者之间还有这个区别。对大家来说可能使用的时候确实没有区别吧。另外,可能有人奇怪我为什么第一个不是想到使用sender()函数完成。其实,我在做的时候不知道有sender()函数这个函数。我是在写博客做例子的时候突然想到这个和计算器好像啊!于是一查才发现有sender()函数。(-_-|||)