簡體   English   中英

python中sys.executable和sys.version不匹配

[英]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.executablesys.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)]

是的

有關:

  • Python問題7774 – sys.executable:如果修改了第零個命令參數,則位置錯誤。
  • Python問題10835 – sys.executable默認值和altinstall
  • python-dev郵件列表線程 –針對sys.executable的更嚴格定義
  • Stackoverflow 問題 –如何在C中找到可執行文件的位置

我認為/usr/local/bin/python是正在運行的可執行文件。 幾乎可以肯定將version字符串編譯為python ,因此不太可能出錯。 查看sys.executable的文檔:

可執行文件

一個字符串,給出有意義的系統上Python解釋器的可執行二進制文件的絕對路徑。 如果Python無法檢索其可執行文件的真實路徑,則sys.executable將為空字符串或無。

python可能無法檢索到這一事實,表明它正在使用sudo設置的PATH進行自己的PATH搜索(根據我對上一個問題的回答,它與用於查找可執行文件的那個不相同)。

在這里可以確定的唯一方法是深入研究python實現,但是通常我會說版本字符串更可能是您可以信任的版本。 但是,另一方面, sudo使用execve執行命令(至少根據man頁)。 您必須指定要執行的可執行文件的完整路徑(某些execexecve執行其自己的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解釋器可執行文件的軟鏈接。

我所做的是:

  1. 安裝python的最新版本(轉到python的網站,下載最新的代碼並configure && make && make install
  2. 檢查此最新版本可執行文件的位置。
  3. 擦除/ usr / bin / python軟鏈接##(您將需要root權限sudo)
  4. ln -s <location上一個python版本可執行文件的ln -s <location > / usr / bin / python ##(很可能需要sudo)
  5. 從命令行執行python。
  6. 導入系統

sys.version ##應該是最后一個。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM