質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 2.7

Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

962閲覧

python2系と3系の違い exec編

EzrealTrueshot

総合スコア388

Python 2.7

Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2017/07/07 02:46

###前提・実現したいこと
python2系で出来ていることを3系でも実装したい。

###発生している問題・エラーメッセージ

Traceback (most recent call last): File "./code", line 24, in <module> main() File "./code", line 12, in main a0.append('1') NameError: name 'a0' is not defined

###該当のソースコード

#!/usr/bin/env python import fileinput def main(): for i in fileinput.input(): a = i.strip() for i in range(0,int(a)): exec("a{}".format(i) + " = []") a0.append('1') a0.append('2') a0.append('3') a1.append('4') a1.append('5') a1.append('6') print(a0) print(a1) if __name__ == '__main__': main()

###試したこと
2to3というpythonの2系から3系にするため?の便利なツールがあるとのことでしたので、試してみました。

[root@theo]# 2to3 pytest.py RefactoringTool: Skipping implicit fixer: buffer RefactoringTool: Skipping implicit fixer: idioms RefactoringTool: Skipping implicit fixer: set_literal RefactoringTool: Skipping implicit fixer: ws_comma RefactoringTool: No changes to pytest.py RefactoringTool: Files that need to be modified: RefactoringTool: pytest.py

###補足情報(言語/FW/ツール等のバージョンなど)
2系実行時 (2.7.5)

[root@theo]# ./pytest.py 2 ['1', '2', '3'] ['4', '5', '6']

3系実行時 (3.5.0)

[root@theo]# ./pytest.py 2 Traceback (most recent call last): File "./code", line 24, in <module> main() File "./code", line 12, in main a0.append('1') NameError: name 'a0' is not defined

何か足りない情報等ございましたらおっしゃってください。
追加でお伝え致します。

よろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

Python3 になるときに exec は構文から関数へ変更されました。それに併せて挙動が変更されたようです。※参考:Issue 4831: exec() behavior - revisited - Python tracker

また、公式リファレンス に下記の注釈があります。

標準の locals 辞書に対する変更を試みてはいけません。 exec() の呼び出しが返る時にコードが locals に与える影響を知りたいなら、明示的に locals 辞書を渡してください

つまり、Python3 でも動作させるにはこんなコードになります。

python

1def main(): 2 locals_dic = locals() 3 exec("a{}".format(0) + " = []", globals(), locals_dic) 4 locals_dic['a0'].append('1') 5 locals_dic['a0'].append('2') 6 print(locals_dic['a0']) 7 8main()

なんだかゴチャゴチャしてしまいました。


そもそも exec() や eval() はよほどの事がない限り使うべきではありません。今回のように実装が複雑になったり、脆弱性の原因にもなります。特に今回のような変数名を exec/eval で決定するような方法は避けるべきです。

変数が不定・複数ある場合はリストや辞書を使いましょう。

python

1import fileinput 2 3def main(): 4 for i in fileinput.input(): 5 a = i.strip() 6 print('a is', a) 7 8 d = {} 9 for i in range(0, int(a)): 10 d[i] = [] 11 12 d[0].append('1') 13 d[0].append('2') 14 d[0].append('3') 15 16 d[1].append('4') 17 d[1].append('5') 18 d[1].append('6') 19 20 print(d[0]) 21 print(d[1]) 22 23main()

さらに defaultdict を使えばリストの定義を自動でやってくれるようになるので、すっきりしたコードになります。

python

1from collections import defaultdict 2 3def main(): 4 d = defaultdict(list) 5 6 d[0].append('1') 7 d[0].append('2') 8 d[0].append('3') 9 10 d[1].append('4') 11 d[1].append('5') 12 d[1].append('6') 13 14 print(d[0]) 15 print(d[1]) 16 17main()

投稿2017/07/07 04:36

編集2017/07/07 04:59
miyahan

総合スコア3095

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

EzrealTrueshot

2017/07/07 04:54

回答ありがとうございます。 参考にさせて頂きます!
guest

0

2to3 はいまは推奨されていません。py2, py3 両方で動作するコードを書いた方が良いです。
そのための支援ツールは次のようなものがあります:

広く使われていて目にするのはsixですが、futureの方に含まれているfuturizeコマンドは、Python2のコードをPy2, Py3 両対応にするための最初のステップとしてとても便利です。

pytest.pyexec 文を含んでいますが、Py3では関数になったので、その対応が必要です。sixであれば以下のように書き換えることで対応できます。

Python

1import six 2(中略) 3 4 six.exec_("a{}".format(i) + " = []") 5(後略)

参考

投稿2017/07/07 04:25

編集2017/07/07 04:30
shimizukawa

総合スコア1847

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

EzrealTrueshot

2017/07/07 04:53

回答ありがとうございます! six・・・なるほど、そういうものがあるのですね。 試してみようと思います。
guest

0

コードを見ていると、変数定義にexecを使っているようですね。
しかし、execはセキュリティに重大なリスクをもたらすため、気をつける必要があります。

動的な変数定義でしたらglobalsを使った方が安全だし、理にかなっているように見えます。

python

1 for i in range(0,int(a)): 2 # exec("a{}".format(i) + " = []") 3 globals()["a{}".format(i)] = []

投稿2017/07/07 04:34

編集2017/07/07 04:35
pashango2

総合スコア930

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pashango2

2017/07/07 04:48

すみません、コードを見たらmainで囲まれていますね。 となると、スコープはglobals()ではなく、locals()になりますが、miyahanさんのご指摘どおり、locals()を変更しても反映はされません。 ローカル変数の動的定義ですがexecを使うよりも辞書などを使った方が無難です。
pashango2

2017/07/07 04:53 編集

私がベストアンサーになっていますが、私はmiyahanさんの案が良いと思います。 ベストアンサーはmiyahanさんにしてください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問