2017-04-08 61 views
2

編寫函數make_monitored將輸入函數f作爲輸入,該函數本身需要一個輸入。 make_monitored返回的結果是第三個函數,比如說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 

這裏是我不明白: 我想打一個元素列表,以作爲內部計數器。我不明白爲什麼他們說沒有定義make_monitored是父函數,我已經定義了一個。

這是另一個問題,我已經完成以前(和正確),使用類似的方法,但成功。

累加器是一個函數,用一個數字參數 重複調用,並將其參數累加到一個和中。每次調用它時,它將返回當前累計總和的 。編寫一個函數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發生在沒有任何參數,但 make_monitored確實需要在1

回答

1

分配a = [0]創建一個新的a,這是本地mf。這意味着mfa的所有其他引用都必須是該當地a而不是父代中的那個。

因此要避免分配給a本身,而是它發生變異:

a[0] = 0 

BTW,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(!嘗試自己運行它)

範圍例:

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

IM。所以唯一的方法是使用像列表一樣的可變數據結構嗎? – Silver

+0

不可以。您可以使用非本地。 我已經編輯了示範規則的教學示例,並使用非本地可能有所幫助。 –

+0

我很感激幫助。這非常有用。感謝您的時間和幫助! – Silver

相關問題