2017-04-08 2 views
2

Schreiben Sie eine Funktion make_monitored, die als Eingabe eine Funktion, f, nimmt, die selbst einen Eingang nimmt. Das Ergebnis, das von make_monitored zurückgegeben wird, ist eine dritte Funktion, zum Beispiel mf, die die Anzahl der Aufrufe durch einen internen Zähler verfolgt.Funktion zum Überwachen und Zählen einer anderen Funktion Python

Wenn die Eingabe für mf die spezielle Zeichenfolge "how-many-calls?" Ist, gibt mf den Wert des Zählers zurück. Wenn der Eingang der spezielle String "reset-count" ist, setzt mf den Zähler auf Null zurück. Für jede andere Eingabe gibt mf das Ergebnis von f an diesem Eingang zurück und erhöht den Zähler.

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 

hier ist, was ich nicht verstehe: ich ein Element Liste zu machen als einen internen Zähler machen wollen. Ich verstehe nicht, warum sie sagen, dass a nicht definiert ist, wenn make_monitored die Elternfunktion ist und ich a definiert habe.

Dies ist eine andere Frage, die ich zuvor (und richtig) abgeschlossen habe, die eine ähnliche Methode verwendet, aber erfolgreich ist.

Ein Akkumulator ist eine Funktion, die wiederholt mit einem einzelnen numerischen Argument aufgerufen wird und ihre Argumente in eine Summe akkumuliert. Jedes Mal, wenn es aufgerufen wird, gibt es die aktuell akkumulierte Summe zurück. Schreiben Sie eine Funktion make_accumulator, die Akkumulatoren generiert, die jeweils eine unabhängige Summe beibehalten.

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

Beispiel Ausführung:

A = make_accumulator()

A (10) Ausgabe: 10

A (10) Ausgang: 20

ich nicht, warum lst [0] wird hier akzeptiert. Der einzig mögliche Grund ist, dass make_accumulator in keine Parameter aber make_monitored nimmt in 1.

Antwort

1

Die Zuordnung a = [0] einen neuen a schafft, die mf lokal ist. Und das bedeutet, dass alle anderen Verweise auf a in 10 zu diesem lokalen a anstelle von dem in dem Eltern sein müssen.

So vermeiden a selbst zuweisen und es stattdessen mutieren:

a[0] = 0 

BTW, Python 3 stellt ein neues Schlüsselwort nonlocal, die für diese Art der Sache praktisch ist. Es funktioniert ähnlich wie das Schlüsselwort global, und Sie könnten es hier verwenden, um ein einfaches int für Ihren Zähler oder Akkumulator zu haben, anstatt sich mit einem int innerhalb eines veränderbaren Containers herumzuärgern.

+0

dank gelang es – Silver

1

Wir definieren eine closure - eine Funktion, die in ihrer eigenen Umgebung ist. Dadurch kann unsere Funktion den zusätzlichen Status verfolgen.

Zum Zeitpunkt der Definition unserer inneren Funktion wird die Variable a einer Liste mit dem Inhalt [0] zugewiesen.

Wenn Sie dies tun:

elif x=="reset-count": a=[0] Sie zuweisen ein zu einem brandneuen Liste, die auf unsere innere Funktion lokal ist; es kennt das außen definierte "a" nicht mehr.

Verwenden Sie das nonlocal-Schlüsselwort, um den Zustand von Schließungen zu verfolgen. 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) 
""" 

In Python 2 können Sie das nichtlokale Schlüsselwort nicht verwenden. Stattdessen müssen Sie eine Art veränderbarer Container mutieren. Eine Liste zu verwenden und das erste Element zu mutieren ist ein üblicher Ansatz und der in Ihrem Beispielcode zu sehen. Dies ist jedoch nicht intuitiv und leicht zu Fehlern, so dass der nichtlokale Ansatz als idiomatischer Python betrachtet wird.

SCOPE Beispiel für python 3.6 (versuchen Sie es selbst laufen!):

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 3.6 mit Python zu lösen. Der einzige Weg ist, eine veränderbare Datenstruktur wie eine Liste zu verwenden, oder? – Silver

+0

Nein. Sie können nonlocal verwenden. Ich habe in einem didaktischen Beispiel der Geltungsbereich Regeln und die Verwendung von nichtlokalen, die möglicherweise helfen, bearbeitet. –

+0

Ich schätze die Hilfe. Es ist sehr nützlich. Danke für deine Zeit und Hilfe! – Silver

Verwandte Themen