前言
最近打算逐渐熟悉一下 Python3 的语法效果,经过网上查找,如果在 Python2 中还原 Python3 的效果可以通过 __future__ 引入一些 Python3 的功能。
于是我就引入了from __future__ import unicode_literals,division,print_function
这一句。
unicode_literals 可以让 Python2 的字符串全部编程 unicode 模式,也就是所有字符串默认前面带 u 了,中文就不会变成乱码。
division 引入之后 Python2 的整数除法也可以输出浮点数了。
比如说1/2
默认输出是 0,因为 被除数不是浮点数 因此输出变整数了,以前我是通过float(1)/2
来解决这个问题,现在就可以通过 __future__ 来解决
print_function 引入之后就可以支持 Python3 的 print ,所以 print 的写法也要和 Python3 一样加括号。
这样 print 命令就可以直接嵌入到 lambda 函数里面,不引入的话 lambda 函数打印只能使用 sys.stdout.write
交代了一下背景,终于要扯出今天的主角 unicode_literals 的坑了。
setProperty 要设置 byte string
最近在开发 QMVVM 模块状态管理模块,使用 Qt 的 DynamicProperty 发现无法正确设置。
1 | # coding:utf-8 |
注: Qt 无法导入可以去 Github 下载兼容脚本
上面的代码就很清晰了,这背后可能也和 Qt 框架有关, Qt 可能不支持 Python unicode string
即便这里不引入 unicode_literals ,只是setProperty(u'test','hello')
这样设置也照样不行了。
signal 调用造成递归永动机
我觉得正常使用几乎不会遇到这个问题,碰巧我在开发 QMVVM 模块,所以用了一些比较偏门的方法来构造变量,结果引入 unicode_literals 出了大问题。
1 | # coding:utf-8 |
这里构建信号槽变量用了比较 tricky 的方法,因为 QMVVM 需要根据传入的字符串动态生成变量。
Python 的变量背后其实就是一个 locals 的字典来产生对应关系,可以通过 update 方法更新字典从而更新到本地变量里面。
当然除了这个方法之外 类里面 也可以使用 setattr 方法添加类属性,只不过用字典也方便我后面获取动态生成的变量。
后面 __init__ 函数里面 QMVVM 通过 getattr 根据字符串动态获取类属性,因此这里测试我也不直接 self.StateSignal 来获取了。
然后这里进行了套娃处理,两个信号槽,一个触发同时会触发另一个。
然后触发 信号槽 就会导致调用永动机从而报错了。
上面的代码就是我花了大半天调试精简出来的,在 QMVVM 内部的运行还是挺绕的,更何况一开始完全没有预料到问题出在 unicode_literals 里面 (:з」∠)
解决方案也不复杂,可以去掉 unicode_literals 或者构建信号槽的变量的时候给字符串加上 b’’ 转换为 byte string
总结
上面的代码测试我汇总到了 github 的仓库上 代码
后面我又测试不同版本的Python,发现 Python 2.7.16 版本已经解决了这个问题,但是 Python 2.7.14 还是出错, Maya 的 Python 2.7.11 也照样有问题。
Python 3.7.6 完全 OK ,所以可以相当肯定这个就是 Python2 的 BUG。
经过了这个坑之后,我还是不推荐使用 unicode_literals 了,毕竟中文乱码至少还可以运行,开了 unicode_literals 之后出问题的代价太大了。
更新 2020-5-7
在 Stack Overflow 上发现了类似的问题 链接
或许这真的是 Qt 的 Bug 而已,如果用起来方便的话还是可以考虑一下的。