2017-04-08 17 views
2

関数を書くmake_monitoredは入力として関数fをとり、それ自身が1つの入力を取ります。 make_monitoredによって返される結果は、内部カウンタを維持することによって呼び出された回数を追跡する第3の関数、たとえばmfです。他の関数を監視して数える関数Python

mfへの入力が特殊文字列「how-many-calls?」の場​​合、mfは カウンタの値を返します。

入力が特殊文字列 "reset-count"の場合、mfはカウンタ をゼロにリセットします。他の入力の場合、mfはその入力でfを呼び出した結果を返し、 はカウンタをインクリメントします。ここ

def make_monitored(f): 
    a=[0] 
    def mf(x): 
     if x=="how-many-calls?": 
      return a[0] 
     elif x=="reset-count": 
      a=[0] 
     else: 
      a[0]+=1 
      return f(x) 
    return mf 


def double(x): #NOT TO BE CHANGED , provided by question 
    return 2 * x 

d = make_monitored(double) #NOT TO BE CHANGED, provided by question 

は私が理解しないものです: 私は内部カウンタとして作るために1つの要素のリストを作りたいです。私は、make_monitorsが親関数で、私が定義したときにaが定義されていないと言う理由を知りません。

これは私がこれまでに(そして正しく)似た方法を使って完成したが、成功したもう一つの質問です。

アキュムレータは、単一の数値引数 で繰り返し呼び出され、その引数を合計に累積する関数です。呼び出されるたびに、現在集計された合計 を返します。 アキュムレータを生成するmake_accumulator関数を記述します。各関数は独立した合計を保持します。

def make_accumulator(): 
    lst=[0] 
    def add(x): 
     lst[0]+=x 
     return lst[0]  
    return add 
A=make_accumulator() 

サンプルの実行:

A = make_accumulator()

A(10)出力:10

A(10)出力:20

私はなぜ取得いけませんlst [0]はここで定義されています。 のみ可能な理由は、make_accumulatorパラメータなしで取りますが、割り当てa = [0]mfにローカルな新しいaを作成します。1.

答えて

1

に make_monitoredを取るということです。つまり、aへの他のすべての参照は、mfで、ローカルのaにする必要があります。

のでa自体への割り当てを回避し、代わりにそれを変異:

a[0] = 0 

ところで、Pythonの3は、この種のもののために便利である新しいキーワードnonlocalを提供します。これはglobalキーワードと同様に機能し、可変のコンテナ内でintを使いこなすのではなく、カウンタやアキュムレータに単純なintを使用することができます。

+0

おかげで、のpython 3.6を使用してそれを – Silver

1

私たちはclosureを定義しています - それは自分の環境の中にある機能です。これにより、関数は余分な状態を追跡できます。

内部関数の定義時に、変数aは内容[0]のリストに割り当てられます。

あなたが行う場合は、この:

elif x=="reset-count": a=[0] あなたは私たちの内側の関数にローカルである真新しいリストに割り当てます。それはもはや外側に定義された 'a'については知りません。

nonlocalキーワードを使用すると、クロージャの状態を追跡できます。 E.G:

def count_calls(func): 
    calls_so_far = 0 
    def inner(x): 
     nonlocal calls_so_far # this allows us to keep track of state 
     if x == 'how-many-calls' 
      return calls_so_far 
     if x == 'reset-count': 
      calls_so_far = 0 
     else: 
      calls_so_far += 1 
      return func(x) 
    return inner 


@count_calls # this is a DECORATOR 
def double(x): 
    return 2*x 

# This decorator is equivalent to the following: 
""" 
def double(x): 
    return 2*x 
double = count_calls(double) 
""" 

Python 2では、nonlocalキーワードは使用できません。代わりに、ある種の変更可能なコンテナを変更する必要があります。リストを使用して最初の要素を変更するのは一般的なアプローチであり、例のコードで見られるものです。これは直感的ではなく、間違いを起こしやすいので、非局所的アプローチはより慣用的なpythonと見なされます。 PYTHON 3.6 FOR

SCOPE例(それを自分で実行してみてください!):

x = 'GLOBAL' 
def outer(): 
    print('running outer()') 
    x = 'OUTER' 
    print(f'\tx = {x}') 
    def inner(): 
     print('\t\trunning inner()') 
     x = 'INNER' 
    def inner_nonlocal(): 
     nonlocal x 
     print('\t\trunning inner_nonlocal()') 
     x = 'INNER_NONLOCAL' 
    inner() 
    print(f'\tx = {x}') 
    inner_nonlocal() 
    print(f'\tx = {x}') 

print('before running outer()') 
print(f'x = {x}') 
outer() 
print('after running outer()') 
print(f'x = {x}') 
+0

イムを解決するために管理。だから唯一の方法は、リストのような変更可能なデータ構造を使用することです? – Silver

+0

いいえ。非ローカルを使用できます。 私はスコープルールの教訓的な例を編集しました。 –

+0

私は助けに感謝します。それは非常に便利です。あなたの時間と助けてくれてありがとう! – Silver

関連する問題