[英]Mismatch between sys.executable and sys.version in Python
安裝了兩個Python解釋器:
[user@localhost ~]$ /usr/bin/python -V && /usr/local/bin/python -V
Python 2.4.3
Python 2.7.6
Sudo為其運行的每個命令更改PATH
,如下所示:
[user@localhost ~]$ env | grep PATH && sudo env | grep PATH
PATH=/usr/kerberos/bin:/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/home/user/bin
PATH=/usr/bin:/bin
我運行一個測試腳本:
[user@localhost ~]$ cat what_python.py
#!/usr/bin/env python
import sys
print sys.executable
print sys.version
[user@localhost ~]$ sudo python what_python.py
/usr/bin/python
2.7.6 (default, Feb 27 2014, 17:05:07)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-54)]
並獲取sys.executable
Python 2.4.3和sys.version
報告的版本2.7.6的路徑。 顯然sys.executable
和sys.version
不匹配。 考慮到sudo如何修改PATH,我可以理解sys.executable
的值。 但是,為什么sys.version
報告版本2.7.6而不是版本2.4.3,而該版本與sys.executable
報告的usr/bin/python
路徑sys.executable
?
這是我的問題的后續操作Sudo更改了PATH,但執行了相同的二進制文件
都@Graeme
python可能無法檢索到它的事實表明它正在做自己的PATH搜索(…)
和@twalberg
(...)看起來sys.executable會搜索當前的PATH而不是解析argv [0](或者可能是因為argv [0]在這種情況下是simpy python ...),(...)
基本上是正確的。 我不願意相信Python做的事情很簡單(愚蠢?),就像使用PATH
來定位自己一樣,但這是事實。
Python的sys
模塊在Python/sysmodule.c
文件中實現。 從版本2.7.6開始, sys.executable
在第1422行設置為:
SET_SYS_FROM_STRING("executable",
PyString_FromString(Py_GetProgramFullPath()));
從文件第701行開始,在文件Modules/getpath.c
定義了Py_GetProgramFullPath()
函數:
char *
Py_GetProgramFullPath(void)
{
if (!module_search_path)
calculate_path();
return progpath;
}
函數calcuate_path()
在同一文件中定義,並包含以下注釋 :
/* If there is no slash in the argv0 path, then we have to
* assume python is on the user's $PATH, since there's no
* other way to find a directory to start the search from. If
* $PATH isn't exported, you lose.
*/
從我的案例可以看出,當導出的$PATH
上的第一個Python與正在運行的Python不同時,也會丟失。
在getpath.c
文件的頂部可以找到有關計算解釋器可執行文件位置的更多信息:
在執行任何搜索之前,應確定可執行文件的位置。 如果argv [0]中包含一個或多個斜杠,則將其原樣使用。 否則,必須已經從外殼程序的路徑中調用了它,因此我們在$ PATH中搜索命名的可執行文件並使用它。 如果在$ PATH上找不到可執行文件(或沒有$ PATH環境變量),則使用原始argv [0]字符串。
接下來,檢查可執行位置以查看它是否是符號鏈接。 如果是這樣,則跟蹤鏈接(如果找到一個,則正確解釋相對路徑名),並使用鏈接目標的目錄。
讓我們進行一些測試以驗證以上內容:
如果argv [0]中包含一個或多個斜杠,則將其不變使用 。
[user@localhost ~]$ sudo /usr/local/bin/python what_python.py
/usr/local/bin/python
2.7.6 (default, Feb 27 2014, 17:05:07)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-54)]
好。
如果在$ PATH上找不到可執行文件(或沒有$ PATH環境變量),則使用原始argv [0]字符串。
[user@localhost ~]$ sudo PATH= python what_python.py
<empty line>
2.7.6 (default, Feb 27 2014, 17:05:07)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-54)]
錯誤。 在這種情況下,sys模塊文檔中的語句為true – 如果Python無法檢索其可執行文件的真實路徑,則sys.executable將為空字符串或None。 。
讓我們看看是否將python二進制文件的位置添加回PATH
(在sudo刪除它之后)是否解決了問題:
[user@localhost ~]$ sudo PATH=$PATH python what_python.py
/usr/local/bin/python
2.7.6 (default, Feb 27 2014, 17:05:07)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-54)]
是的
有關:
我認為/usr/local/bin/python
是正在運行的可執行文件。 幾乎可以肯定將version字符串編譯為python
,因此不太可能出錯。 查看sys.executable
的文檔:
可執行文件
一個字符串,給出有意義的系統上Python解釋器的可執行二進制文件的絕對路徑。 如果Python無法檢索其可執行文件的真實路徑,則sys.executable將為空字符串或無。
python
可能無法檢索到這一事實,表明它正在使用sudo設置的PATH
進行自己的PATH
搜索(根據我對上一個問題的回答,它與用於查找可執行文件的那個不相同)。
在這里可以確定的唯一方法是深入研究python實現,但是通常我會說版本字符串更可能是您可以信任的版本。 但是,另一方面, sudo
使用execve
執行命令(至少根據man
頁)。 您必須指定要執行的可執行文件的完整路徑(某些exec
變execve
執行其自己的PATH
搜索,而這不是)。 因此, python
填寫sys.executable
應該是毫無sys.executable
。
我不知道是否有任何方法可以獲取python
解釋器的實際argv[0]
( sys.argv[0]
始終是腳本或-c
的名稱),但這很有趣。 如果它是/usr/local/bin/python
,這將是python
的錯誤。
我認為最好的辦法就是在/etc/sudoers
設置secure_path
,希望這樣您將獲得一些一致性。
實際上execve
接受可執行路徑的參數,然后是argv
數組,因此argv[0]
不一定是/usr/local/bin/python
。 您仍然可以通過以下腳本找到它:
import time
time.sleep(60)
然后運行它並獲取ps
以提供完整的參數:
sudo python sleep.py &
ps -o args= -C python
另外,要確保正在運行哪個python
,您可以執行以下操作:
sudo ls -l /proc/PID/exe
在程序運行時。
每次啟動python解釋器時,shell都會轉到/ usr / bin / python並執行它(接下來嘗試:python -c“ import os; print(os.environ ['_'])”)。
那么,正如您所看到的自己ln -l | grep python
ln -l | grep python
/ usr / bin / python是python解釋器可執行文件的軟鏈接。
我所做的是:
configure && make && make install
) ln -s <location
上一個python版本可執行文件的ln -s <location
> / usr / bin / python ##(很可能需要sudo) sys.version ##應該是最后一個。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.