Muitas das respostas fornecidas requerem tantas linhas por propriedade, ou seja, / e / ou - o que eu consideraria uma implementação feia ou tediosa por causa da repetitividade necessária para várias propriedades, etc. Eu prefiro manter as coisas em ordem / simplificar até que elas não pode mais ser simplificado ou até que não sirva muito para isso.
Resumindo: em trabalhos concluídos, se eu repetir duas linhas de código, normalmente a converto em uma função auxiliar de linha única, e assim por diante ... Simplifico argumentos matemáticos ou ímpares como (start_x, start_y, end_x, end_y) para (x, y, w, h) ou seja, x, y, x + w, y + h (às vezes requer min / max ou se w / h são negativos e a implementação não gosta disso, vou subtrair de x / y e abs p / h, etc.).
Substituir os getters / setters internos é um bom caminho a percorrer, mas o problema é que você precisa fazer isso para todas as classes ou orientar a classe nessa base ... Isso não funciona para mim, como eu preferiria ser livre para escolher os filhos / pais por herança, nós filhos, etc.
Eu criei uma solução que responde à pergunta sem usar um tipo de dados Dict para fornecer os dados, pois acho que é tedioso para inserir os dados, etc.
Minha solução exige que você adicione 2 linhas extras acima da sua classe para criar uma classe base para a classe na qual você deseja adicionar as propriedades e, em seguida, 1 linha por e você tem a opção de adicionar retornos de chamada para controlar os dados e informá-lo quando os dados forem alterados , restrinja os dados que podem ser definidos com base no valor e / ou tipo de dados e muito mais.
Você também tem a opção de usar _object.x, _object.x = value, _object.GetX (), _object.SetX (value) e eles são tratados de forma equivalente.
Além disso, os valores são os únicos dados não estáticos atribuídos à instância da classe, mas a propriedade real é atribuída à classe, significando o que você não deseja repetir, não precisa ser repetido ... Você pode atribuir um valor padrão para que o getter não precise dele todas as vezes, embora exista uma opção para substituir o valor padrão padrão e outra opção para que o getter retorne o valor bruto armazenado, substituindo os retornos padrão (observação: este método significa que o valor bruto é atribuído apenas quando um valor é atribuído; caso contrário, é Nenhum - quando o valor é Redefinido, ele atribui Nenhum, etc.)
Também existem muitas funções auxiliares - a primeira propriedade adicionada adiciona mais ou menos 2 auxiliares à classe para referenciar os valores da instância ... Eles são ResetAccessors (_key, ..) varargs repetidos (todos podem ser repetidos usando o primeiro argumento args ) e SetAccessors (_key, _value) com a opção de serem adicionados mais à classe principal para auxiliar na eficiência - os planejados são: uma maneira de agrupar os acessadores, portanto, se você tende a redefinir alguns de cada vez, sempre , você pode atribuí-los a um grupo e redefinir o grupo em vez de repetir as teclas nomeadas a cada vez e muito mais.
O valor armazenado da instância / bruto é armazenado na classe , a classe. referencia a classe Accessor que contém vars / valores / funções estáticos para a propriedade _classe. é a própria propriedade que é chamada quando acessada através da classe de instância durante a configuração / obtenção, etc.
O Accessor _class .__ aponta para a classe, mas como é interno, ele precisa ser atribuído à classe, e foi por isso que eu optei por usar __Name = AccessorFunc (...) para atribuí-la, uma única linha por propriedade com muitas opções opcionais. argumentos a serem usados (usando varargs com chave porque são mais fáceis e mais eficientes de identificar e manter) ...
Também crio muitas funções, como mencionado, algumas das quais usam informações da função de acessador para que não precisem ser chamadas (pois é um pouco inconveniente no momento - agora você precisa usar _class. .FunctionName (_class_instance , args) - Eu usei a pilha / rastreamento para capturar a referência da instância para capturar o valor adicionando as funções que executam essa maratona de bits ou adicionando os acessadores ao objeto e usando self (com o nome this para indicar que eles é para a instância e retém o acesso a si próprio, a referência da classe AccessorFunc e outras informações nas definições de função).
Não está bem feito, mas é um apoio fantástico para os pés. Nota: Se você não usar __Name = AccessorFunc (...) para criar as propriedades, não terá acesso à tecla __, mesmo que eu a defina na função init. Se o fizer, não haverá problemas.
Além disso: Observe que Nome e Chave são diferentes ... O nome é 'formal', usado na Criação de Nome da Função, e a chave é para armazenamento e acesso a dados. ie _class.x onde x minúsculo é a chave, o nome seria X maiúsculo para que GetX () seja a função em vez de Getx () que parece um pouco estranha. isso permite que o self.x funcione e pareça apropriado, mas também permite GetX () e pareça apropriado.
Eu tenho uma classe de exemplo configurada com a chave / nome idêntico e diferente para mostrar. várias funções auxiliares criadas para gerar os dados (Nota: nem tudo isso está completo) para que você possa ver o que está acontecendo.
A lista atual de funções usando a tecla: x, nome: X gera como:
Esta não é de forma alguma uma lista abrangente - existem algumas que ainda não foram publicadas no momento da publicação ...
_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
Alguns dos dados que estão sendo produzidos são:
Isto é para uma nova classe criada usando a classe Demo sem nenhum dado atribuído além do nome (para que possa ser gerado), que é _foo, o nome da variável que eu usei ...
_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)
E isso é depois de atribuir todas as propriedades _foo (exceto o nome) os seguintes valores na mesma ordem: '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) |
Observe que, devido a tipos de dados restritos ou restrições de valor, alguns dados não foram atribuídos - isso ocorre por design. O setter proíbe que tipos de dados ou valores incorretos sejam atribuídos, mesmo que sejam atribuídos como um valor padrão (a menos que você substitua o comportamento de proteção de valor padrão)
O código não foi publicado aqui porque não havia espaço após os exemplos e explicações ... Também porque ele mudará.
Observação: no momento desta postagem, o arquivo está confuso - isso será alterado. Mas, se você executá-lo em Sublime Text e compilá-lo ou em Python, ele compilará e cuspirá uma tonelada de informações - a parte do AccessorDB não está concluída (que será usada para atualizar os auxiliares Print Getters e GetKeyOutput funções, além de serem alteradas para uma função de Instância, provavelmente inseridas em uma única função e renomeadas - procure-a ..)
Próximo: Nem tudo é necessário para que ele seja executado - muitas das coisas comentadas na parte inferior são para mais informações usadas para depuração - pode não estar presente quando você o baixa. Se for, você poderá descomentar e recompilar para obter mais informações.
Estou procurando uma solução alternativa para a necessidade de MyClassBase: pass, MyClass (MyClassBase): ... - se você souber de uma solução - poste-a.
A única coisa necessária na classe são as linhas __ - o str é para depuração e o init - elas podem ser removidas da classe Demo, mas você precisará comentar ou remover algumas das linhas abaixo (_foo / 2/3 ) ..
As classes String, Dict e Util na parte superior fazem parte da minha biblioteca Python - elas não estão completas. Copiei algumas coisas que precisava da biblioteca e criei algumas novas. O código completo será vinculado à biblioteca completa e o incluirá, além de fornecer chamadas atualizadas e remover o código (na verdade, o único código restante será a Classe Demo e as instruções de impressão - o sistema AccessorFunc será movido para a biblioteca). ..
Parte do arquivo:
##
## 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 = { } )
Essa beleza facilita incrivelmente a criação de novas classes com propriedades adicionadas dinamicamente com AccessorFuncs / callbacks / data-type / value enforcement, etc.
Por enquanto, o link está em (Este link deve refletir as alterações no documento.): Https://www.dropbox.com/s/6gzi44i7dh58v61/dynamic_properties_accessorfuncs_and_more.py?dl=0
Além disso: se você não usar o Sublime Text, recomendo-o no Notepad ++, Atom, Visual Code e outros por causa de implementações de encadeamento apropriadas que o tornam muito, muito mais rápido de usar ... Também estou trabalhando em um código semelhante ao IDE sistema de mapeamento para ele - consulte: https://bitbucket.org/Acecool/acecoolcodemappingsystem/src/master/ (Adicione o repositório no Package Manager primeiro e depois instale o plug-in - quando a versão 1.0.0 estiver pronta, adicionarei para a lista principal de plugins ...)
Espero que esta solução ajude ... e, como sempre:
Só porque funciona, não dá certo - Josh 'Acecool' Moser
:
e de__init__
referênciasself.fn_readyonly
.