[PYTHON] Implémenter un modèle avec état et comportement

Considérez les interrupteurs (boutons d'alimentation pour l'éclairage, boutons de destination à chaque étage de l'ascenseur, etc.) comme des modèles primitifs avec état et comportement. Le commutateur a deux états, un état enfoncé «on» et un état non pressé «off». De plus, le comportement du commutateur switch () change en fonction de l'état. S'il est dans l'état pressé «on», il sera dans l'état non pressé «off», et s'il n'est pas pressé, il sera dans l'état pressé «on».

example1


class Switch:
    def __init__(self, state="off"):
        self.state = state

    def switch(self):
        if self.state == "on":
            self.state = "off"
        elif self.state == "off":
            self.state = "on"
        else:
            # I wonder whether it should be ValueError().
            raise RuntimeError(self.__class__.__name__ + " has an unexpected state: {}".format(self.state))


switch = Switch()
assert switch.state == "off"
switch.switch()
assert switch.state == "on"
switch.switch()
assert switch.state == "off"
switch.state = True
switch.switch()
-> RuntimeError: Switch has an unexpected state: True

Pour les valeurs (états) possibles de Switch.state, vous devez regarder l'implémentation de Switch. Par exemple, l'utilisation de valeurs énumérées pour représenter des états peut améliorer la visibilité.

example2


from enum import Enum, auto


class SwitchState(Enum):
    ON = auto()
    OFF = auto()


class Switch:
    def __init__(self, state=SwitchState.OFF):
        self.state = state

    def switch(self):
        if self.state == SwitchState.ON:
            self.state = SwitchState.OFF
        elif self.state == SwitchState.OFF:
            self.state = SwitchState.ON
        else:
            raise RuntimeError(self.__class__.__name__ + " has an unexpected state: {}".format(self.state))


switch = Switch(SwitchState.ON)
switch.switch()
switch = Switch("on")  # warning: expected SwitchState type

De plus, si la valeur par défaut de l'argument du constructeur «state» est définie sur «SwitchState», un avertissement sera émis pour les valeurs autres que «SwitchState». Cependant, des valeurs inattendues telles que ʻon peuvent être affectées à Switch.state` comme suit:

switch.state = True
switch.switch()  # RuntimeError: Switch has an unexpected state: True

Vous ne remarquez pas qu'une valeur inattendue a été attribuée jusqu'à ce que switch () soit appelé. Par conséquent, il est plus facile d'envoyer une TypeError lorsqu'une valeur inattendue est affectée à Switch.state comme indiqué ci-dessous.

example2


class Switch:
    def __init__(self, state=SwitchState.OFF):
        self._state = state

    def switch(self):
        if self._state == SwitchState.ON:
            self._state = SwitchState.OFF
        elif self._state == SwitchState.OFF:
            self._state = SwitchState.ON
        else:
            raise RuntimeError(self.__class__.__name__ + " has an unexpected state: {}".format(self._state))

    @property
    def state(self) -> SwitchState:
        return self._state

    @state.setter
    def state(self, value: SwitchState):
        if type(value) is not SwitchState:
            raise TypeError(self.__class__.__name__ + ".state must be SwitchState, but get: {}".format(type(value)))
        self._state = value


switch = Switch(SwitchState.ON)
switch.switch()
switch.state = True  # TypeError: Switch.state must be SwitchState, but get: <class 'bool'>

Si vous ne voulez pas que l'état de Switch soit changé depuis l'extérieur de la classe, il est impossible de définir une valeur dans Switch.state.

class Switch:
    def __init__(self, state=SwitchState.OFF):
        self._state = state

    def switch(self):
        if self._state == SwitchState.ON:
            self._state = SwitchState.OFF
        elif self._state == SwitchState.OFF:
            self._state = SwitchState.ON
        else:
            raise RuntimeError(self.__class__.__name__ + " has an unexpected state: {}".format(self._state))

    @property
    def state(self) -> SwitchState:
        return self._state


switch = Switch(SwitchState.ON)
switch.switch()
switch.state = SwitchState.OFF  # Property cannot be set

Si vous voulez changer l'état de Switch depuis l'extérieur de la classe, il est préférable de fournir des méthodes turn_on (), turn_off () pour la transition d'état plutôt que de céder Switch.state à l'extérieur de la classe. Dans certains cas.

class Switch:
    def __init__(self, state=SwitchState.OFF):
        self._state = state

    def switch(self):
        if self._state == SwitchState.ON:
            self.turn_off()
        elif self._state == SwitchState.OFF:
            self.turn_on()
        else:
            raise RuntimeError(self.__class__.__name__ + " has an unexpected state: {}".format(self._state))

    @property
    def state(self) -> SwitchState:
        return self._state

    def turn_on(self):
        self._state = SwitchState.ON
    
    def turn_off(self):
        self._state = SwitchState.OFF


switch = Switch()
switch.turn_off()
assert switch.state == SwitchState.OFF
switch.switch()
assert switch.state == SwitchState.ON

Enfin, nous modifierons l'implémentation en fonction de l'ajout de fonctions à Switch plus tard. Jusqu'à présent, il était implémenté pour que le comportement change en fonction de l'état (le traitement de la méthode diffère selon l'état), mais il peut aussi être implémenté pour que l'état s'exprime par la différence de comportement (l'état diffère en fonction de la différence de traitement). ça peut.

from enum import Enum, auto


class SwitchState(Enum):
    ON = auto()
    OFF = auto()


class Switch:
    def __init__(self, state=SwitchState.OFF):
        self.switch = self.turn_on if state == SwitchState.OFF else self.turn_off

    @property
    def state(self) -> SwitchState:
        return SwitchState.OFF if self.switch == self.turn_on else SwitchState.ON

    def turn_on(self):
        self.switch = self.turn_off

    def turn_off(self):
        self.switch = self.turn_on


switch = Switch(SwitchState.ON)
switch.switch()
assert switch.state == SwitchState.OFF
switch.switch()
assert switch.state == SwitchState.ON

Il n'y a aucune différence dans la fonctionnalité de «Switch», seule l'implémentation est différente.

Recommended Posts

Implémenter un modèle avec état et comportement
Implémenter un modèle avec état et comportement (3) - Exemple d'implémentation par décorateur
Implémenter un modèle de régression logistique en temps discret avec stan
Créer une visionneuse de modèle 3D avec PyQt5 et PyQtGraph
Créer un itérateur de modèle avec PySide
Un mémo contenant Python2.7 et Python3 dans CentOS
Implémenter un modèle utilisateur personnalisé dans Django
Essayez TensorFlow RNN avec un modèle de base
Créer une pile avec une file d'attente et une file d'attente avec une pile (à partir de LetCode / Implémenter la pile à l'aide de files d'attente, Implémenter la file d'attente à l'aide de piles)
Créer une application Todo avec Django ④ Implémenter la fonction de création de dossier et de tâche
Un modèle qui identifie la guitare avec fast.ai
Connectez Scratch X et Digispark avec bouteille
Chargez le modèle caffe avec Chainer et classez les images
Construire un environnement python avec virtualenv et direnv
Prédire l'été chaud avec un modèle de régression linéaire
Gérez les transitions d'état et communiquez avec les compteurs intelligents
Créez un environnement virtuel avec pyenv et venv
Lancer un serveur Web avec Python et Flask
Compilez et exécutez Rust avec une seule commande
Résolution du modèle Lorenz 96 avec Julia et Python
J'ai essayé d'implémenter "Bases de l'analyse des séries temporelles et du modèle d'espace d'état" (Hayamoto) avec pystan
Créez un modèle de classification d'images de manière explosive avec Azure Custom Vision et implémentez-le avec Flask
Essayez de créer un site Web simple avec responder et sqlite3
J'ai essayé d'implémenter et d'apprendre DCGAN avec PyTorch
Créez un environnement virtuel python avec virtualenv et virtualenvwrapper
Créez une application graphique native avec Py2app et Tkinter
[# 2] Créez Minecraft avec Python. ~ Dessin du modèle et implémentation du lecteur ~
Créez un lot d'images et gonflez avec ImageDataGenerator
J'ai essayé de faire LINE BOT avec Python et Heroku
Créez un environnement virtuel python avec virtualenv et virtualenvwrapper
Créons une application Mac avec Tkinter et py2app
J'ai essayé d'implémenter Grad-CAM avec keras et tensorflow
Implémenter un modèle avec état et comportement (3) - Exemple d'implémentation par décorateur
Exemple d'utilisation de variables de classe et de méthodes de classe
Découvrez Wasserstein GAN avec le modèle Keras et l'optimisation TensorFlow
Jetez un œil au profilage et au vidage avec Dataflow
[Linux] Créez un auto-certificat avec Docker et apache
Construire un environnement de calcul numérique avec pyenv et miniconda3
Implémenter FReLU avec tf.keras
Format A4 avec python-pptx
Complexité et robustesse du modèle
Montage du modèle avec lmfit
Régression avec un modèle linéaire
Décorer avec un décorateur
[Didacticiel d'analyse Python dans la base de données avec SQL Server 2017] Étape 5: Formation et enregistrement des modèles à l'aide de T-SQL
Avec et sans WSGI
Implémenter le modèle mathématique «modèle SIR» des maladies infectieuses avec OpenModelica (exemple de régulation répétée et de relaxation)
J'ai essayé de mettre en œuvre le modèle de base du réseau neuronal récurrent
Enregistrez le modèle pystan et les résultats dans un fichier pickle
Convertissez RVB et HSV sous une forme divisible avec PyTorch
[Django] Gérez les paramètres comme l'écriture dans settings.py avec un modèle
Un simple lecteur de musique interactif fait avec Chuck et OpenPose
À la suite du montage et du réglage avec POH! Lite
Créez une caméra de surveillance WEB avec Raspberry Pi et OpenCV
Implémenter le modèle mathématique «modèle SIR» des maladies infectieuses avec Open Modelica
Associez Python Enum à une fonction pour la rendre appelable
[Azure] Créer, déployer et réapprendre un modèle [ML Studio classic]
Comportement en donnant une liste avec shell = True dans le sous-processus
Créez des applications, enregistrez des données et partagez-les avec un seul e-mail
Créons un diagramme PRML avec Python, Numpy et matplotlib.