2

私はこれらすべてにかなり遅れていることを知っていますが、Python 2.7+ と Python 3+ の両方で使用できるようにしたい、2.7 用に記述された比較的単純なコマンドライン Python スクリプトを持っています。それは単一のスクリプトであるため:

  • 私は6つを使いたくありません- whilesixはただの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__ importPython 3 ではどのように動作しますか? Python 4 が登場し、その時点で Python 3 に非推奨の機能が含まれており、「将来の」Python 4 からインポートする必要がある場合はどうなりますか?
  • この文字のスクリプトを 1 つのファイルに保持し、Python 2.7 と (できれば) 3+ の両方と.py互換性を持たせたい:printsys.stdout.write__future__
  • どこでも新しい文字列書式設定構文を使用したほうがよいでしょうか?
4

1 に答える 1

2

Python の__from__ future import featureステートメントは前方互換性があります。つまりfeature、将来のリリースで標準になったとしても、インポート ステートメントは有効です。

したがって、独自の関数を機能させるために一連の作業を行うのではなく、print無条件にこれをファイルの先頭 (他のコードの前) に配置します。

from __future__ import print_function

それは永遠に機能します。

于 2013-04-27T01:31:44.797 に答える