0

プログラムに __import__() と reload() を実装しようとして失敗しましたが、機能させることができません。.py ファイル (モジュール) に書き込む文字列があり、それをモジュールとしてロードします。次に、その .py ファイル (モジュール) に変更を加えて書き込みますが、新しく更新されたモジュールで戻り値を変更できないようです。これが私のコードです:

str1 = '''
def run():
    return 10

'''
f = open('mycode.py','w')
f.write(str1)
f.close()
mymodule = __import__('mycode')

es = 'number = mymodule.run()'
exec(es)
print "number", number


str2 = '''
def run():
    return 99

'''
f = open('mycode.py','w')
f.write(str2)
f.close()

mymodule = reload(mymodule)
mymodule = __import__('mycode')

es = 'number = mymodule.run()'
exec(es)
print "number", number


OUTPUT:
>> number 10
>> number 10 # should be 99

私はここを見てきました: __import__() を使用して同じ python モジュールをフェイルセーフな方法で再インポートする

ここ:

別のモジュールにインポートされたモジュールのリロード

そしてここ:

Python モジュールをアンロード (再ロード) するにはどうすればよいですか?

しかし、私は解決策を思いつくことができませんでした。どんな助けでも大歓迎です。ありがとう。

ポール

編集

exec(es) を使用している理由は、複数のパラメーターがある場合に es をカスタマイズしたいからです。次に例を示します。

p = [2,1]
p2 = [3,4,5]
p3 = [100,200,300,500]

str1 = '''
def run(x,y):
        return x + y

'''

with open('mycode.py','w') as f:
    f.write(str)
import mycode as mymodule

# how do i do this dynamically, 
# how to handle it when # of paremeters for run() change?
print mymodule.run(p[0],p[1])  # hard-coded parameter passing
# or, print mymodule.run(p[0],p3[1],p[2]) # if run() is changed

したがって、問題は私の run() が異なるパラメーターを持つことができることです。run(x,y) または run(larry、moe、curly、hickory、dickory、dock) のいずれかです。複数のパラメータを run() に動的に渡すにはどうすればよいですか? ありがとう。

4

2 に答える 2

0

ここでの実際の問題は非常に単純です。そして、それを修正する方法を説明します。しかし、実際には、これを行うべきではありません。何をしようとしても、それは間違っています。

誰もがそのようなことをしたいと思う理由がないわけではありません。しかし、関数をファーストクラスの値として渡したり、リテラルなモジュール名でexec呼び出したりできることを知らないために使用する人には、そのような理由はないと確信しています。__import__実際に何をしようとしているのかを説明していただければ、説明できます。

しかしその間:

最初の を実行すると、ファイルがimport作成され、はそのファイルをリロードするだけです。mycode.pycreload

を削除し、代わりにmycode.pyc実行することでこれを確認できます。そして、それは明らかに1つの可能な修正を提供します.python -B reloadtest.pypython reloadtest.py

os.unlink('mycode.pyc')または、 を呼び出す直前に明示的に行うこともできますreload。ほとんどの人はこれを恐ろしく非pythonicと考えると思いますが、そもそもあなたがやろうとしていること以上にそうではないと思います.

最後に、mycode.py既存のファイルをその場で書き換えるのではなく、新しいファイルを作成すれば、問題は解決すると思います。


一方、コードは次のものとまったく同じです。(コメントの混乱に対処するために:まったく同じとは、まったく同じ問題があり、まったく同じ解決策で解決されることを意味します。)また、1つの巨大な4 つの代わりにアンチパターン (対話型インタープリター以外の場所で reload を使用):

str1 = '''
def run():
    return 10

'''
with open('mycode.py', 'w') as f:
    f.write(str1)
import mycode as mymodule

print "number", mymodule.run()

str2 = '''
def run():
    return 99

'''
with open('mycode.py', 'w') as f:
    f.write(str2)

reload(mymodule)

print "number", mymodule.run()

編集ではexec、動的に可変の数のパラメーターを渡したいため、使用していることを説明します。

run(x,y) または run(larry、moe、curly、hickory、dickory、dock) のいずれかです。複数のパラメータを run() に動的に渡すにはどうすればよいですか?

単純。x, yorlarry, moe, curly, hickory, dickory, docktuplelist、またはその他のシーケンスに入れて、 を使用しますrun(*seq)

たとえば、次のようなコードがあるとします。

es = 'number = mymodule.run({})'.format(','.join(params))
exec(es)

それを次のものに置き換えることができます:

number = mymodule.run(*params)

実際、必要と思われる場所を想像できるほとんどの場合、execそれを行うためのより良い方法があります。わからない場合は、Google または StackOverflow で簡単に検索できます。それができない場合は、方法を尋ねてください。動的コード生成に を使用execするのは tcl の慣用句であり、PHP と JavaScript では何年も前に使用されていましたが、Python で正しいことを行うことはほとんどありません。

そして、おそらく今では推測できるように、import/ reload/ execfile/etc への動的なモジュールの作成についても同じことが言えます。

たとえば、実際のコードはおそらく次のようなことをしようとしています。

def make_new_module(n):
    str = '''
    def run():
        return {}        
    '''.format(n)
    f = open('mycode.py','w')
    f.write(str1)
    f.close()
    return __import__('mycode')

しかし、その場で関数を定義することができます:

def make_new_function(n):
    def run():
        return n
    return run

本当に という名前が必要な場合はmymodule.run、クラス、クラス インスタンスなどの名前空間を簡単に作成しnamedtupleて貼り付けることができます。

本当に必要な場合は、その場で新しいモジュールを作成することもできます (ただし、その必要はないと確信しています)。

import types
def make_new_module(n):
    def run():
        return n
    mymodule = types.ModuleType('mymodule')
    mymodule.run = run
    return mymodule

また、既存のモジュールで関数を再バインドするのはさらに簡単です。

def change_mymodule_run(n):
    def run():
        return n
    mymodule.run = run

はい、モジュールは関数と同じようにファーストクラスの値であるため、moduleが静的な値ではなく動的なパラメーターである場合も同様に簡単に実行できます。

def change_module_run(module, n):
    def run():
        return n
    module.run = run
于 2013-03-09T00:40:40.053 に答える
0

一部のコメンターが言っているように、動的コードを作成するためにモジュールを作成する必要はおそらくありません。異なる結果をもたらす2 つの異なるバージョンのrun関数を作成する別の実装を次に示します。

def run_function_factory(n):
    def run_function():
        return n
    return run_function

run1 = run_function_factory(10)
print("run1 returns", run1()) # prints "run1 returns 10"

run2 = run_function_factory(99)
print("run2 returns", run2()) # prints "run2 returns 99"

明らかに、実際のコードはもっと複雑になりますが、同様のスタイルのコーディング (関数をファーストクラス オブジェクトとして扱う) は、必要なほぼすべてのバリエーションで可能です。たとえば、runが 2 つの引数を取り、aandbがそれらを使用して何らかの演算を行い、n戻る前に次のようなものを使用する場合:

def run_function_factory(n):
    def run_function(a, b):
        return a*n + b

run1 = run_function_factory(10)
for x in range(3):
    for y in range(2,5):
        print(run1(x,y)) # prints 2,3,4,12,13,14,22,23,24 (one per line)
于 2013-03-09T01:19:18.973 に答える