Wie man prüft, ob eine Funktion in Python aufgerufen wurde

PythonPythonBeginner
Jetzt üben

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einführung

In diesem Lab lernen Sie, wie Sie prüfen können, ob eine Funktion in Python aufgerufen wurde. Dies ist eine entscheidende Fähigkeit für das Debugging, die Leistungsanalyse und das Testen. Das Lab untersucht Techniken zum Nachverfolgen von Funktionsaufrufen, einschließlich der Anzahl der Aufrufe einer Funktion und der verwendeten Argumente.

Das Lab beginnt mit einem einfachen Python-Funktionsbeispiel und stellt eine grundlegende Technik zur manuellen Verfolgung von Funktionsaufrufen vor, bei der eine globale Variable verwendet wird, um die Anzahl der Aufrufe zu zählen. Anschließend werden Sie durch die Modifikation des Codes geführt, um den Zähler bei jedem Funktionsaufruf zu erhöhen und die Gesamtzahl der Aufrufe anzuzeigen. Das Lab wird dann fortfahren, fortgeschrittenere Methoden zur Überwachung von Funktionsaufrufen zu untersuchen, wie das Erstellen von Wrapper-Funktionen und die Verwendung des unittest.mock-Moduls.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("Python")) -.-> python/BasicConceptsGroup(["Basic Concepts"]) python(("Python")) -.-> python/FunctionsGroup(["Functions"]) python(("Python")) -.-> python/AdvancedTopicsGroup(["Advanced Topics"]) python/BasicConceptsGroup -.-> python/variables_data_types("Variables and Data Types") python/FunctionsGroup -.-> python/function_definition("Function Definition") python/FunctionsGroup -.-> python/arguments_return("Arguments and Return Values") python/AdvancedTopicsGroup -.-> python/decorators("Decorators") subgraph Lab Skills python/variables_data_types -.-> lab-559518{{"Wie man prüft, ob eine Funktion in Python aufgerufen wurde"}} python/function_definition -.-> lab-559518{{"Wie man prüft, ob eine Funktion in Python aufgerufen wurde"}} python/arguments_return -.-> lab-559518{{"Wie man prüft, ob eine Funktion in Python aufgerufen wurde"}} python/decorators -.-> lab-559518{{"Wie man prüft, ob eine Funktion in Python aufgerufen wurde"}} end

Verständnis der Verfolgung von Funktionsaufrufen

In diesem Schritt werden wir das grundlegende Konzept der Verfolgung von Funktionsaufrufen in Python untersuchen. Das Verständnis, wie oft eine Funktion aufgerufen wird und mit welchen Argumenten, ist entscheidend für das Debugging, die Leistungsanalyse und das Testen. Wir beginnen mit einem einfachen Beispiel und stellen dann eine grundlegende Technik zur manuellen Verfolgung von Funktionsaufrufen vor.

Beginnen wir damit, eine einfache Python-Funktion im Verzeichnis ~/project mit dem VS Code-Editor zu erstellen. Erstellen Sie eine Datei namens my_function.py und fügen Sie den folgenden Code hinzu:

## ~/project/my_function.py
def greet(name):
  """This function greets the person passed in as a parameter."""
  print(f"Hello, {name}!")

## Example usage
greet("Alice")
greet("Bob")

Dieser Code definiert eine Funktion greet, die einen Namen als Eingabe nimmt und eine Begrüßung ausgibt. Anschließend ruft er die Funktion zweimal mit verschiedenen Namen auf.

Um dieses Skript auszuführen, öffnen Sie das Terminal in VS Code (normalerweise können Sie dies tun, indem Sie Strg + `` oder Cmd + `` drücken) und führen Sie den folgenden Befehl aus:

python ~/project/my_function.py

Sie sollten die folgende Ausgabe sehen:

Hello, Alice!
Hello, Bob!

Jetzt ändern wir die Datei my_function.py, um zu verfolgen, wie oft die Funktion greet aufgerufen wird. Wir führen eine globale Variable ein, um die Anzahl der Aufrufe zu verfolgen.

Ändern Sie die Datei my_function.py, um den folgenden Code einzuschließen:

## ~/project/my_function.py
invocation_count = 0

def greet(name):
  """This function greets the person passed in as a parameter."""
  global invocation_count
  invocation_count += 1
  print(f"Hello, {name}!")

## Example usage
greet("Alice")
greet("Bob")

print(f"The greet function was called {invocation_count} times.")

In dieser geänderten Version haben wir eine globale Variable invocation_count hinzugefügt und sie bei jedem Aufruf der Funktion greet erhöht. Wir haben auch eine Print-Anweisung am Ende hinzugefügt, um die Gesamtzahl der Aufrufe anzuzeigen.

Führen Sie das Skript erneut mit demselben Befehl aus:

python ~/project/my_function.py

Sie sollten jetzt die folgende Ausgabe sehen:

Hello, Alice!
Hello, Bob!
The greet function was called 2 times.

Dieses einfache Beispiel zeigt eine grundlegende Möglichkeit, Funktionsaufrufe zu verfolgen. Dieser Ansatz kann jedoch für komplexere Anwendungen mit vielen Funktionen umständlich werden. In den nächsten Schritten werden wir ausgefeiltere Techniken mithilfe von Wrapper-Funktionen und dem unittest.mock-Modul untersuchen.

Erstellen einer Wrapper-Funktion

In diesem Schritt lernen wir, wie man Wrapper-Funktionen verwendet, um Funktionsaufrufe zu verfolgen. Eine Wrapper-Funktion ist eine Funktion, die um eine andere Funktion herumgelegt wird und es ermöglicht, Funktionalität vor oder nach der Ausführung der ursprünglichen Funktion hinzuzufügen. Dies ist eine leistungsstarke Technik zur Überwachung von Funktionsaufrufen, ohne den Code der ursprünglichen Funktion zu ändern.

Lasst uns mit der greet-Funktion aus dem vorherigen Schritt fortfahren. Wir werden eine Wrapper-Funktion erstellen, die die Anzahl der Aufrufe von greet verfolgt.

Ändern Sie die Datei my_function.py im Verzeichnis ~/project, um den folgenden Code einzuschließen:

## ~/project/my_function.py
invocation_count = 0

def greet(name):
  """This function greets the person passed in as a parameter."""
  print(f"Hello, {name}!")

def greet_wrapper(func):
  """This is a wrapper function that tracks the number of times the wrapped function is called."""
  def wrapper(*args, **kwargs):
    global invocation_count
    invocation_count += 1
    result = func(*args, **kwargs)
    return result
  return wrapper

## Apply the wrapper to the greet function
greet = greet_wrapper(greet)

## Example usage
greet("Alice")
greet("Bob")

print(f"The greet function was called {invocation_count} times.")

In diesem Code:

  • Wir definieren eine greet_wrapper-Funktion, die eine Funktion (func) als Eingabe nimmt.
  • Innerhalb von greet_wrapper definieren wir eine weitere Funktion namens wrapper. Diese wrapper-Funktion ist die eigentliche Wrapper-Funktion, die ausgeführt wird, wenn wir die umhüllte Funktion aufrufen.
  • Die wrapper-Funktion erhöht die invocation_count, ruft die ursprüngliche Funktion (func) mit allen an sie übergebenen Argumenten auf und gibt das Ergebnis zurück.
  • Anschließend wenden wir die Wrapper-Funktion auf die greet-Funktion an, indem wir greet = greet_wrapper(greet) zuweisen. Dies ersetzt die ursprüngliche greet-Funktion durch die umhüllte Version.

Führen Sie das Skript erneut mit demselben Befehl aus:

python ~/project/my_function.py

Sie sollten die folgende Ausgabe sehen:

Hello, Alice!
Hello, Bob!
The greet function was called 2 times.

Diese Ausgabe ist dieselbe wie im vorherigen Schritt, aber jetzt verwenden wir eine Wrapper-Funktion, um die Aufrufe zu verfolgen. Dieser Ansatz ist flexibler, da Sie dieselbe Wrapper-Funktion problemlos auf mehrere Funktionen anwenden können.

Jetzt fügen wir eine weitere Funktion hinzu und wenden dieselbe Wrapper-Funktion auf sie an. Fügen Sie die folgende Funktion zur Datei my_function.py hinzu:

## ~/project/my_function.py
invocation_count = 0

def greet(name):
  """This function greets the person passed in as a parameter."""
  print(f"Hello, {name}!")

def add(x, y):
  """This function adds two numbers and returns the result."""
  print(f"Adding {x} and {y}")
  return x + y

def greet_wrapper(func):
  """This is a wrapper function that tracks the number of times the wrapped function is called."""
  def wrapper(*args, **kwargs):
    global invocation_count
    invocation_count += 1
    result = func(*args, **kwargs)
    return result
  return wrapper

## Apply the wrapper to the greet function
greet = greet_wrapper(greet)
add = greet_wrapper(add)

## Example usage
greet("Alice")
greet("Bob")
add(5, 3)

print(f"The greet function was called {invocation_count} times.")

Wir haben eine add-Funktion hinzugefügt und auch die greet_wrapper-Funktion auf sie angewendet. Jetzt wird die invocation_count die Gesamtzahl der Aufrufe von sowohl greet als auch add verfolgen.

Führen Sie das Skript erneut aus:

python ~/project/my_function.py

Sie sollten eine Ausgabe ähnlich der folgenden sehen:

Hello, Alice!
Hello, Bob!
Adding 5 and 3
The greet function was called 3 times.

Wie Sie sehen können, spiegelt die invocation_count jetzt die Gesamtzahl der Aufrufe von sowohl der greet- als auch der add-Funktion wider. Wrapper-Funktionen bieten eine saubere und wiederverwendbare Möglichkeit, Funktionsaufrufe zu überwachen.

Verwenden von unittest.mock zur Überwachung von Aufrufen

In diesem Schritt werden wir untersuchen, wie man das unittest.mock-Modul verwendet, um Funktionsaufrufe zu überwachen. Das unittest.mock-Modul ist ein leistungsstarkes Werkzeug für das Testen und Debugging und bietet eine bequeme Möglichkeit, Funktionsaufrufe, Argumente und Rückgabewerte zu verfolgen.

Lasst uns mit der greet-Funktion aus den vorherigen Schritten fortfahren. Wir werden unittest.mock verwenden, um die Aufrufe von greet zu überwachen.

Ändern Sie die Datei my_function.py im Verzeichnis ~/project, um den folgenden Code einzuschließen:

## ~/project/my_function.py
from unittest import mock

def greet(name):
  """This function greets the person passed in as a parameter."""
  print(f"Hello, {name}!")

## Create a mock object for the greet function
mock_greet = mock.Mock(wraps=greet)

## Example usage
mock_greet("Alice")
mock_greet("Bob")

## Print the number of times the function was called
print(f"The greet function was called {mock_greet.call_count} times.")

## Print the arguments the function was called with
print(f"The calls were: {mock_greet.call_args_list}")

In diesem Code:

  • Wir importieren das mock-Modul aus unittest.
  • Wir erstellen ein mock.Mock-Objekt, das die greet-Funktion umhüllt. Das wraps-Argument teilt dem Mock-Objekt mit, die ursprüngliche greet-Funktion aufzurufen, wenn es aufgerufen wird.
  • Wir rufen dann das mock_greet-Objekt anstelle der ursprünglichen greet-Funktion auf.
  • Schließlich verwenden wir die Attribute call_count und call_args_list des Mock-Objekts, um Informationen über die Funktionsaufrufe zu erhalten.

Führen Sie das Skript erneut mit demselben Befehl aus:

python ~/project/my_function.py

Sie sollten eine Ausgabe ähnlich der folgenden sehen:

Hello, Alice!
Hello, Bob!
The greet function was called 2 times.
The calls were: [call('Alice'), call('Bob')]

Diese Ausgabe zeigt, dass die greet-Funktion zweimal aufgerufen wurde, und es zeigt auch die Argumente, die bei jedem Aufruf an die Funktion übergeben wurden.

Jetzt betrachten wir die call_args_list genauer. Es ist eine Liste von call-Objekten, die jeweils einen einzelnen Aufruf der gemockten Funktion darstellen. Sie können die Argumente jedes Aufrufs über die Attribute args und kwargs des call-Objekts zugreifen.

Beispielsweise ändern wir den Code, um die Argumente des ersten Aufrufs auszugeben:

## ~/project/my_function.py
from unittest import mock

def greet(name):
  """This function greets the person passed in as a parameter."""
  print(f"Hello, {name}!")

## Create a mock object for the greet function
mock_greet = mock.Mock(wraps=greet)

## Example usage
mock_greet("Alice")
mock_greet("Bob")

## Print the number of times the function was called
print(f"The greet function was called {mock_greet.call_count} times.")

## Print the arguments the function was called with
print(f"The calls were: {mock_greet.call_args_list}")

## Print the arguments of the first call
if mock_greet.call_args_list:
  print(f"The arguments of the first call were: {mock_greet.call_args_list[0].args}")

Führen Sie das Skript erneut aus:

python ~/project/my_function.py

Sie sollten eine Ausgabe ähnlich der folgenden sehen:

Hello, Alice!
Hello, Bob!
The greet function was called 2 times.
The calls were: [call('Alice'), call('Bob')]
The arguments of the first call were: ('Alice',)

Diese Ausgabe zeigt, dass der erste Aufruf von greet mit dem Argument "Alice" erfolgt ist.

Das unittest.mock-Modul bietet eine leistungsstarke und flexible Möglichkeit, Funktionsaufrufe in Python zu überwachen. Es ist ein wertvolles Werkzeug für das Testen, Debugging und die Leistungsanalyse.

Zusammenfassung

In diesem Lab (Praktikum) haben wir zunächst die Wichtigkeit des Nachverfolgens von Funktionsaufrufen für das Debugging, die Leistungsanalyse und das Testen in Python verstanden. Wir haben eine einfache greet-Funktion erstellt, die eine Begrüßung ausgibt, und dann manuell die Anzahl der Aufrufe dieser Funktion verfolgt, indem wir eine globale Variable invocation_count eingeführt und sie innerhalb der Funktion erhöht haben. Dies hat es uns ermöglicht, zu überwachen, wie oft die Funktion ausgeführt wurde.