私はこれらすべてにかなり遅れていることを知っていますが、Python 2.7+ と Python 3+ の両方で使用できるようにしたい、2.7 用に記述された比較的単純なコマンドライン Python スクリプトを持っています。それは単一のスクリプトであるため:
- 私は6つを使いたくありません- while
six
はただの1つのファイルですが、1つではなく2つのファイル (six
モジュールとスクリプト) を処理する必要があります。 - 私は2to3を使いたくありません。1 つではなく、2 つのファイル (スクリプトの 2.7 バージョンと 3.2 バージョン) を処理する必要があるからです。
したがって、私にとって最善のアプローチは、Python 2.x を Python 3.x と可能な限り互換性を持って作成することであると考えました。その後、一度コーディングすれば、USB サムドライブ OS でスクリプトを実行する必要があるかどうかを心配する必要はありません。USB サムドライブ OS には Python 2.7 (またはPython 3+のみ)しかなく、見つけるのに苦労する可能性があります。または適切なバージョンの Python をインストールします。
私の問題を示すために、ここに Learning Python の例に基づいたサンプル スクリプトを示します-- サンプルの章 9: Python での一般的なタスク- および Ubuntu 11.04 での準備bash
(少し Unicode を使用して、スパイスを効かせます):
cd /tmp
mkdir /tmp/ptest
echo 'Байхъусут, зæрæдтæ!.. Байхъусут, лæппутæ!..' > /tmp/ptest/test.txt
echo 'Байхъусут, зæрæдтæ!.. Байхъусут, лæппутæ!..
Байхъусут зарæгмæ, фыдæлты кадæгмæ,
Дзæбæхдæр бахъырнут уæ бæзджын хъæлæстæй!..' > /tmp/ptest/Байхъусут.txt
cat > tscript.py <<"EOF"
# -*- coding: utf-8 -*-
import fileinput, sys, string, os
if ( len(sys.argv) > 3 ) or ( len(sys.argv) < 2 ):
print "Usage: ", sys.argv[0], "searchterm [path]"
sys.exit()
# take the first argument out of sys.argv and assign it to searchterm
searchterm, sys.argv[1:] = sys.argv[1], sys.argv[2:]
if len(sys.argv) == 1: # if no dir is specified,
indir = os.curdir # use current dir
else: # otherwise, use dir specified
indir = sys.argv[1] # on the command line
filenames = [indir+"/"+f for f in os.listdir(indir) if os.path.isfile(indir+"/"+f)]
for line in fileinput.input(filenames):
num_matches = string.count(line, searchterm)
if num_matches: # a nonzero count means there was a match
print "found '%s' %d times in %s on line " % ( searchterm, num_matches, fileinput.filename() ), \
fileinput.filelineno()
EOF
これを試す:
$ python2.7 tscript.py Байхъусут /tmp/ptest
found 'Байхъусут' 2 times in /tmp/ptest/test.txt on line 1
found 'Байхъусут' 2 times in /tmp/ptest/Байхъусут.txt on line 1
found 'Байхъусут' 1 times in /tmp/ptest/Байхъусут.txt on line 2
$ python3.2 tscript.py Байхъусут /tmp/ptest
File "tscript.py", line 17
print "Usage: ", sys.argv[0], "searchterm [path]"
^
SyntaxError: invalid syntax
わかりました、それは印刷の変更に違いありません - 括弧を追加するだけでよいでしょうか? 私はこのように変更します:
print ("Usage: ", sys.argv[0], "searchterm [path]")
....
print ("found '%s' %d times in %s on line " % ( searchterm, num_matches, fileinput.filename() ), \
fileinput.filelineno() )
...それでいいですか?:
$ python3.2 tscript.py Байхъусут /tmp/ptest
Traceback (most recent call last):
File "tscript.py", line 31, in <module>
num_matches = string.count(line, searchterm)
AttributeError: 'module' object has no attribute 'count'
いいえ..だから私もこの行を変更します:
num_matches = line.count(searchterm) # string.count(line, searchterm)
... それで十分?まあ-やや、それはそうです:
$ python3.2 tscript.py Байхъусут /tmp/ptest
found 'Байхъусут' 2 times in /tmp/ptest/test.txt on line 1
found 'Байхъусут' 2 times in /tmp/ptest/Байхъусут.txt on line 1
found 'Байхъусут' 1 times in /tmp/ptest/Байхъусут.txt on line 2
$ python2.7 tscript.py Байхъусут /tmp/ptest
("found '\xd0\x91\xd0\xb0\xd0\xb9\xd1\x85\xd1\x8a\xd1\x83\xd1\x81\xd1\x83\xd1\x82' 2 times in /tmp/ptest/test.txt on line ", 1)
("found '\xd0\x91\xd0\xb0\xd0\xb9\xd1\x85\xd1\x8a\xd1\x83\xd1\x81\xd1\x83\xd1\x82' 2 times in /tmp/ptest/\xd0\x91\xd0\xb0\xd0\xb9\xd1\x85\xd1\x8a\xd1\x83\xd1\x81\xd1\x83\xd1\x82.txt on line ", 1)
("found '\xd0\x91\xd0\xb0\xd0\xb9\xd1\x85\xd1\x8a\xd1\x83\xd1\x81\xd1\x83\xd1\x82' 1 times in /tmp/ptest/\xd0\x91\xd0\xb0\xd0\xb9\xd1\x85\xd1\x8a\xd1\x83\xd1\x81\xd1\x83\xd1\x82.txt on line ", 2)
少なくともクラッシュしませんが、python 2.7print
はタプルを認識し、デフォルトではそのタプル内の文字列を正しくデコードしないようです...
だから、どうやら、今私は python 2.7print_function
からインポートしたい (どの python バージョンが __future__ import with_statement から必要ですか? ); したがって、これをファイルの先頭 (ステートメントの後) に配置しようとしましたが、2.x バージョンにのみインポートを使用することをお勧めします。__future__
coding
import __future__, sys
if sys.version_info[0] < 3:
from __future__ import print_function
else:
pass
...しかし、私は得る:
$ python2.7 tscript.py Байхъусут /tmp/ptest
File "tscript.py", line 6
from __future__ import print_function
SyntaxError: from __future__ imports must occur at the beginning of the file
これに対する答えは、Python グレースフル フューチャー フィーチャー (__future__) インポートの質問で、ラッパー.py
ファイルを使用することですが、1 つではなく 2 つのファイルを考えなければならないという同じ問題が再び発生します。
余分なファイルが作成されたとしても、このようにカンニングできると思いました。
import __future__, sys
if sys.version_info[0] < 3:
str = """from __future__ import print_function"""
f = open('compat23.py','w')
f.write(str)
f.close()
import compat23
print("sys.version_info[0] < 3", end='(')
else:
print("sys.version_info[0] >= 3", end=')')
...しかし、それは実際には問題ではありません:
$ python2.7 tscript.py Байхъусут /tmp/ptest
File "tscript.py", line 11
print("sys.version_info[0] < 3", end='(')
^
SyntaxError: invalid syntax
...インポートは新しく作成されたモジュール__future__
のスコープに対してのみ有効だったため、明らかに。compat23
そう:
- コンパイル時のステートメントである
__future__
ことを考えると、インポートを 3 未満のバージョンのみに制限しようとしているのは明らかに間違いです。from __future__ ...
しかしその後: - Python 3 はこのステートメントにどのように反応しますか? それは単に無視されますか?
print
では、Python 4 で再び非推奨にすることを決定したfrom __future__ import print_function
場合、現在 Python 3 で無視されているとしても、Python 3 では再び意味を持たないのでしょうか?
したがって、これについて考えるのを避け、単一ファイルのみのスクリプトを使用したい場合は、noconv.htmlのアドバイスに従います : " ... または、機能する別の印刷機能を使用できますPython 2 と Python 3 の両方で..トリックは sys.stdout.write() とフォーマットを使用することです.... "; Eli Bendersky の Web サイトでも見られます » Making code compatible with Python 2 and 3 .
__future__
そして、インポート部分ではなく、ファイルの先頭でこれを試して、対応する印刷ステートメントを変更します。
def printso(*inargs):
outstr = ""
for inarg in inargs:
outstr += str(inarg) + " "
outstr += "\n"
sys.stdout.write(outstr)
.... printso ("使用法: ", sys.argv[0], "searchterm [パス]") .... printso ("'%s' が %s 行の %s で %d 回見つかりました" % ( searchterm, num_matches, fileinput.filename() ), \ fileinput.filelineno() )
...そして、これは実際、python 2.7と3.2の両方でうまく機能します:
$ python2.7 tscript.py Байхъусут /tmp/ptest
found 'Байхъусут' 2 times in /tmp/ptest/test.txt on line 1
found 'Байхъусут' 2 times in /tmp/ptest/Байхъусут.txt on line 1
found 'Байхъусут' 1 times in /tmp/ptest/Байхъусут.txt on line 2
$ python3.2 tscript.py Байхъусут /tmp/ptest
found 'Байхъусут' 2 times in /tmp/ptest/test.txt on line 1
found 'Байхъусут' 2 times in /tmp/ptest/Байхъусут.txt on line 1
found 'Байхъусут' 1 times in /tmp/ptest/Байхъусут.txt on line 2
%
わかりましたが、文字列書式設定のパーセント記号も非推奨であることがわかりました。代わりに、次のように書く必要があります。
#printso ("found '%s' %d times in %s on line " % ( searchterm, num_matches, fileinput.filename() ), \
# fileinput.filelineno() )
printso ("found '{0}' {1} times in {2} on line ".format(searchterm, num_matches, fileinput.filename() ), \
fileinput.filelineno() )
ありがたいことに、これは 2.7 と 3.2 の両方で機能し、新しい Python 3.0 文字列フォーマットでも機能します。本当に必要なのでしょうか? -comp.lang.python | Google グループには次のように記載されています。
>> Python 3.x でも古い 2.x 構文を使用できます:
> ええ、しかしそれは非推奨であり、- 私が理解しているように- 削除される可能性があります
> 将来のバージョンでは完全に。また、将来、
別の開発者のコードで作業している場合、その開発者は
新しい形式を使用する可能性があります。両方を使用できると思いますが、それはなんとひどい混乱
でしょう。何年も削除されることはありません - もしあったとしても。
...しかし、非推奨であることを考えると、これがいつまで真実であり続けるかを誰が確信できるでしょうか?
つまり、本質的に-確認したいのですが:
from __future__ import
Python 3 ではどのように動作しますか? Python 4 が登場し、その時点で Python 3 に非推奨の機能が含まれており、「将来の」Python 4 からインポートする必要がある場合はどうなりますか?- この文字のスクリプトを 1 つのファイルに保持し、Python 2.7 と (できれば) 3+ の両方と
.py
互換性を持たせたい:print
sys.stdout.write
__future__
- どこでも新しい文字列書式設定構文を使用したほうがよいでしょうか?