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