2011-06-03 53 views
36

我想看看是否有任何需要最小化Python版本的方法。如何編寫能夠正確需要最小python版本的Python代碼?

由於新的異常處理(as關鍵字),我有幾個需要Python 2.6的Python模塊。

它看起來,即使我在我的腳本的開頭檢查python版本,代碼將無法運行,因爲解釋器將在模塊內部失敗,拋出一個醜陋的系統錯誤,而不是告訴用戶使用新的python 。

+0

另請參閱http://stackoverflow.com/questions/3035749/how-to-write-a-python-2-6-script-that-gracefully-fails-with-older-python和http:// stackoverflow .com/questions/388069/python-graceful-future-feature-future-import – 2011-06-03 08:50:07

+0

答案*您*接受http://stackoverflow.com/questions/3035749不使用新的異常處理。 – Johnsyweb 2011-06-03 09:31:57

+1

更新(2016年10月29日):現在setuptools和pip支持'python_requires'關鍵字到'setup'函數 - 請參閱我的[answer](http://stackoverflow.com/a/40300957/95735)。 – 2016-10-28 08:27:41

回答

8
import sys 
if sys.hexversion < 0x02060000: 
    sys.exit("Python 2.6 or newer is required to run this program.") 

import module_requiring_26 

而且這個涼爽的部分是,它可以包含在__init__文件或模塊內。

+2

您不希望在Python 3下運行腳本嗎? – 2011-06-03 09:04:11

+1

這是Walter Mundt的回答的劣質版本,在這之前已經發布。 – 2017-05-27 08:22:51

1

我猜你有這樣的:

import module_foo 
... 
import sys 
# check sys.version 

但module_foo需要一個特定的版本呢?既然如此,這是完全合法的。因此重新安排你的代碼:

import sys 
# check sys.version 
import module_foo 

Python並不需要進口,除了from __future__ import [something]在你的代碼的頂部。

33

您不應該在腳本本身內部使用任何Python 2.6功能。此外,在導入任何需要新Python版本的模塊之前,您必須先進行版本檢查。

E.g.啓動腳本,像這樣:

#!/usr/bin/env python 
import sys 

if sys.version_info[0] != 2 or sys.version_info[1] < 6: 
    print("This script requires Python version 2.6") 
    sys.exit(1) 

# rest of script, including real initial imports, here 
+2

+1。我在你的'print'中添加了一些括號,因爲否則就像Tim指出它會在Python 3中出現一個'SyntaxError'失敗(這是棘手的事情!)我認爲這是最正確的方法 - 我的方法更快,但是一點點黑客。 – 2011-06-03 10:37:19

+0

我不認爲它有必要在Python 3中工作。畢竟,Python 3通常不是與Python 2.x兼容的源代碼。由於需要分發幾乎任何東西的單獨Python 2.x和3.x版本,因此您可以完全退出Python 3.x版本。 – 2011-06-06 14:31:35

+1

即使嘗試使用_3.x_運行腳本,也可以優雅地退出,但除非_entire_腳本碰巧是be_syntactically_ valid 3.x,否則這將不起作用。 'print'不是打印錯誤消息的好選擇,因爲它默認打印到_stdout_;簡單的解決方案是使用'sys.exit(「這個腳本需要Python 2.x,> = 2.6」')(如在公認的答案中),它打印到_stderr_並且也用代碼1退出。在Windows上,當使用'pythonw.exe'調用時,您必須對錯誤進行額外處理才能顯示出來。) – mklement0 2015-08-15 21:44:04

14

(見本question也)我發現要做到這一點最簡單的方法就是加入這樣一行:在文件開始

b'You need Python 2.6 or later.' 

。這利用了字節文字是在2.6中引入的事實,因此任何早期版本都會使用您提供的任何消息作爲堆棧跟蹤來提升SyntaxError

如果您需要Python 2.7版,怎麼樣:

{'You need Python 2.7 or later.'} 

這是在2.6語法錯誤。

對於Python 2.5這應該工作:

'You need Python 2.5' if 'you want this to run or' else 'this line fails!' 

這是在2.4語法錯誤。

+14

雖然這很聰明,但它非常違背「顯式與隱式」規則。根據這樣的副作用,我感覺不對。從很多問題來看,許多終端用戶從不讀取堆棧跟蹤,只看到「哦,語法錯誤!程序必須被破壞!」 – 2011-06-03 09:03:03

+0

@Tim:哦,我同意這絕對是hacky,但它必須是。請記住,如果您的代碼使用新功能,那麼它將永遠不會編譯爲字節碼,因此您無法查詢sys.version_info等,因爲它不會運行!因此,您需要儘早趕上,向用戶提供稍好的信息。 – 2011-06-03 09:08:41

+0

......儘管像Walter Mundt的回答那樣拆分文件也是一種好方法。我的方法是一種快速和骯髒的方式來做到這一點,而不添加新的文件(加上它很有趣的想法了!) – 2011-06-03 09:21:34

1

而不是索引你總是可以做到這一點,

import platform 
if platform.python_version() not in ('2.6.6'): 
    raise RuntimeError('Not right version') 
+0

這是硬編碼的_specific_版本,而問題是關於_minimum_版本檢查。 – mklement0 2017-06-10 14:43:25

0

爲了補充現有的,有用的答案:

您可能需要編寫與兩個的Python 2.x的運行腳本 3.x要求最低版本爲每個。例如,如果您的代碼使用argparse模塊,則至少需要2.7(使用2.x Python)至少3.2(使用3.x Python)。

下面的代碼片段實現了這種檢查;唯一需要適應不同的但類似的情況是MIN_VERSION_PY2=...MIN_VERSION_PY3=...分配。

如前所述:這應該是放置在腳本的頂部,在任何其他import語句之前。

import sys 

MIN_VERSION_PY2 = (2, 7) # min. 2.x version as major, minor[, micro] tuple 
MIN_VERSION_PY3 = (3, 2) # min. 3.x version 

# This is generic code that uses the tuples defined above. 
if (sys.version_info[0] == 2 and sys.version_info < MIN_VERSION_PY2 
     or 
    sys.version_info[0] == 3 and sys.version_info < MIN_VERSION_PY3): 
     sys.exit(
     "ERROR: This script requires Python 2.x >= %s or Python 3.x >= %s;" 
     " you're running %s." % (
      '.'.join(map(str, MIN_VERSION_PY2)), 
      '.'.join(map(str, MIN_VERSION_PY3)), 
      '.'.join(map(str, sys.version_info)) 
     ) 
    ) 

如果版本不符合要求,像下面的消息被打印到stderr和腳本,退出代碼退出1.

This script requires Python 2.x >= 2.7 or Python 3.x >= 3.2; you're running 2.6.2.final.0. 

注:這是一個基本上改寫版本的一個早期的,不必要的複雜的答案,在實現之後 - 歸功於Arkady's helpful answer - 比較運算符(如>)可以直接應用於元組。

15

您可以利用的事實,元組進行比較時,Python會做正確的事情:

#!/usr/bin/python 
import sys 
MIN_PYTHON = (2, 6) 
if sys.version_info < MIN_PYTHON: 
    sys.exit("Python %s.%s or later is required.\n" % MIN_PYTHON) 
-1

我需要確保我使用Python 3.5(或最終導致更高)。我自己哼了一聲,然後我想問問SO - 但我沒有留下深刻印象的答案(對不起,你們都:: smile ::)。我沒有放棄,而是提出了下面的方法。我測試過的min_pythonmax_python規範元組的各種組合,它似乎很好地工作:

  • 把這個代碼放到一個__init__.py是有吸引力的:

    • 避免了污染許多模塊,冗餘版本檢查
    • 將它放在程序包層次結構的頂部,更進一步支持主體,假設整個層次結構遵守相同的Python版本contraints
    • 利用一個地方(文件),我可以使用最便攜的Python代碼(例如Python的1 ???)的檢查邏輯,仍然寫我真正模塊的代碼版本我想
    • 如果我不是「所有的Python版本曾經」兼容其它包初始化的東西,我可以鏟到另一個模塊,例如__init_p3__.py,如樣本註釋掉的最後一行所示。 不要忘記用適當的包裝名稱替換pkgname佔位符。
  • 如果你不想分鐘(或最大),只需將其設置爲=()

  • 如果你只關心主要版本,只需使用一個「一-PLE」,例如= (3,)不要忘了逗號,否則(3)只是一個括號(簡單)表達式計算到一個單一的int
  • 你可以不只是一個或兩個版本的水平,例如規定更細的最小/最大= (3, 4, 1)
  • 當max實際上不大於min時,只有一個「考慮運行」建議,或者是因爲max是一個空元組(或非元素)?或者元素較少。

注:我沒有太大的Windoze程序員,所以text_cmd_mintext_cmd_max價值取向爲* nix系統。如果您修復了代碼以在其他環境中工作(例如Windoze或某些特定的* Nix變體),請發佈。 (理想情況下,一個超級智能代碼塊將適用於所有環境,但我現在對我的* Nix唯一解決方案感到滿意。)

PS:我對Python有點新,我不喜歡沒有一個版本低於2.7.9.final.0的解釋器,所以測試我的代碼以獲得更早的變體是一件非常困難的事情。另一方面,有人真的在意嗎? (這是一個實際的問題,我有:在什麼(實際ISH)方面,我需要處理口譯的「優雅的錯誤,Python的版本」問題2.7.9之前?)

__init__。 PY

'''Verify the Python Interpreter version is in range required by this package''' 

min_python = (3, 5) 
max_python = (3,) 

import sys 

if (sys.version_info[:len(min_python)] < min_python) or (sys.version_info[:len(max_python)] > max_python): 

    text_have = '.'.join("%s" % n for n in sys.version_info) 
    text_min = '.'.join("%d" % n for n in min_python) if min_python else None 
    text_max = '.'.join("%d" % n for n in max_python) if max_python else None 

    text_cmd_min = 'python' + text_min + ' ' + " ".join("'%s'" % a for a in sys.argv) if min_python    else None 
    text_cmd_max = 'python' + text_max + ' ' + " ".join("'%s'" % a for a in sys.argv) if max_python > min_python else None 

    sys.stderr.write("Using Python version: " + text_have + "\n") 

    if min_python: sys.stderr.write(" - Min required: " + text_min + "\n") 
    if max_python: sys.stderr.write(" - Max allowed : " + text_max + "\n") 
    sys.stderr.write("\n") 

    sys.stderr.write("Consider running as:\n\n") 
    if text_cmd_min: sys.stderr.write(text_cmd_min + "\n") 
    if text_cmd_max: sys.stderr.write(text_cmd_max + "\n") 
    sys.stderr.write("\n") 

    sys.exit(9) 

# import pkgname.__init_p3__ 
11

與9.0.0版PIP在分配的元數據supportsRequires-Python字段,可以通過帶24-2-0版本setuptools的寫入開始。該功能可通過python_requires關鍵字參數獲得setup函數。

例(在setup.py):

setup(
... 
    python_requires='>=2.5,<2.7', 
... 

) 

要使用此功能一個具有第一包的項目/腳本如果還沒有的優勢。這在典型情況下非常簡單,並且應該儘可能完成,因爲它允許用戶輕鬆安裝,使用和卸載指定的項目/腳本。詳情請參閱Python Packaging User Guide

+0

自3月份以來的正確答案。 +1 – pelson 2017-07-08 14:06:47

+0

另一個參考:https://github.com/pypa/pip/issues/3182#issuecomment-289073930 – pelson 2017-07-08 14:07:02

相關問題