Schreiben Sie eine kurze Eigenschaftsdefinition in Python

Code, der normalerweise Eigenschaften mit `` `@ property``` definiert, ist lang

In Python können Sie Eigenschaften mithilfe des Eigenschaftendekorators wie folgt definieren. Beispielsweise kann eine Benutzerklasse mit den Eigenschaften name und email wie folgt definiert werden:

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

Sie können den Wert einer Eigenschaft als `user.name``` und die Werteinstellung als` user.name = "Taro" `` `schreiben.

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

Für die Seite, die die Benutzerklasse verwendet, ist nichts ärgerlich, aber aus der Sicht der Seite, die die Benutzerklasse definiert, ist es ärgerlich, weil Sie so viele ähnliche Codes schreiben müssen, wie es Eigenschaften gibt.

Erstellen Sie eine Hilfsfunktion, die Eigenschaften definiert

Definieren Sie daher die folgende Hilfsfunktion.

def define_property(self, name, value=None):
    # "_User__name"Name nach Name Mangling.
    field_name = "_{}__{}".format(self.__class__.__name__, name)

    #Stellen Sie den Anfangswert ein.
    setattr(self, field_name, value)

    # getter/Setter generieren,Eigenschaften definieren.
    getter = lambda _: getattr(self, field_name)
    setter = lambda _, value: setattr(self, field_name, value)
    setattr(self.__class__, name, property(getter, setter))

Damit kann die Definition der User-Klasse wie folgt gekürzt werden.

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

define_propertyKönnte die Codemenge erheblich reduzieren,nameOderemailIch halte das mehrfache Schreiben für überflüssig.

Erstellen Sie einen Dekorator für den Konstruktor

Erstellen Sie daher einen Dekorator für den Konstruktor.

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_propertiesSie können die Benutzerklasse wie folgt umschreiben:

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

Es gibt keine Redundanz. Es wird mit etwas mehr Verbesserung abgeschlossen.

Vollständiges Formular

Nehmen Sie die folgenden Änderungen vor, um es ein wenig bequemer zu machen:

Der geänderte Code lautet wie folgt.

define_property.py


def define_property(self, name, value=None, readable=True, writable=True):
    # "_User__name"Name nach Name Mangling.
    field_name = "_{}__{}".format(self.__class__.__name__, name)

    #Stellen Sie den Anfangswert ein.
    setattr(self, field_name, value)

    # getter/Setter generieren,Eigenschaften definieren.
    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

Der Testcode lautet wie folgt.

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

Schreiben Sie eine kurze Eigenschaftsdefinition in Python
Schreiben Sie A * (A-Stern) -Algorithmen in Python
Schreiben Sie ein Kreisdiagramm in Python
Schreiben Sie das Vim-Plugin in Python
Schreiben Sie eine Suche mit Tiefenpriorität in Python
Schreiben Sie den Test in die Python-Dokumentzeichenfolge
Schreiben Sie ein Caesar-Verschlüsselungsprogramm in Python
Schreiben Sie eine einfache Giermethode in Python
Schreiben Sie ein einfaches Vim-Plugin in Python 3
Schreiben Sie Python in MySQL
Schreiben Sie Pandec-Filter in Python
Erstellen Sie eine Funktion in Python
Erstellen Sie ein Wörterbuch in Python
Schreiben Sie ein super einfaches molekulardynamisches Programm in Python
Schreiben Sie die Beta-Distribution in Python
Schreiben Sie Python in Rstudio (reticulate)
Ich möchte in Python schreiben! (2) Schreiben wir einen Test
Erstellen Sie ein Lesezeichen in Python
Schreiben Sie in Python ein logarithmisches Histogramm auf die x-Achse
Zeichne ein Herz in Python
Wahrscheinlich in einer Nishiki-Schlange (Originaltitel: Vielleicht in Python)
Schreiben Sie einen tabellengesteuerten Test in C.
[Python] Verwalten Sie Funktionen in einer Liste
Definition des Funktionsargumenttyps in Python
Schreiben Sie ein JSON-Schema mit Python DSL
Erstellen Sie einen DI-Container mit Python
Schreiben Sie einen HTTP / 2-Server in Python
Zeichnen Sie eine Streudiagrammmatrix mit Python
Schreiben Sie die AWS Lambda-Funktion in Python
ABC166 in Python A ~ C Problem
Erstellen Sie eine Binärdatei in Python
Schreiben Sie Selentestcode in Python
Löse ABC036 A ~ C mit Python
Implementierung eines einfachen Algorithmus in Python 2
Löse ABC037 A ~ C mit Python
Führen Sie einen einfachen Algorithmus in Python aus
Zeichnen Sie ein CNN-Diagramm in Python
Erstellen Sie eine zufällige Zeichenfolge in Python
Schreiben Sie einen C-Sprach-Unit-Test in Python
Schreiben Sie ein Batch-Skript mit Python3.5 ~
Beim Schreiben eines Programms in Python
Bei Verwendung von @property in Python wird ein Attribut nicht festgelegt
Spiralbuch in Python! Python mit einem Spiralbuch! (Kapitel 14 ~)
Löse ABC175 A, B, C mit Python
Verwenden Sie print in Python2 lambda expression
Ein einfacher HTTP-Client, der in Python implementiert ist
Führen Sie eine nicht rekursive Euler-Tour in Python durch
Ich habe ein Pay-Management-Programm in Python erstellt!
Versuchen Sie, ein SYN-Paket in Python zu senden
Versuchen Sie, eine einfache Animation in Python zu zeichnen
Erstellen Sie eine einfache GUI-App in Python
Mit Python Teil 2 ein Herz zeichnen (SymPy Edition)
[Python] [Windows] Machen Sie eine Bildschirmaufnahme mit Python
Schreiben Sie die O_SYNC-Datei in C und Python
Führen Sie den Python-Interpreter im Skript aus
Wie bekomme ich Stacktrace in Python?