Python 常见问题总结
1 错误:No module named '_tkinter'
如果在使用类似 matplotlib 库时遇到如下错误:
1 2 3 4 |
import tkinter
File "/usr/local/lib/python3.6/tkinter/__init__.py", line 36, in <module>
import _tkinter # If this fails your Python may not be configured for Tk
ModuleNotFoundError: No module named '_tkinter' |
因为事实上 tkinter 并不是一个第三方库,而是 Python 的内置接口类,并不能使用 pip3 来进行安装。
可尝试使用以下方法解决:
1)安装 python-tk 和 tk-dev 库:
1 2 |
sudo apt install python3-tk
sudo apt install tk-dev |
2)重新编译 Python 3.6.5:
进入 Python 3.6.5 源码目录,运行如下命令:
1 2 3 4 |
make clean
./configure
make -j8
sudo make install |
3)如果正确安装则可以运行:
1 |
import tkinter |
2 错误:ModuleNotFoundError: No module named 'pandas'
在安装 Python 3.6 以后可能会遇到如下问题:
1 2 3 4 |
Traceback (most recent call last):
File "dataset.py", line 4, in <module>
import pandas as pd
ModuleNotFoundError: No module named 'pandas' |
通常情况下只需要运行:
1 2 |
pip3 install wheel
pip3 install pandas |
不过在 Python 3.6 时,如果你之前装了其他版本比如 3.5 版本的 Python,可能运行后直接安装到 Python 3.5 的目录下,3.6 仍然没有安装。这时可以使用以下命令安装在指定版本上:
1 |
sudo python3.6 -m pip install pandas |
3 错误:_tkinter.TclError: couldn't connect to display "localhost:11.0"
如果在使用 SSH 远端调用 matlibplot 等显示界面时遇到如下错误:
1 2 3 4 5 |
File "/usr/local/lib/python3.5/site-packages/matplotlib/backends/_backend_tk.py", line 1046, in new_figure_manager_given_figure
window = Tk.Tk(className="matplotlib")
File "/usr/lib/python3.5/tkinter/__init__.py", line 1871, in __init__
self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
_tkinter.TclError: couldn't connect to display "localhost:11.0" |
可能有几个问题,请检查:
1)SSH 连接方式,请使用 -X 参数:
ssh -X user@webserver.com
2)MacOS 请安装 XQuartz 后重启再尝试(参见[2])。
4 子目录 import 根目录路径
如果你的在子目录有一个 python 脚本,类似 tests/test.py 希望 import 根目录的 load_data.py ,一个可行的方法就是在 test.py 文件头部加入:
1 2 |
import sys
sys.path.append('./') |
然后正常 import 方式类似:
1 |
from load_data import SparseDataset |
运行时在根目录运行:
1 |
python tests/test.py |
5 处理多进程 apply_async 中的 error
在使用 apply_async 函数进行异步多线程处理时,如果线程内部报错,在主线程中是不会显示的,这样会给调试带来很大不便。一个较好的方式是使用其 error_callback 参数获取错误并进行处理(显示调用栈等)。
方法如下:
定义 error_handler 函数:
1 2 3 4 |
def error_handler(e):
print('error')
print(dir(e), "\n")
print("-->{}<--".format(e.__cause__)) |
将其作为参数传入:
1 2 3 4 5 6 |
my_pool.apply_async(
do_stuff,
args=(i,),
callback=success_handler,
error_callback=error_handler
) |
报错时会输出如下类似信息:
1 2 3 4 5 6 7 8 9 10 11 12 | error ['__cause__', '__class__', '__context__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__suppress_context__', '__traceback__', 'args', 'with_traceback']
-->
""" Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/multiprocessing/pool.py", line 119, in worker result = (True, func(*args, **kwds))
File "1.py", line 10, in do_stuff result = 5/(2 - num) #Line 9 ZeroDivisionError: division by zero
"""<-- |
参考 [3]
6 处理多进程中的通信
在 Python 中如果想要在进程之间共享变量,使用 global 全局变量或者变量域的方式并不太可行[4]。比如如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
from multiprocessing import Pool
final_list = []
input_list_one = ['one', 'two', 'three', 'four', 'five']
input_list_two = ['six', 'seven', 'eight', 'nine', 'ten']
def worker(data):
for item in data:
final_list.append(item)
with Pool(processes=2) as pool:
pool.apply_async(worker, args=[input_list_one])
pool.apply_async(worker, args=[input_list_two])
pool.close()
pool.join()
print(final_list) |
实际上输出是空:
1 |
[] |
而我们想要的是能够连接两个 list 的输出。一个比较好的方法是使用 Manager 来管理进程间的变量,声明变量时使用 Manager 中的相应函数,只需简单修改成如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
from multiprocessing import Pool, Manager
manager = Manager()
final_list = manager.list()
input_list_one = ['one', 'two', 'three', 'four', 'five']
input_list_two = ['six', 'seven', 'eight', 'nine', 'ten']
def worker(data):
for item in data:
final_list.append(item)
with Pool(processes=2) as pool:
pool.apply_async(worker, args=[input_list_one])
pool.apply_async(worker, args=[input_list_two])
pool.close()
pool.join()
print(final_list) |
再次运行输出就变成了:
1 |
['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten'] |
这就是我们想要的输出了。
当然 Manager 不仅可以定义 list 还有很多变量类型例如:
list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Barrier, Queue, Value and Array
我们可以进行想要的定义。
7 正确提前终止 Pool 中的多进程
在使用多进程并发时,如果想要在某个进程内部提前终止所有进程,一个比较好的方法是使用 Manager 中的 Event 来进行控制。
一个典型示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import multiprocessing
def myfunction(i, event):
print('Start {}'.format(i))
if not event.is_set():
print('End {}'.format(i))
if i == 20:
event.set()
# p.terminate()
if __name__ == "__main__":
p= multiprocessing.Pool(10)
m = multiprocessing.Manager()
event = m.Event()
for i in range(100):
p.apply_async(myfunction, (i, event))
p.close()
event.wait() # We'll block here until a worker calls `event.set()`
p.terminate() # Terminate all processes in the Pool |
在上述例子中,我们没有使用通常使用的 p.join() 而是用 event.wait() 。这一函数的目的是在没有产生 event.set() 调用之前运行当前 pool 中的所有 worker,当你触发停止条件时,只需调用 event.set() 则整个 pool 中的 Process 都被停止,最后只需调用 p.terminate() 终止所有进程即可。
8 在 main 函数中正确退出整个程序
在 main 函数中退出整个程序较好的方式是使用 SystemExit。
一个示例如下:
1 2 |
if is_all_finished():
raise SystemExit(0) |
9 错误 zipfile.BadZipfile: Truncated file header
出现上述错误如果排除 zip 文件损坏情况,可以考虑是不是有多线程冲突。因为 zipfile 是非线程安全的,如果再多线程中使用,应该加锁。
10 Python 中多文件全局变量的实现
首先创建如下文件并保存为 global_var.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # -*- coding: utf-8 -*- #全局变量使用
def _init(): # 初始化
global _global_dict
_global_dict = {}
def set_value(key, value=None):
""" 定义一个全局变量 """
_global_dict[key] = value
def get_value(key, defValue=None):
""" 获得一个全局变量,不存在则返回默认值 """
try:
return _global_dict[key]
except KeyError:
return defValue |
使用方法如下,其中 gvar._init_() 只需要在 main 函数中调用一次即可:
1 2 3 4 5 6 |
import global_var as gvar
gvar._init_()
gvar.set_value("a",1)
value=gvar.get_value('a')
print(value) |
11 Python 中字符串相等判断
在 Python 中判断两个变量是否相等可以用 == 或者 is,但是判断字符串是否相等 只能用 ==。
例如下面的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
test = 'aa.bb'.split('.')[0]
print(test)
print(test == 'aa')
print(test == 'bb')
print(test != 'aa')
print(test != 'bb')
print(test is 'aa')
print(test is 'bb')
print(test is not 'aa')
print(test is not 'bb') |
其输出为:
1 2 3 4 5 6 7 8 9 | aa True False False True False False True True |
可见采用 is 判断字符串是否相同时就出现了错误。
其原因是,对于 is 来说判断的是二者是不是同一个对象,比如相同的字符串是同一个对象,例如都是 'aa',但如果不同的字符串就不是同一个对象,即使而这内容相等,例如 'aa.bb' 中前两个字节的 'aa' 与字符串 'aa' 显然不是同一个对象,但二者内容实际上是相等的。例如如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
test = 'aa'
print(test)
print(test == 'aa')
print(test == 'bb')
print(test != 'aa')
print(test != 'bb')
print(test is 'aa')
print(test is 'bb')
print(test is not 'aa')
print(test is not 'bb') |
其输出就为:
1 2 3 4 5 6 7 8 9 | aa True False False True True False False True |
参考文献
[1] https://blog.csdn.net/blueheart20/article/details/78763208
[2] https://wikis.nyu.edu/display/ADRC/Enable+X11+Forwarding+on+Mac+OS+X
[3] https://stackoverflow.com/questions/28595234/python3-how-to-find-out-which-line-in-apply-async-target-function-caused-error-w
[4] https://blog.ruanbekker.com/blog/2019/02/19/sharing-global-variables-in-python-using-multiprocessing/
[5] https://blog.csdn.net/qq_41037945/article/details/104365445
[6] http://www.download2me.com/article/396304.html
consists of the book itself