Fassen wir den Grad der Kopplung zwischen Modulen mit Python-Code zusammen

Zweck

Ich habe nicht viel angerührt, seit ich mit grundlegenden Informationen studiert habe, und zu diesem Zeitpunkt habe ich nicht versucht, Code zu schreiben, also habe ich beschlossen, wieder zu lernen.

Wie hoch ist der Kopplungsgrad zwischen Modulen?

Es zeigt, wie stark die Beziehung zwischen Modulen ist. Es wird gesagt, dass die Unabhängigkeit von Modulen erhöht werden kann, indem der Grad der Kopplung zwischen Modulen verringert wird. Eine erhöhte Modulunabhängigkeit hat folgende Vorteile:

Schauen Sie sich zum Beispiel den folgenden Code an. Diese Funktion bestimmt anhand des aktuellen westlichen Kalenders, ob es sich um ein feuchtes Jahr handelt.

Code mit geringer Modulunabhängigkeit ist nur wenig wiederverwendbar

from datetime import datetime
from calendar import isleap

#Eine Funktion, die bestimmt, ob dieses Jahr ein feuchtes Jahr ist und das Ergebnis ausgibt
def A():
    this_year = datetime.now().year
    if isleap(this_year):
        print('Dieses Jahr ist ein feuchtes Jahr')
    else:
        print('Dieses Jahr ist kein feuchtes Jahr')

Angenommen, Sie möchten einen "Mechanismus zur Bestimmung, ob vor 10 Jahren ein feuchtes Jahr war" in dieses Modul integrieren.

from datetime import datetime
from calendar import isleap

#Eine Funktion, die bestimmt, ob dieses Jahr ein feuchtes Jahr ist und das Ergebnis ausgibt
def A():
    this_year = datetime.now().year
    if isleap(this_year):
        print('Dieses Jahr ist ein feuchtes Jahr')
    else:
        print('Dieses Jahr ist kein feuchtes Jahr')

#Eine Funktion, die bestimmt, ob vor 10 Jahren ein feuchtes Jahr ist, und das Ergebnis ausgibt
def B():
    this_year = datetime.now().year - 10
    if isleap(this_year):
        print('Vor 10 Jahren ist ein feuchtes Jahr')
    else:
        print('Vor 10 Jahren ist kein feuchtes Jahr')

Code mit geringer Modulunabhängigkeit ist schwer zu testen

Fast der gleiche Code ist geschrieben und fühlt sich intuitiv überhaupt nicht gut an. Außerdem treten beim Testen Probleme auf. Nehmen wir an, Sie möchten die folgenden Testdaten für Funktion A eingeben und testen, ob das Jahr der Schwellung richtig beurteilt wird.

Testdaten Erwarteter Wert
2000 Dieses Jahr ist ein feuchtes Jahr
2020 Dieses Jahr ist ein feuchtes Jahr
2100 Dieses Jahr ist kein feuchtes Jahr

Wie testest du es?

Korrekt. Dies kann nicht getestet werden. Dies liegt daran, dass beide Funktionen A und B eine Mischung aus "Verarbeitung zum Finden des aktuellen Kalenders" und "Mechanismus zum Bestimmen des Jahres der Lauheit" aufweisen und ihre Funktionen nicht unabhängig sind.

Daher ist es besser, dies zu tun.

def A(year):
    if isleap(year):
        print('Dieses Jahr ist ein feuchtes Jahr')
    else:
        print('Dieses Jahr ist kein feuchtes Jahr')

Auf diese Weise sollten die Kalenderinformationen von außen eingegeben werden. Egal ob vor 10 Jahren, vor 100 Jahren oder vor 200 Jahren, Sie benötigen nur eine Funktion, unabhängig davon, ob Sie mehrere Testdaten haben.

Es gibt einen Bewertungsstandard für den Grad der Modulkopplung

Es gibt verschiedene Arten der Kopplung zwischen Modulen.

Evaluationskriterien Kopplungsgrad zwischen Modulen Modulunabhängigkeit
Innere Verbindung hoch Niedrig
Gemeinsame Verbindung
Äußere Verbindung
Control Join
Stempelkombination
Datenverbindung Niedrig hoch

Von hier aus werde ich es mit einem Code zusammenfassen. Dieses Mal werde ich es mit Python reproduzieren.

Innere Verbindung

Dies ist heutzutage fast unmöglich und schwer zu reproduzieren ... Ist es so, wenn du es erzwingst?

Es gibt ein solches Modul. Benutzername, Level, Angriff, Verteidigung usw. werden als globale Variablen definiert.

moduleA.py


username = 'hogehogekun'
level = 25
attack = 20
defence = 5

def show_user_status():
    print('Nutzername:' + username)
    print('Niveau:' + str(level))
    print('Offensivkraft:' + str(attack))
    print('Verteidigungskraft:' + str(defence))

Angenommen, Sie haben Code, der dies ausnutzt.

main.py


import moduleA

#Erhöhen Sie das Level um 1
moduleA.level += 1

#Status mit der Funktion moduleA anzeigen
moduleA.show_user_status()

Ergebnis


Benutzername: hogehogekun
Stufe: 26
Angriffskraft: 20
Verteidigung: 5

Der Anfangswert des Levels war 25, aber er hat sich um 1 erhöht. Es gibt kein Problem mit dem Verhalten, aber das Verhalten von Modul A hängt stark vom Verhalten des Hauptmoduls ab.

Gemeinsame Verbindung

Angenommen, Sie haben Benutzerinformationen in einer Klasse zusammengefasst und in einer Liste verwaltet.

moduleA.py


class User:
    def __init__(self, username, level, attack, defence):
        self.username = username
        self.level = level
        self.attack = attack
        self.defence = defence

    def show_user_status(self):
        print('Nutzername:' + self.username)
        print('Niveau:' + str(self.level))
        print('Offensivkraft:' + str(self.attack))
        print('Verteidigungskraft:' + str(self.defence))

#Verwalten Sie die Liste der Benutzer in einer Liste
user_list = [User('hogehogekun', 75, 90, 80), User('fugafugakun', 10, 5, 7)]

Angenommen, in mainA gibt es zwei Funktionen, die dieses Modul verwenden.

mainA.py


import moduleA

def funcA():
  del(moduleA.user_list[0])

def funcB():
  print(moduleA.user_list[0].username)


#In der Reihenfolge funcA, funcB ausführen
funcA()
funcB()

Ergebnis


fugafugakun

Vielleicht hat funcA diesmal das erste Element der globalen Liste gelöscht. Als funcB einen Blick darauf warf, war Hogehoge bereits verschwunden und hinterließ nur noch Fugafuga. Wenn funcB auf moduleA.user_list [1] verweist, tritt übrigens IndexError auf. Auf diese Weise müssen Sie beim gemeinsamen Join, wenn Sie einen Teil der gemeinsamen Datenstruktur ändern oder löschen, alle Module überprüfen, die auf den gemeinsamen Teil verweisen.

Äußere Verbindung

Sehr ähnlich einem allgemeinen Join, aber die Wahrnehmung, dass die gemeinsam genutzten Informationen eher eine Sammlung einzelner Daten als eine Datenstruktur wie eine Liste oder ein Objekt sind.

Nehmen wir diesmal an, dass Informationen zur kumulierten Benutzeranzahl und zum Dienststatus vorliegen.

moduleA.py


class User:
    def __init__(self, username, level, attack, defence):
        self.username = username
        self.level = level
        self.attack = attack
        self.defence = defence

    def show_user_status(self):
        print('Nutzername:' + self.username)
        print('Niveau:' + str(self.level))
        print('Offensivkraft:' + str(self.attack))
        print('Verteidigungskraft:' + str(self.defence))

user_count = 123091 #Kumulierte Anzahl von Benutzern
service_status = 200 #Service Status

main.py


import moduleA

def funcA():
    print(moduleA.user_count)

def funcB():
    print(moduleA.service_status)

funcA()
funcB()

Ergebnis


123091
200

Dieser Code hat keine Verhaltensprobleme. Sowohl die Anzahl der Benutzer als auch der Servicestatus wurden in funcA und funcB korrekt erfasst. Wenn jedoch eine Spezifikationsänderung wie der service_status von moduleA.py zu einem Zeichentyp anstelle eines numerischen Typs wird, muss funcB geändert werden, das auf die entsprechenden Informationen verweist.

Control Join

Control Join verwendet Argumente, um die Verarbeitung der aufgerufenen Funktion zu steuern. In diesem Code wird eine unterschiedliche Verarbeitung durchgeführt, je nachdem, ob 1 oder 2 an some_command übergeben wird.

moduleA.py


class User:
    def __init__(self, username, level, attack, defence):
        self.username = username
        self.level = level
        self.attack = attack
        self.defence = defence

    def some_command(self, command_id):
        if command_id == 1: #Befehl zur Statusanzeige
            print('Nutzername:' + self.username)
            print('Niveau:' + str(self.level))
            print('Offensivkraft:' + str(self.attack))
            print('Verteidigungskraft:' + str(self.defence))

        elif command_id == 2: #Level-up-Befehl
            print(self.username + 'Level wurde um 1 erhöht!')
            self.level += 1

main.py


from moduleA import User

user1 = User('hogehogekun', 40, 20, 20)
user1.some_command(1)
user1.some_command(2)

Ergebnis


Benutzername: hogehogekun
Stufe: 40
Angriffskraft: 20
Verteidigung: 20
Das Level von Hogehogekun wurde um 1 erhöht!

Auf den ersten Blick sieht es gut aus, weil die als Befehl bezeichneten Informationen von außen weitergegeben werden. Ein anderes Modul, das some_command aufruft, muss die interne Struktur von some_command kennen. Daher ist der Kopplungsgrad relativ hoch.

Stempelkombination

Benutzerklasse wie gewohnt. Dieses Mal konzentrieren wir uns auf den Austausch zwischen funcA und funcB in main.py. Das Aufrufen von funcB in funcA und das Übergeben einer Liste als Argument sieht aus wie eine Art Code.

moduleA.py


class User:
    def __init__(self, username, level, attack, defence):
        self.username = username
        self.level = level
        self.attack = attack
        self.defence = defence

    def show_user_status(self):
        print('Nutzername:' + self.username)
        print('Niveau:' + str(self.level))
        print('Offensivkraft:' + str(self.attack))
        print('Verteidigungskraft:' + str(self.defence))

Angenommen, ein anderes Modul verhält sich so.

main.py


from moduleA import User

def funcA():
    user_list = [User('hogehogekun', 20, 10, 10), User('fugafugakun', 99, 99, 99), User('piyopiyokun', 99, 99, 99)]
    funcB(user_list)

def funcB(user_list):
    print(user_list[2].username)

funcA()

Ergebnis


piyopiyokun

An dieser Stelle ist daran nichts auszusetzen, aber wenn sich beispielsweise die Anzahl der Elemente in funcA ändert, ist funcB betroffen.

main.py


def funcA():
    user_list = [User('hogehogekun', 20, 10, 10), User('fugafugakun', 99, 99, 99)]
    funcB(user_list)

def funcB(user_list):
    print(user_list[2].username)

funcA()

Ergebnis


IndexError: list index out of range

In der Stempelkombination wird die gesamte Liste übergeben, das aufrufende Modul verwendet jedoch nur einige Informationen. Dieses Mal verwendet funcB nur das dritte Element, obwohl ihm eine Liste mit drei Elementen übergeben wird. Zu diesem Zeitpunkt kann funcB betroffen sein, selbst wenn sich die Elemente ändern, die nicht auf der funcB-Seite (in diesem Fall die Nummer) in der Stempelkombination verwendet werden.

Datenverbindung

Minimiert die zwischen mehreren Modulen übertragenen Informationen. Nach dem Beispiel einer Stempelkombination sieht es so aus.

moduleA.py


class User:
    def __init__(self, username, level, attack, defence):
        self.username = username
        self.level = level
        self.attack = attack
        self.defence = defence

    def show_user_status(self):
        print('Nutzername:' + self.username)
        print('Niveau:' + str(self.level))
        print('Offensivkraft:' + str(self.attack))
        print('Verteidigungskraft:' + str(self.defence))

main.py


def funcA():
    user_list = [User('hogehogekun', 20, 10, 10), User('fugafugakun', 99, 99, 99), User('piyopiyokun', 99, 99, 99)]
    funcB(user_list[2])

def funcB(target_user):
    print(target_user.username)

funcA()

Ergebnis


piyopiyokun

Da funcB nur piyopiyokun verarbeitet, sind die zu übergebenden Daten in erster Linie nur user_list [2]. Wenn dies die Anzahl der Benutzerlisten verringert, sollte dies funcA, nicht jedoch funcB betreffen. Erstens bedeutet die Verringerung der Anzahl der Benutzerlisten, dass funcA geändert wird, sodass der Einflussbereich erheblich kleiner sein kann.

Auf diese Weise kann der Kopplungsgrad von Modulen geschwächt werden, indem nur die erforderlichen Informationen ausgetauscht werden.

Nachtrag: Als ich das Buch las, das ich hatte, hieß es: "Das aufrufende Modul kann die aufrufenden Daten mit den empfangenen Argumenten direkt bearbeiten." Mit anderen Worten, es scheint, dass Sie als Referenz übergeben sollten. Je nach Entwickler und Entwicklungsmethode schien es hier unterschiedliche Denkweisen zu geben.

Zusammenfassung

Es gibt verschiedene Vorteile, wenn die Stärke der Module hoch und der Grad der Kopplung zwischen den Modulen niedrig eingestellt wird.

Und so weiter!

Recommended Posts

Fassen wir den Grad der Kopplung zwischen Modulen mit Python-Code zusammen
Konvertieren Sie den Zeichencode der Datei mit Python3
Lassen Sie uns die Grundlagen des Python-Codes von TensorFlow aufschlüsseln
Berühren wir die API der Netatmo Weather Station mit Python. #Python #Netatmo
Messen Sie die Testabdeckung von Push-Python-Code auf GitHub.
[Python3] Schreiben Sie das Codeobjekt der Funktion neu
Lesen wir die RINEX-Datei mit Python ①
Fassen wir den Python-Codierungsstandard PEP8 (1) zusammen.
Fassen wir den Python-Codierungsstandard PEP8 (2) zusammen.
[Python] Ruft den Zeichencode der Datei ab
[Python] Lesen Sie den Quellcode von Flasche Teil 2
Zusammenfassung der Unterschiede zwischen PHP und Python
2016 Todai Mathematik mit Python gelöst
[Hinweis] Exportieren Sie das HTML der Site mit Python.
Die Antwort von "1/2" unterscheidet sich zwischen Python2 und 3
Berechnen Sie die Gesamtzahl der Kombinationen mit Python
Überprüfen Sie das Datum der Flaggenpflicht mit Python
Code zum Überprüfen des Betriebs von Python Matplot lib
Statische Analyse von Python-Code mit GitLab CI
[Python] Bestimmen Sie den Typ der Iris mit SVM
[Blender x Python] Denken Sie an Code mit Symbolen
Simulieren wir den Übergang der Infektionsrate in Bezug auf die Bevölkerungsdichte mit Python
Lassen Sie uns mit Python Receive spielen und den Text des Eingabeformulars speichern / anzeigen
Richten Sie die Anzahl der Stichproben zwischen Datenklassen für maschinelles Lernen mit Python aus
Einfache Möglichkeit, die Quelle der Python-Module zu überprüfen
Extrahieren Sie die Tabelle der Bilddateien mit OneDrive & Python
Lerne Nim mit Python (ab Anfang des Jahres).
Zerstören Sie den Zwischenausdruck der Sweep-Methode mit Python
der Zen von Python
Visualisieren Sie den Bereich der internen und externen Einfügungen mit Python
Holen Sie sich den Rückkehrcode eines Python-Skripts von bat
Berechnen Sie den Regressionskoeffizienten der einfachen Regressionsanalyse mit Python
Verwenden wir die Python-Version des Confluence-API-Moduls.
Verwenden wir die offenen Daten von "Mamebus" in Python
Zusammenfassung des grundlegenden Ablaufs des maschinellen Lernens mit Python
Holen Sie sich mit Python den Betriebsstatus von JR West
Lassen Sie uns GPIO von Raspeye mit Python CGI betreiben
[Python] Lassen Sie uns die URL der Django-Administrator-Site ändern
Ich habe versucht, die String-Operationen von Python zusammenzufassen
Ich habe versucht, die Entropie des Bildes mit Python zu finden
Versuchen Sie, COVID-19 Tokyo-Daten mit Python zu kratzen
Ich habe versucht, das Bild mit Python + OpenCV "gammakorrektur" zu machen
Die Geschichte der Implementierung des Themas Facebook Messenger Bot mit Python
Lassen Sie uns jupyter ausführen, das von VS Code nativ mit python3.8 unterstützt wird
Vereinheitlichen Sie die Umgebung des Python-Entwicklungsteams, beginnend mit Poetry
Visualisieren Sie die Ergebnisse von Entscheidungsbäumen, die mit Python scikit-learn erstellt wurden
Berechnen Sie mit Python Millionen von Stellen in der Quadratwurzel von 2
Lassen Sie uns den Befehl pünktlich mit dem Bot der Zwietracht ausführen
Führen Sie die Intelligenz Ihrer eigenen Python-Bibliothek mit VScode aus.
Ich habe die Strategie des Aktiensystemhandels mit Python evaluiert.
Die Geschichte eines Rubinisten, der mit Python :: Dict-Daten mit Pycall kämpft
[Homologie] Zählen Sie mit Python die Anzahl der Löcher in den Daten
Versuchen Sie, den Betrieb von Netzwerkgeräten mit Python zu automatisieren
Stellen wir uns die Anzahl der mit Matplotlib mit dem Coronavirus infizierten Personen vor
Die Geschichte, dass Python nicht mehr mit VS Code (Windows 10) arbeitet
Schreiben Sie den Datensatzadditionsknoten von SPSS Modeler mit Python neu.
Der Prozess, Python-Code objektorientiert zu machen und zu verbessern