Ecrire une courte définition de propriété en Python

Le code qui définit normalement les propriétés avec @ property``` est long

En Python, vous pouvez définir des propriétés à l'aide du décorateur de propriétés comme suit. À titre d'exemple, une classe User avec des propriétés nommées name et email peut être définie comme suit:

class User:

    def __init__(self, *, name=None, email=None):
        self.__name = name
        self.__email = email

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, name):
        self.__name = name

    @property
    def email(self):
        return self.__email

    @email.setter
    def email(self, email):
        self.__email = email

Vous pouvez écrire la valeur d'une propriété sous la forme user.name, et définir la valeur comme ```user.name = "Taro" `` `.

user = User(name="taro", email="[email protected]")
print(user.name) # => "taro"
user.name = "Taro"
print(user.name) # => "Taro"

Il n'y a rien qui semble ennuyeux du côté qui utilise la classe User, mais du point de vue du côté qui définit la classe User, c'est ennuyeux car il faut écrire autant de codes similaires qu'il y a de propriétés.

Créer une fonction d'assistance qui définit les propriétés

Par conséquent, définissez la fonction d'assistance suivante.

def define_property(self, name, value=None):
    # "_User__name"Nom après nom mutilant.
    field_name = "_{}__{}".format(self.__class__.__name__, name)

    #Définir la valeur initiale.
    setattr(self, field_name, value)

    # getter/Générer setter,Définir les propriétés.
    getter = lambda _: getattr(self, field_name)
    setter = lambda _, value: setattr(self, field_name, value)
    setattr(self.__class__, name, property(getter, setter))

Avec cela, la définition de la classe User peut être raccourcie comme suit.

class User:
    def __init__(self, *, name=None, email=None):
        define_property(self, "name", name)
        define_property(self, "email", email)

define_propertyMême si j'ai pu réduire considérablement la quantité de code,nameOuemailJe pense qu'écrire plusieurs fois est redondant.

Créer un décorateur pour le constructeur

Par conséquent, créez un décorateur pour le constructeur.

def define_properties(*names):
    def decorator(constructor):
        def wrapper(self, **kwargs):
            for name in names:
                define_property(self, name, kwargs.get(name))
            constructor(self, **kwargs)
        return wrapper
    return decorator

define_propertiesVous pouvez utiliser pour réécrire la classe d'utilisateurs comme suit:

class User:
    @define_properties("name", "email")
    def __init__(self):
        pass

Il n'y a pas de redondance. Il sera complété par un peu plus d'amélioration.

Formulaire rempli

Pour le rendre un peu plus pratique, apportez les modifications suivantes:

Le code modifié est le suivant.

define_property.py


def define_property(self, name, value=None, readable=True, writable=True):
    # "_User__name"Nom après nom mutilant.
    field_name = "_{}__{}".format(self.__class__.__name__, name)

    #Définir la valeur initiale.
    setattr(self, field_name, value)

    # getter/Générer setter,Définir les propriétés.
    getter = (lambda self: getattr(self, field_name)) if readable else None
    setter = (lambda self, value: setattr(self, field_name, value)) if writable else None
    setattr(self.__class__, name, property(getter, setter))

def define_properties(constructor=None, *, accessible=(), readable=(), writable=()):
    if callable(constructor):
        def wrapper(self, *args, **kwargs):
            for name, value in kwargs.items():
                define_property(self, name, value)
            constructor(self, *args, **kwargs)
        return wrapper
    else:
        to_set = lambda x: set(x) if any(isinstance(x, type_) for type_ in (set, list, tuple)) else {x}
        accessibles = to_set(accessible)
        readables = accessibles | to_set(readable)
        writables = accessibles | to_set(writable)

        def decorator(constructor):
            def wrapper(self, *args, **kwargs):
                for name in (readables | writables):
                    readable = name in readables
                    writable = name in writables
                    initial_value = kwargs.get(name, None)
                    define_property(self, name, initial_value, readable, writable)
                constructor_kwargs = dict([(key, kwargs[key]) for key in (constructor.__kwdefaults__ or {}) if key in kwargs])
                constructor(self, *args, **constructor_kwargs)
            return wrapper
        return decorator

Le code de test est le suivant.

define_property_test.rb


import unittest
from define_property import *

class DefinePropertyTest(unittest.TestCase):

    def test_initial_value(self):
        class User:
            def __init__(self, *, name=None, email=None):
                define_property(self, "name", name)
                define_property(self, "email", email)

        user = User()
        taro = User(name="taro", email="[email protected]")
        self.assertEqual(None, user.name)
        self.assertEqual(None, user.email)
        self.assertEqual("taro", taro.name)
        self.assertEqual("[email protected]", taro.email)

    def test_accessor(self):
        class User:
            def __init__(self, *, name=None):
                define_property(self, "name", name)

        taro = User(name="taro")
        self.assertEqual("taro", taro.name)
        taro.name = "Taro"
        self.assertEqual("Taro", taro.name)

    def test_readable(self):
        class User:
            def __init__(self, *, name=None, email=None):
                define_property(self, "name", name, readable=True)
                define_property(self, "email", email, readable=False)

        taro = User(name="taro", email="[email protected]")
        taro.name
        with self.assertRaises(AttributeError):
            taro.email

    def test_writable(self):
        class User:
            def __init__(self, *, name=None, email=None):
                define_property(self, "name", name, writable=True)
                define_property(self, "email", email, writable=False)

        taro = User(name="taro", email="[email protected]")
        taro.name = "Taro"
        with self.assertRaises(AttributeError):
            taro.email = "[email protected]"

    def test_not_accessible(self):
        class User:
            def __init__(self, *, name=None, email=None):
                define_property(self, "name", name, readable=False)
                define_property(self, "email", email, readable=False)

        taro = User(name="taro", email="[email protected]")
        with self.assertRaises(AttributeError):
            taro.name
        with self.assertRaises(AttributeError):
            taro.email

    def test_access_by_other_method(self):
        class User:
            def __init__(self, *, name=None, email=None):
                define_property(self, "name", name)
            def get_name(self):
                return self.__name

        taro = User(name="taro")
        self.assertEqual("taro", taro.get_name())

class DefinePropertiesTest(unittest.TestCase):

    def test_no_arguments(self):
        class User:
            @define_properties
            def __init__(self, *, name=None, email=None):
                pass

        with self.assertRaises(AttributeError):
            User().name
        User(name="taro").name

        with self.assertRaises(AttributeError):
            User(name="taro").email
        User(name="taro", email="[email protected]").email

    def test_initial_value(self):
        class User:
            @define_properties(accessible=("name", "email"))
            def __init__(self, *, name=None, email=None):
                if name != None:
                    self.__name = self.name.upper()
                if email != None:
                    self.__email = self.email.upper()

        user = User()
        self.assertEqual(None, user.name)
        self.assertEqual(None, user.email)

        taro = User(name="taro", email="[email protected]")
        self.assertEqual("TARO", taro.name)
        self.assertEqual("[email protected]", taro.email)

    def test_accessible_with_no_arguments(self):
        class User:
            @define_properties(accessible=())
            def __init__(self):
                pass

        user = User()
        with self.assertRaises(AttributeError):
            user.name

    def test_accessible_with_string_argument(self):
        class User:
            @define_properties(accessible="name")
            def __init__(self):
                pass

        user = User()
        self.assertEqual(None, user.name)
        user.name = "jiro"
        self.assertEqual("jiro", user.name)

        user = User(name="taro")
        self.assertEqual("taro", user.name)
        user.name = "jiro"
        self.assertEqual("jiro", user.name)

    def test_accessible_with_tuple_argument(self):
        class User:
            @define_properties(accessible=("name", "email"))
            def __init__(self):
                pass

        user = User()
        self.assertEqual(None, user.name)
        self.assertEqual(None, user.email)
        user.name = "jiro"
        user.email = "[email protected]"
        self.assertEqual("jiro", user.name)
        self.assertEqual("[email protected]", user.email)

        user = User(name="taro", email="[email protected]")
        self.assertEqual("taro", user.name)
        self.assertEqual("[email protected]", user.email)
        user.name = "jiro"
        user.email = "[email protected]"
        self.assertEqual("jiro", user.name)
        self.assertEqual("[email protected]", user.email)

    def test_readable_with_no_arguments(self):
        class User:
            @define_properties(readable=())
            def __init__(self):
                pass

        user = User()
        with self.assertRaises(AttributeError):
            user.name

    def test_readable_with_string_argument(self):
        class User:
            @define_properties(readable="name")
            def __init__(self):
                pass

        user = User()
        self.assertEqual(None, user.name)
        with self.assertRaises(AttributeError):
            user.name = "jiro"

        user = User(name="taro")
        self.assertEqual("taro", user.name)
        with self.assertRaises(AttributeError):
            user.name = "jiro"

    def test_readable_with_tuple_argument(self):
        class User:
            @define_properties(readable=("name", "email"))
            def __init__(self):
                pass

        user = User()
        self.assertEqual(None, user.name)
        self.assertEqual(None, user.email)
        with self.assertRaises(AttributeError):
            user.name = "jiro"
        with self.assertRaises(AttributeError):
            user.email = "[email protected]"

        user = User(name="taro", email="[email protected]")
        self.assertEqual("taro", user.name)
        self.assertEqual("[email protected]", user.email)
        with self.assertRaises(AttributeError):
            user.name = "jiro"
        with self.assertRaises(AttributeError):
            user.email = "[email protected]"

    def test_writable_with_no_arguments(self):
        class User:
            @define_properties(writable=())
            def __init__(self):
                pass

        user = User()
        with self.assertRaises(AttributeError):
            user.name
        user.name = "taro"

    def test_writable_with_string_argument(self):
        class User:
            @define_properties(writable="name")
            def __init__(self):
                pass

        user = User()
        with self.assertRaises(AttributeError):
            user.name
        user.name = "jiro"

        user = User(name="taro")
        with self.assertRaises(AttributeError):
            user.name
        user.name = "jiro"

    def test_writable_with_tuple_argument(self):
        class User:
            @define_properties(writable=("name", "email"))
            def __init__(self):
                pass

        user = User()
        with self.assertRaises(AttributeError):
            user.name
        with self.assertRaises(AttributeError):
            user.email
        user.name = "jiro"
        user.email = "[email protected]"

        user = User(name="taro", email="[email protected]")
        with self.assertRaises(AttributeError):
            user.name
        with self.assertRaises(AttributeError):
            user.email
        user.name = "jiro"
        user.email = "[email protected]"

if __name__ == "__main__":
    unittest.main()

Recommended Posts

Ecrire une courte définition de propriété en Python
Ecrire des algorithmes A * (A-star) en Python
Ecrire un graphique à secteurs en Python
Ecrire le plugin vim en Python
Écrire une recherche de priorité en profondeur en Python
Ecrire le test dans la docstring python
Ecrire un programme de chiffrement Caesar en Python
Ecrire une méthode de cupidité simple en Python
Ecrire un plugin Vim simple en Python 3
Ecrire Python dans MySQL
Ecrire des filtres Pandec en Python
Créer une fonction en Python
Créer un dictionnaire en Python
Ecrire un programme de dynamique moléculaire super simple en python
Écrire une distribution bêta en Python
Ecrire python dans Rstudio (réticulé)
Je veux écrire en Python! (2) Écrivons un test
Créer un bookmarklet en Python
Ecrire un histogramme à l'échelle logarithmique sur l'axe des x en python
Dessinez un cœur en Python
Probablement dans un serpent Nishiki (Titre original: Peut-être en Python)
Ecrire un test piloté par table en C
[python] Gérer les fonctions dans une liste
Définition du type d'argument de fonction en python
Ecrire un schéma JSON avec Python DSL
Créer un conteneur DI avec Python
Ecrire un serveur HTTP / 2 en Python
Dessinez une matrice de diagramme de dispersion avec python
Ecrire une fonction AWS Lambda en Python
ABC166 en Python A ~ C problème
Créer un fichier binaire en Python
Ecrire le code de test du sélénium en python
Résoudre ABC036 A ~ C avec Python
Implémentation d'un algorithme simple en Python 2
Résoudre ABC037 A ~ C avec Python
Exécutez un algorithme simple en Python
Dessinez un diagramme CNN en Python
Créer une chaîne aléatoire en Python
Ecrire un test unitaire de langage C en Python
Ecrire un script batch avec Python3.5 ~
Lors de l'écriture d'un programme en Python
J'obtiens un attribut impossible à définir lors de l'utilisation de @property en python
Écrire de la documentation dans Sphinx avec Python Livereload
Livre en spirale en Python! Python avec un livre en spirale! (Chapitre 14 ~)
Résoudre ABC175 A, B, C avec Python
Utiliser l'impression dans l'expression lambda Python2
Un client HTTP simple implémenté en Python
Faites une visite Euler non récursive en Python
J'ai fait un programme de gestion de la paie en Python!
Essayez d'envoyer un paquet SYN en Python
Essayez de dessiner une animation simple en Python
Créer une application GUI simple en Python
Dessiner un cœur avec Python Partie 2 (SymPy Edition)
[Python] [Windows] Faites une capture d'écran avec Python
Ecrire le fichier O_SYNC en C et Python
Exécuter l'interpréteur Python dans le script
Comment obtenir stacktrace en python