@ property``` est longEn 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.
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_property
Même si j'ai pu réduire considérablement la quantité de code,name
Ouemail
Je pense qu'écrire plusieurs fois est redondant.
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_properties
Vous 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.
Pour le rendre un peu plus pratique, apportez les modifications suivantes:
define_property```.
True pour `` `` readable
pour le définir comme lisible.True '' pour
inscriptible '' pour le définir comme inscriptible.
define_properties```.accessible
est définie comme lisible et inscriptible.readable '' et
writable '' sont définies comme lisibles et inscriptibles.
define_properties```, définissez une propriété lisible / inscriptible avec le nom spécifié dans l'argument mot-clé du constructeur.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