少なくとも特定のバージョンのPythonを必要とするPythonスクリプトを使用している場合、以前のバージョンのPythonを使用してスクリプトを起動したときに正しく失敗するための正しい方法は何ですか?
エラーメッセージを発行して終了するのに十分なほど早く制御を取得するにはどうすればよいですか。
たとえば、ternery演算子(2.5の新機能)と "with"ブロック(2.6の新機能)を使用するプログラムがあります。私は、スクリプトが最初に呼び出すであろう単純なインタプリタ - バージョンチェッカールーチンを書きました…それがそれをそれほど遠くに得ないことを除いて。代わりに、スクリプトは私のルーチンが呼ばれる前でさえも、Pythonのコンパイル中に失敗します。そのため、スクリプトのユーザーには非常にあいまいなシナックスエラーのトレースバックが見られます。これは、単に間違ったバージョンのPythonを実行した場合であることを専門家に推測させる必要があります。
私はPythonのバージョンをチェックする方法を知っています。問題は、一部の構文が古いバージョンのPythonでは違法であることです。このプログラムを考えてください。
import sys
if sys.version_info < (2, 4):
raise "must use python 2.5 or greater"
else:
# syntax error in 2.4, ok in 2.5
x = 1 if True else 2
print x
2.4で実行したとき、私はこの結果が欲しい
$ ~/bin/python2.4 tern.py
must use python 2.5 or greater
そしてこの結果ではない:
$ ~/bin/python2.4 tern.py
File "tern.py", line 5
x = 1 if True else 2
^
SyntaxError: invalid syntax
(同僚のためのチャネリング)
eval
を使ってテストできます。
try:
eval("1 if True else 2")
except SyntaxError:
# doesn't have ternary
また、with
isはPython 2.5で利用可能です。ただfrom __future__ import with_statement
を追加するだけです。
編集:十分に早く制御を取得するには、インポートする前にそれを異なる.py
ファイルに分割し、メインファイルで互換性をチェックすることができます(例:パッケージの__init__.py
)。
# __init__.py
# Check compatibility
try:
eval("1 if True else 2")
except SyntaxError:
raise ImportError("requires ternary support")
# import from another module
from impl import *
次のことを行うプログラムのラッパーを用意してください。
import sys
req_version = (2,5)
cur_version = sys.version_info
if cur_version >= req_version:
import myApp
myApp.run()
else:
print "Your Python interpreter is too old. Please consider upgrading."
2.0より前のPythonインタプリタを使っている人と出会う予定があるなら、sys.version()
の使用を検討することもできますが、その場合はいくつかの正規表現を使用する必要があります。
そして、これを行うためのもっとエレガントな方法があるかもしれません。
やってみる
import platform platform.python_version()
あなたに "2.3.1"のような文字列を与えるべきです。これが正確ではない場合は、「プラットフォーム」ビルトインを通じて利用可能な豊富なデータセットがあります。あなたが欲しいものはどこかにそこにあるべきです。
おそらくこのバージョン比較をするための最善の方法はsys.hexversion
を使うことです。バージョンタプルを比較してもすべてのPythonバージョンで望ましい結果が得られるとは限らないため、これは重要です。
import sys
if sys.hexversion < 0x02060000:
print "yep!"
else:
print "oops!"
import sys
# prints whether python is version 3 or not
python_version = sys.version_info.major
if python_version == 3:
print("is python 3")
else:
print("not python 3")
Nykakinからの返事 AskUbunt :
標準ライブラリのplatform
モジュールを使ってコードからPythonのバージョンをチェックすることもできます。
機能は2つあります。
platform.python_version()
(文字列を返します).platform.python_version_Tuple()
(Tupleを返します)。たとえばファイルを作成します。
version.py
)
バージョンを確認する簡単な方法:
import platform
print(platform.python_version())
print(platform.python_version_Tuple())
eval
メソッドを使用することもできます。
try:
eval("1 if True else 2")
except SyntaxError:
raise ImportError("requires ternary support")
Pythonファイルをコマンドラインで実行します。
$ python version.py
2.7.11
('2', '7', '11')
Windows 10上のWAMPサーバを介したCGI付きPythonの出力:
質問は:エラーメッセージを出して終了するのに十分なほど早く制御を取得するにはどうすればよいですか?
私が答える質問は次のとおりです。アプリを起動する前にエラーメッセージを発行するのに十分早く制御を取得するにはどうすればよいですか?
私は他の記事とはかなり違った答えをすることができます。今のところ答えはPythonの中からあなたの質問を解決しようとしているようです。
私は、Pythonを起動する前にバージョンチェックを行います。私はあなたの道はLinuxかunixだと思います。しかし、私はあなたにはWindowsスクリプトしか提供できません。私はそれをLinuxスクリプティング構文に適応させることはそれほど難しくないでしょう。
これがバージョン2.7のDOSスクリプトです。
@ECHO OFF
REM see http://ss64.com/nt/for_f.html
FOR /F "tokens=1,2" %%G IN ('"python.exe -V 2>&1"') DO ECHO %%H | find "2.7" > Nul
IF NOT ErrorLevel 1 GOTO Python27
ECHO must use python2.7 or greater
GOTO EOF
:Python27
python.exe tern.py
GOTO EOF
:EOF
これはアプリケーションのどの部分も実行しないので、Pythonの例外は発生しません。一時ファイルを作成したり、OS環境変数を追加したりすることはありません。また、バージョンの構文規則が異なるためにアプリが例外に終わることはありません。それは3つの可能性が低いアクセスのセキュリティポイントです。
FOR /F
行が重要です。
FOR /F "tokens=1,2" %%G IN ('"python.exe -V 2>&1"') DO ECHO %%H | find "2.7" > Nul
複数のPythonバージョンをチェックするには、URLをチェックしてください。 http://www.fpschultze.de/modules/smartfaq/faq.php?faqid=17
そして私のハックバージョン:
[MSスクリプト; PythonバージョンチェックPythonモジュールの発売開始] http://Pastebin.com/aAuJ91FQ
後方互換性を保つために、セットはPython 2.4のコア言語の一部となりました。当時私はこれをしました。これはあなたにとってもうまくいくでしょう。
if sys.version_info < (2, 4):
from sets import Set as set
import sys
sys.version
このような答えを得ているでしょう
'2.7.6(デフォルト、2016年10月26日、20:30:19)\ n [GCC 4.8.4]
こちら2.7.6はバージョンです
前述のように、構文エラーは実行時ではなくコンパイル時に発生します。 Pythonは「インタプリタ言語」ですが、Pythonコードは実際には直接解釈されません。それはバイトコードにコンパイルされ、それが解釈されます。モジュールがインポートされたとき(コンパイル済みのバージョンが.pycまたは.pydファイルの形式で利用可能でない場合)にコンパイルステップがあります。あなたのコードは実行中です。
上記のように、evalを使用することで、コンパイル時のステップを延期して実行時に1行のコードで実行することができますが、これを避けることをお勧めします。不必要な実行時コンパイルは、ある理由では、そして別の理由では、コードが散らかっているように感じます。 (望むなら、コードを生成するコードを生成するコードを生成することができます - そして今から6か月以内にそれを修正しデバッグするのに絶対に素晴らしい時間を過ごすことができます。)
import sys
if sys.hexversion < 0x02060000:
from my_module_2_5 import thisFunc, thatFunc, theOtherFunc
else:
from my_module import thisFunc, thatFunc, theOtherFunc
..これは、新しい構文を使用する関数が1つしかなく、それが非常に短かったとしても実行します。 (実際、私はそのような関数の数とサイズを最小にするためにあらゆる合理的な手段をとるでしょう。その中にその単一の構文の行を持つifTrueAElseB(cond、a、b)のような関数さえ書くかもしれません。)
もう1つ指摘しておく価値のあることは(まだ誰も指摘していないことに少し驚いたことです)、以前のバージョンのPythonは次のようなコードをサポートしていなかったことです。
value = 'yes' if MyVarIsTrue else 'no'
..それはのようなサポートコードをしました
value = MyVarIsTrue and 'yes' or 'no'
それが三項式を書くための古い方法でした。私はまだPython 3をインストールしていませんが、私の知る限りでは「古い」方法は今日でも機能するので、必要に応じて新しい構文を条件付きで使用する価値があるかどうかを自分で判断できます。古いバージョンのPythonの使用をサポートするため。
ファイルの一番上に次のコードを追加してください。
import sys
if float(sys.version.split()[0][:3]) < 2.7:
print "Python 2.7 or higher required to run this code, " + sys.version.split()[0] + " detected, exiting."
exit(1)
その後、通常のPythonコードを続けます。
import ...
import ...
other code...
私は最良の方法はバージョンではなく機能をテストすることだと思います。場合によっては、これは些細なことですが、そうでないこともあります。
例えば:
try :
# Do stuff
except : # Features weren't found.
# Do stuff for older versions.
Try/exceptブロックの使用方法が十分に特定されている限り、ほとんどの拠点をカバーできます。
スタンドアローンのpythonスクリプトでは、次のモジュールのdocstringトリックがpythonバージョン(ここではv2.7.x)を強制するために動作します(* nixでテスト済み)。
#!/bin/sh
''''python -V 2>&1 | grep -q 2.7 && exec python -u -- "$0" ${1+"$@"}; echo "python 2.7.x missing"; exit 1 # '''
import sys
[...]
これは、欠けているpython実行可能ファイルも処理するはずですが、grepに依存しています。背景については こちら を参照してください。
私は自分自身で問題を解決しようとしている間にクイックサーチの後にこの質問をちょうど見つけました、そして私は上記の提案のいくつかに基づくハイブリッドを思い付きました。
私はDevPlayerのラッパースクリプトを使うという考えが好きですが、欠点は異なるOS用に複数のラッパーを管理することになるので、私はpythonでラッパーを書くことにしましたが、同じ基本的な「exeを実行してバージョンをつかむ」ロジックを使いますそしてこれを思い付いた。
2.5以降ではうまくいくはずだと思います。私はこれまでにLinux上で2.66、2.7.0、および3.1.2上で、OS X上で2.6.1上でテストしました。
import sys, subprocess
args = [sys.executable,"--version"]
output, error = subprocess.Popen(args ,stdout = subprocess.PIPE, stderr = subprocess.PIPE).communicate()
print("The version is: '%s'" %error.decode(sys.stdout.encoding).strip("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLMNBVCXZ,.+ \n") )
はい、私は最終的なデコード/ストリップラインが恐ろしいことを知っています、しかし私はすぐにバージョン番号をつかみたいと思いました。私はそれを洗練するつもりです。
今のところこれは十分にうまく機能しますが、誰かがそれを改善できる(またはなぜそれがひどいアイデアであるかを教えてください)のであれば、それもクールです。
私はakhanの優れた答えを拡張しています。これは役に立つメッセージを表示します以前の Pythonスクリプトはコンパイルさえされています。
スクリプトがPython 3.6以降で実行されていることを確認するには、次の2行をPythonスクリプトの先頭に追加します。
#!/bin/sh
''''python3 -c 'import sys; sys.exit(sys.version_info < (3, 6))' && exec python3 -u -- "$0" ${1+"$@"}; echo 'This script requires Python 3.6 or newer.'; exit 1 # '''
(注:2行目はfour一重引用符で始まり、three一重引用符で終わります。これは奇妙に見えるかもしれませんが、誤植ではありません。
このソリューションの利点は、3.6より古いPythonバージョンが使用されている場合、print(f'Hello, {name}!')
のようなコードでSyntaxError
が発生しないことです。代わりにこの役に立つメッセージが表示されます。
This script requires Python 3.6 or newer.
もちろん、この解決法はUnix風のシェルで、そしてスクリプトが直接呼び出された時(例えば:./script.py
)で、そして適切なeXecuteパーミッションビットがセットされている時にのみ機能します。
sys.hexversion
またはsys.version_info
で確認できます。
sys.hexversion
は16進数であるため、あまり人に優しくありません。 sys.version_info
はタプルなので、より人に優しいです。
sys.hexversion
でPython 3.6以降をチェックしてください。
import sys, time
if sys.hexversion < 0x30600F0:
print("You need Python 3.6 or greater.")
for _ in range(1, 5): time.sleep(1)
exit()
sys.version_info
でPython 3.6以降をチェックしてください。
import sys, time
if sys.version_info[0] < 3 and sys.version_info[1] < 6:
print("You need Python 3.6 or greater.")
for _ in range(1, 5): time.sleep(1)
exit()
sys.version_info
はより人間に優しいですが、より多くの文字を取ります。 sys.hexversion
は、人にやさしくないとしてもお勧めします。
これがお役に立てば幸いです。