Un grand nombre des réponses fournies nécessitent autant de lignes par propriété, c'est-à-dire / et / ou - ce que je considérerais comme une implémentation laide ou fastidieuse en raison de la répétitivité requise pour plusieurs propriétés, etc. Je préfère garder les choses en ébullition / les simplifier jusqu'à ce qu'elles ne peut plus être simplifié ou tant que cela ne sert pas à grand chose.
En bref: dans les travaux terminés, si je répète 2 lignes de code, je le convertis généralement en une fonction d'assistance sur une seule ligne, etc. (x, y, w, h) c'est-à-dire x, y, x + w, y + h (nécessitant parfois min / max ou si w / h sont négatifs et que l'implémentation ne l'aime pas, je vais soustraire de x / y et abs w / h, etc.).
Remplacer les getters / setters internes est une bonne façon de procéder, mais le problème est que vous devez le faire pour chaque classe, ou parent de la classe à cette base ... Cela ne fonctionne pas pour moi car je préférerais être libre de choisir les enfants / parents pour l'héritage, les nœuds enfants, etc.
J'ai créé une solution qui répond à la question sans utiliser un type de données Dict pour fournir les données car je trouve cela fastidieux de saisir les données, etc ...
Ma solution vous oblige à ajouter 2 lignes supplémentaires au-dessus de votre classe pour créer une classe de base pour la classe à laquelle vous souhaitez ajouter les propriétés, puis 1 ligne par et vous avez la possibilité d'ajouter des rappels pour contrôler les données, vous informer lorsque les données changent , restreignez les données qui peuvent être définies en fonction de la valeur et / ou du type de données, et bien plus encore.
Vous avez également la possibilité d'utiliser _object.x, _object.x = valeur, _object.GetX (), _object.SetX (valeur) et ils sont gérés de manière équivalente.
De plus, les valeurs sont les seules données non statiques qui sont affectées à l'instance de classe, mais la propriété réelle est affectée à la classe, ce qui signifie que les choses que vous ne voulez pas répéter, n'ont pas besoin d'être répétées ... Vous peut affecter une valeur par défaut afin que le getter n'en ait pas besoin à chaque fois, bien qu'il existe une option pour remplacer la valeur par défaut, et il existe une autre option pour que le getter renvoie la valeur stockée brute en remplaçant les retours par défaut (remarque: cette méthode signifie que la valeur brute n'est affectée que lorsqu'une valeur est affectée, sinon elle est None - lorsque la valeur est Reset, alors elle affecte None, etc.)
Il existe également de nombreuses fonctions d'assistance - la première propriété qui est ajoutée ajoute environ 2 assistants à la classe pour référencer les valeurs d'instance ... Ce sont des varargs ResetAccessors (_key, ..) répétés (tous peuvent être répétés en utilisant les premiers arguments nommés ) et SetAccessors (_key, _value) avec la possibilité d'ajouter plus à la classe principale pour aider à l'efficacité - ceux prévus sont: un moyen de regrouper les accesseurs, donc si vous avez tendance à réinitialiser quelques-uns à la fois, à chaque fois , vous pouvez les affecter à un groupe et réinitialiser le groupe au lieu de répéter les touches nommées à chaque fois, et plus encore.
La valeur stockée instance / raw est stockée dans la classe., la classe. fait référence à la classe d'accesseur qui contient des variables / valeurs / fonctions statiques pour la propriété. _classe. est la propriété elle-même qui est appelée lorsqu'elle est accessible via la classe d'instance lors de la définition / de l'obtention, etc.
L'Accessor _class .__ pointe vers la classe, mais parce qu'il est interne, il doit être affecté dans la classe, c'est pourquoi j'ai choisi d'utiliser __Name = AccessorFunc (...) pour l'attribuer, une seule ligne par propriété avec de nombreux facultatifs arguments à utiliser (en utilisant des varargs à clé car ils sont plus faciles et plus efficaces à identifier et à maintenir) ...
Je crée également de nombreuses fonctions, comme mentionné, dont certaines utilisent les informations de la fonction d'accesseur de sorte qu'elles n'ont pas besoin d'être appelées (car c'est un peu gênant pour le moment - pour le moment, vous devez utiliser _class. .FunctionName (_class_instance , args) - Je me suis servi de la pile / trace pour saisir la référence d'instance pour saisir la valeur en ajoutant les fonctions qui exécutent ce bit marathon, ou en ajoutant les accesseurs à l'objet et en utilisant self (nommé ceci pour indiquer qu'ils 'pour l'instance et pour conserver l'accès à soi, à la référence de classe AccessorFunc et à d'autres informations dans les définitions de fonction).
Ce n'est pas tout à fait fait, mais c'est une prise de pied fantastique. Remarque: Si vous n'utilisez pas __Name = AccessorFunc (...) pour créer les propriétés, vous n'aurez pas accès à la clé __ même si je la définis dans la fonction init. Si vous le faites, il n'y a aucun problème.
Notez également que le nom et la clé sont différents ... Le nom est «formel», utilisé dans la création de nom de fonction, et la clé est pour le stockage et l'accès aux données. c'est-à-dire _class.x où x minuscule est la clé, le nom serait X majuscule pour que GetX () soit la fonction au lieu de Getx () qui semble un peu étrange. cela permet à self.x de fonctionner et d'avoir l'air approprié, mais également d'autoriser GetX () et d'avoir l'air approprié.
J'ai un exemple de classe configuré avec une clé / un nom identique et différent à afficher. un grand nombre de fonctions d'assistance créées afin de sortir les données (Remarque: tout cela n'est pas terminé) afin que vous puissiez voir ce qui se passe.
La liste actuelle des fonctions utilisant la touche: x, nom: X sort comme:
Ce n'est en aucun cas une liste complète - il y en a quelques-uns qui ne l'ont pas encore fait au moment de la publication ...
_instance.SetAccessors( _key, _value [ , _key, _value ] .. ) Instance Class Helper Function: Allows assigning many keys / values on a single line - useful for initial setup, or to minimize lines. In short: Calls this.Set<Name>( _value ) for each _key / _value pairing.
_instance.ResetAccessors( _key [ , _key ] .. ) Instance Class Helper Function: Allows resetting many key stored values to None on a single line. In short: Calls this.Reset<Name>() for each name provided.
Note: Functions below may list self.Get / Set / Name( _args ) - self is meant as the class instance reference in the cases below - coded as this in AccessorFuncBase Class.
this.GetX( _default_override = None, _ignore_defaults = False ) GET: Returns IF ISSET: STORED_VALUE .. IF IGNORE_DEFAULTS: None .. IF PROVIDED: DEFAULT_OVERRIDE ELSE: DEFAULT_VALUE 100
this.GetXRaw( ) RAW: Returns STORED_VALUE 100
this.IsXSet( ) ISSET: Returns ( STORED_VALUE != None ) True
this.GetXToString( ) GETSTR: Returns str( GET ) 100
this.GetXLen( _default_override = None, _ignore_defaults = False ) LEN: Returns len( GET ) 3
this.GetXLenToString( _default_override = None, _ignore_defaults = False ) LENSTR: Returns str( len( GET ) ) 3
this.GetXDefaultValue( ) DEFAULT: Returns DEFAULT_VALUE 1111
this.GetXAccessor( ) ACCESSOR: Returns ACCESSOR_REF ( self.__<key> ) [ AccessorFuncBase ] Key: x : Class ID: 2231452344344 : self ID: 2231448283848 Default: 1111 Allowed Types: {"<class 'int'>": "<class 'type'>", "<class 'float'>": "<class 'type'>"} Allowed Values: None
this.GetXAllowedTypes( ) ALLOWED_TYPES: Returns Allowed Data-Types {"<class 'int'>": "<class 'type'>", "<class 'float'>": "<class 'type'>"}
this.GetXAllowedValues( ) ALLOWED_VALUES: Returns Allowed Values None
this.GetXHelpers( ) HELPERS: Returns Helper Functions String List - ie what you're reading now... THESE ROWS OF TEXT
this.GetXKeyOutput( ) Returns information about this Name / Key ROWS OF TEXT
this.GetXGetterOutput( ) Returns information about this Name / Key ROWS OF TEXT
this.SetX( _value ) SET: STORED_VALUE Setter - ie Redirect to __<Key>.Set N / A
this.ResetX( ) RESET: Resets STORED_VALUE to None N / A
this.HasXGetterPrefix( ) Returns Whether or Not this key has a Getter Prefix... True
this.GetXGetterPrefix( ) Returns Getter Prefix... Get
this.GetXName( ) Returns Accessor Name - Typically Formal / Title-Case X
this.GetXKey( ) Returns Accessor Property Key - Typically Lower-Case x
this.GetXAccessorKey( ) Returns Accessor Key - This is to access internal functions, and static data... __x
this.GetXDataKey( ) Returns Accessor Data-Storage Key - This is the location where the class instance value is stored.. _x
Certaines des données produites sont:
Il s'agit d'une toute nouvelle classe créée à l'aide de la classe Demo sans aucune donnée autre que le nom (afin qu'elle puisse être sortie) qui est _foo, le nom de variable que j'ai utilisé ...
_foo --- MyClass: ---- id( this.__class__ ): 2231452349064 :::: id( this ): 2231448475016
Key Getter Value | Raw Key Raw / Stored Value | Get Default Value Default Value | Get Allowed Types Allowed Types | Get Allowed Values Allowed Values |
Name: _foo | _Name: _foo | __Name.DefaultValue( ): AccessorFuncDemoClass | __Name.GetAllowedTypes( ) <class 'str'> | __Name.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
x: 1111 | _x: None | __x.DefaultValue( ): 1111 | __x.GetAllowedTypes( ) (<class 'int'>, <class 'float'>) | __x.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
y: 2222 | _y: None | __y.DefaultValue( ): 2222 | __y.GetAllowedTypes( ) (<class 'int'>, <class 'float'>) | __y.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
z: 3333 | _z: None | __z.DefaultValue( ): 3333 | __z.GetAllowedTypes( ) (<class 'int'>, <class 'float'>) | __z.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
Blah: <class 'int'> | _Blah: None | __Blah.DefaultValue( ): <class 'int'> | __Blah.GetAllowedTypes( ) <class 'str'> | __Blah.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
Width: 1 | _Width: None | __Width.DefaultValue( ): 1 | __Width.GetAllowedTypes( ) (<class 'int'>, <class 'bool'>) | __Width.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
Height: 0 | _Height: None | __Height.DefaultValue( ): 0 | __Height.GetAllowedTypes( ) <class 'int'> | __Height.GetAllowedValues( ) (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) |
Depth: 2 | _Depth: None | __Depth.DefaultValue( ): 2 | __Depth.GetAllowedTypes( ) Saved Value Restricted to Authorized Values ONLY | __Depth.GetAllowedValues( ) (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) |
this.IsNameSet( ): True this.GetName( ): _foo this.GetNameRaw( ): _foo this.GetNameDefaultValue( ): AccessorFuncDemoClass this.GetNameLen( ): 4 this.HasNameGetterPrefix( ): <class 'str'> this.GetNameGetterPrefix( ): None
this.IsXSet( ): False this.GetX( ): 1111 this.GetXRaw( ): None this.GetXDefaultValue( ): 1111 this.GetXLen( ): 4 this.HasXGetterPrefix( ): (<class 'int'>, <class 'float'>) this.GetXGetterPrefix( ): None
this.IsYSet( ): False this.GetY( ): 2222 this.GetYRaw( ): None this.GetYDefaultValue( ): 2222 this.GetYLen( ): 4 this.HasYGetterPrefix( ): (<class 'int'>, <class 'float'>) this.GetYGetterPrefix( ): None
this.IsZSet( ): False this.GetZ( ): 3333 this.GetZRaw( ): None this.GetZDefaultValue( ): 3333 this.GetZLen( ): 4 this.HasZGetterPrefix( ): (<class 'int'>, <class 'float'>) this.GetZGetterPrefix( ): None
this.IsBlahSet( ): False this.GetBlah( ): <class 'int'> this.GetBlahRaw( ): None this.GetBlahDefaultValue( ): <class 'int'> this.GetBlahLen( ): 13 this.HasBlahGetterPrefix( ): <class 'str'> this.GetBlahGetterPrefix( ): None
this.IsWidthSet( ): False this.GetWidth( ): 1 this.GetWidthRaw( ): None this.GetWidthDefaultValue( ): 1 this.GetWidthLen( ): 1 this.HasWidthGetterPrefix( ): (<class 'int'>, <class 'bool'>) this.GetWidthGetterPrefix( ): None
this.IsDepthSet( ): False this.GetDepth( ): 2 this.GetDepthRaw( ): None this.GetDepthDefaultValue( ): 2 this.GetDepthLen( ): 1 this.HasDepthGetterPrefix( ): None this.GetDepthGetterPrefix( ): (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
this.IsHeightSet( ): False this.GetHeight( ): 0 this.GetHeightRaw( ): None this.GetHeightDefaultValue( ): 0 this.GetHeightLen( ): 1 this.HasHeightGetterPrefix( ): <class 'int'> this.GetHeightGetterPrefix( ): (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
Et ceci après avoir assigné à toutes les propriétés _foo (sauf le nom) les valeurs suivantes dans le même ordre: 'string', 1.0, True, 9, 10, False
this.IsNameSet( ): True this.GetName( ): _foo this.GetNameRaw( ): _foo this.GetNameDefaultValue( ): AccessorFuncDemoClass this.GetNameLen( ): 4 this.HasNameGetterPrefix( ): <class 'str'> this.GetNameGetterPrefix( ): None
this.IsXSet( ): True this.GetX( ): 10 this.GetXRaw( ): 10 this.GetXDefaultValue( ): 1111 this.GetXLen( ): 2 this.HasXGetterPrefix( ): (<class 'int'>, <class 'float'>) this.GetXGetterPrefix( ): None
this.IsYSet( ): True this.GetY( ): 10 this.GetYRaw( ): 10 this.GetYDefaultValue( ): 2222 this.GetYLen( ): 2 this.HasYGetterPrefix( ): (<class 'int'>, <class 'float'>) this.GetYGetterPrefix( ): None
this.IsZSet( ): True this.GetZ( ): 10 this.GetZRaw( ): 10 this.GetZDefaultValue( ): 3333 this.GetZLen( ): 2 this.HasZGetterPrefix( ): (<class 'int'>, <class 'float'>) this.GetZGetterPrefix( ): None
this.IsBlahSet( ): True this.GetBlah( ): string Blah this.GetBlahRaw( ): string Blah this.GetBlahDefaultValue( ): <class 'int'> this.GetBlahLen( ): 11 this.HasBlahGetterPrefix( ): <class 'str'> this.GetBlahGetterPrefix( ): None
this.IsWidthSet( ): True this.GetWidth( ): False this.GetWidthRaw( ): False this.GetWidthDefaultValue( ): 1 this.GetWidthLen( ): 5 this.HasWidthGetterPrefix( ): (<class 'int'>, <class 'bool'>) this.GetWidthGetterPrefix( ): None
this.IsDepthSet( ): True this.GetDepth( ): 9 this.GetDepthRaw( ): 9 this.GetDepthDefaultValue( ): 2 this.GetDepthLen( ): 1 this.HasDepthGetterPrefix( ): None this.GetDepthGetterPrefix( ): (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
this.IsHeightSet( ): True this.GetHeight( ): 9 this.GetHeightRaw( ): 9 this.GetHeightDefaultValue( ): 0 this.GetHeightLen( ): 1 this.HasHeightGetterPrefix( ): <class 'int'> this.GetHeightGetterPrefix( ): (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
_foo --- MyClass: ---- id( this.__class__ ): 2231452349064 :::: id( this ): 2231448475016
Key Getter Value | Raw Key Raw / Stored Value | Get Default Value Default Value | Get Allowed Types Allowed Types | Get Allowed Values Allowed Values |
Name: _foo | _Name: _foo | __Name.DefaultValue( ): AccessorFuncDemoClass | __Name.GetAllowedTypes( ) <class 'str'> | __Name.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
x: 10 | _x: 10 | __x.DefaultValue( ): 1111 | __x.GetAllowedTypes( ) (<class 'int'>, <class 'float'>) | __x.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
y: 10 | _y: 10 | __y.DefaultValue( ): 2222 | __y.GetAllowedTypes( ) (<class 'int'>, <class 'float'>) | __y.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
z: 10 | _z: 10 | __z.DefaultValue( ): 3333 | __z.GetAllowedTypes( ) (<class 'int'>, <class 'float'>) | __z.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
Blah: string Blah | _Blah: string Blah | __Blah.DefaultValue( ): <class 'int'> | __Blah.GetAllowedTypes( ) <class 'str'> | __Blah.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
Width: False | _Width: False | __Width.DefaultValue( ): 1 | __Width.GetAllowedTypes( ) (<class 'int'>, <class 'bool'>) | __Width.GetAllowedValues( ) Saved Value Restrictions Levied by Data-Type |
Height: 9 | _Height: 9 | __Height.DefaultValue( ): 0 | __Height.GetAllowedTypes( ) <class 'int'> | __Height.GetAllowedValues( ) (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) |
Depth: 9 | _Depth: 9 | __Depth.DefaultValue( ): 2 | __Depth.GetAllowedTypes( ) Saved Value Restricted to Authorized Values ONLY | __Depth.GetAllowedValues( ) (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) |
Notez qu'en raison de types de données restreints ou de restrictions de valeurs, certaines données n'ont pas été affectées - c'est par conception. Le setter interdit les mauvais types de données ou valeurs d'être attribués, même d'être assignés comme valeur par défaut (sauf si vous remplacez le comportement de protection de la valeur par défaut)
Le code n'a pas été posté ici car je n'avais pas de place après les exemples et explications ... Aussi parce qu'il va changer.
Veuillez noter: au moment de cette publication, le fichier est en désordre - cela va changer. Mais, si vous l'exécutez dans Sublime Text et le compilez, ou l'exécutez à partir de Python, il compilera et crachera une tonne d'informations - la partie AccessorDB n'est pas terminée (qui sera utilisée pour mettre à jour les Getters d'impression et l'assistant GetKeyOutput fonctions en plus d'être changées en fonction Instance, probablement mises en une seule fonction et renommées - recherchez-la ..)
Suivant: Tout n'est pas nécessaire pour qu'il fonctionne - une grande partie des éléments commentés en bas sont pour plus d'informations utilisées pour le débogage - il peut ne pas être là lorsque vous le téléchargez. Si c'est le cas, vous devriez pouvoir décommenter et recompiler pour obtenir plus d'informations.
Je cherche un moyen de contourner le besoin de MyClassBase: pass, MyClass (MyClassBase): ... - si vous connaissez une solution - postez-la.
La seule chose nécessaire dans la classe sont les lignes __ - la chaîne est pour le débogage tout comme l' init - elles peuvent être supprimées de la classe de démonstration mais vous devrez commenter ou supprimer certaines des lignes ci-dessous (_foo / 2/3 ) ..
Les classes String, Dict et Util en haut font partie de ma bibliothèque Python - elles ne sont pas complètes. J'ai copié quelques éléments dont j'avais besoin dans la bibliothèque et j'en ai créé quelques nouveaux. Le code complet sera lié à la bibliothèque complète et l'inclura avec la fourniture d'appels mis à jour et la suppression du code (en fait, le seul code restant sera la classe de démonstration et les instructions d'impression - le système AccessorFunc sera déplacé vers la bibliothèque). ..
Partie du dossier:
##
## MyClass Test AccessorFunc Implementation for Dynamic 1-line Parameters
##
class AccessorFuncDemoClassBase( ):
pass
class AccessorFuncDemoClass( AccessorFuncDemoClassBase ):
__Name = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'Name', default = 'AccessorFuncDemoClass', allowed_types = ( TYPE_STRING ), allowed_values = VALUE_ANY, documentation = 'Name Docs', getter_prefix = 'Get', key = 'Name', allow_erroneous_default = False, options = { } )
__x = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'X', default = 1111, allowed_types = ( TYPE_INTEGER, TYPE_FLOAT ), allowed_values = VALUE_ANY, documentation = 'X Docs', getter_prefix = 'Get', key = 'x', allow_erroneous_default = False, options = { } )
__Height = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'Height', default = 0, allowed_types = TYPE_INTEGER, allowed_values = VALUE_SINGLE_DIGITS, documentation = 'Height Docs', getter_prefix = 'Get', key = 'Height', allow_erroneous_default = False, options = { } )
Cette beauté rend incroyablement facile la création de nouvelles classes avec des propriétés ajoutées dynamiquement avec AccessorFuncs / rappels / type de données / application de valeur, etc.
Pour l'instant, le lien est à (Ce lien doit refléter les modifications apportées au document.): Https://www.dropbox.com/s/6gzi44i7dh58v61/dynamic_properties_accessorfuncs_and_more.py?dl=0
Aussi: Si vous n'utilisez pas Sublime Text, je le recommande par-dessus Notepad ++, Atom, Visual Code et autres en raison des implémentations de threading appropriées, ce qui le rend beaucoup, beaucoup plus rapide à utiliser ... Je travaille également sur un code de type IDE système de cartographie pour cela - jetez un oeil à: https://bitbucket.org/Acecool/acecoolcodemappingsystem/src/master/ (Ajoutez d'abord Repo dans le gestionnaire de packages, puis installez le plugin - lorsque la version 1.0.0 est prête, je vais ajouter à la liste principale des plugins ...)
J'espère que cette solution aide ... et, comme toujours:
Tout simplement parce que cela fonctionne, ne fait pas les choses correctement - Josh 'Acecool' Moser
:
et de__init__
référencesself.fn_readyonly
.