Como adicionar propriedade a uma classe dinamicamente?

o objectivo é criar uma classe mock que se comporte como um conjunto de resultados db.

por exemplo, se uma pesquisa de base de dados retorna, usando uma expressão dict, {'ab':100, 'cd':200}, então eu gostaria de ver:

>>> dummy.ab
100
No início, pensei que talvez pudesse fazê-lo desta maneira.
ks = ['ab', 'cd']
vs = [12, 34]
class C(dict):
    def __init__(self, ks, vs):
        for i, k in enumerate(ks):
            self[k] = vs[i]
            setattr(self, k, property(lambda x: vs[i], self.fn_readyonly))

    def fn_readonly(self, v)
        raise "It is ready only"

if __name__ == "__main__":
    c = C(ks, vs)
    print c.ab

Mas c.ab devolve um objecto de propriedade.

substituir a Linha setattr por k = property(lambda x: vs[i]) não tem qualquer utilidade.

Então, qual é a maneira certa de criar uma propriedade de instância no tempo de execução?

P. S. Eu sou consciente de uma alternativa apresentada em como se utiliza o método __getattribute__?

Author: Boann, 2009-08-25

18 answers

Acho que devia expandir esta resposta, agora que sou mais velha e sábia e sei o que se passa. Mais vale tarde do que nunca.

{Você[26]}pode adicionar uma propriedade a uma classe dinamicamente. Mas esse é o truque: você tem que adicioná-lo à classe .

>>> class Foo(object):
...     pass
... 
>>> foo = Foo()
>>> foo.a = 3
>>> Foo.b = property(lambda self: self.a + 1)
>>> foo.b
4

A property é na verdade uma implementação simples de uma coisa chamada a descritor. É um objeto que fornece tratamento personalizado para um dado atributo, em uma dada classe . Como uma maneira para considerar uma enorme árvore de if.

Quando pergunto por foo.b no exemplo acima, o Python vê que o b definido na classe implementa o protocolodescritor -O que significa que é um objecto com um __get__, __set__, ou método de __delete__ O descritor assume a responsabilidade de lidar com esse atributo, de modo que o Python chama Foo.b.__get__(foo, Foo), e o valor de retorno é repassado para você como o valor do atributo. No caso de property, cada um destes métodos chama apenas de fget, fset, ou fdel passaste para o construtor.

Os descritores são a forma do Python expor a canalização de toda a sua implementação OO. De facto, existe um outro tipo de descritor ainda mais comum do que property.
>>> class Foo(object):
...     def bar(self):
...         pass
... 
>>> Foo().bar
<bound method Foo.bar of <__main__.Foo object at 0x7f2a439d5dd0>>
>>> Foo().bar.__get__
<method-wrapper '__get__' of instancemethod object at 0x7f2a43a8a5a0>
O método humble é apenas mais um tipo de descritor. Seu __get__ tackles sobre a instância chamadora como o primeiro argumento; em efeito, ele faz isso:
def __get__(self, instance, owner):
    return functools.partial(self.function, instance)
De qualquer forma, suspeito que é por isso que os descritores só trabalham nas aulas: são um formalização do material que alimenta classes em primeiro lugar. Eles são mesmo a exceção à regra: você pode obviamente atribuir descritores a uma classe, e as classes são exemplos de type! Na verdade, tentar ler Foo.b ainda chama property.__get__; é apenas idiomático para os descritores se retornarem quando acessados como atributos de classe. Acho muito fixe que praticamente todo o sistema OO do Python possa ser expresso em Python. :) E eu escrevi um wordy blog post sobre descritores um tempo atrás, se você estiver interessado.
 251
Author: Eevee, 2013-02-28 04:49:20

O objectivo é criar uma classe mock que se comporte como um conjunto de resultados db.

Então o que você quer é um dicionário onde você pode soletrar a ['b'] como A. b? Isso é fácil.
class atdict(dict):
    __getattr__= dict.__getitem__
    __setattr__= dict.__setitem__
    __delattr__= dict.__delitem__
 51
Author: bobince, 2009-08-25 14:33:07
Parece que você poderia resolver este problema muito mais simplesmente com um namedtuple, já que você conhece toda a lista de campos antes do tempo.
from collections import namedtuple

Foo = namedtuple('Foo', ['bar', 'quux'])

foo = Foo(bar=13, quux=74)
print foo.bar, foo.quux

foo2 = Foo()  # error

Se você precisa absolutamente de escrever o seu próprio setter, você terá que fazer o metaprogramação no nível de classe; property() não funciona em instâncias.

 32
Author: Eevee, 2011-12-06 21:16:09
Não precisas de usar uma propriedade para isso. Basta anular __setattr__ para os Fazer ler apenas.
class C(object):
    def __init__(self, keys, values):
        for (key, value) in zip(keys, values):
            self.__dict__[key] = value

    def __setattr__(self, name, value):
        raise Exception("It is read only!")

Tada.

>>> c = C('abc', [1,2,3])
>>> c.a
1
>>> c.b
2
>>> c.c
3
>>> c.d
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute 'd'
>>> c.d = 42
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __setattr__
Exception: It is read only!
>>> c.a = 'blah'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __setattr__
Exception: It is read only!
 26
Author: Ryan, 2016-04-28 00:36:26

Você não pode adicionar um novo property() a uma instância no tempo de execução, porque as propriedades são descritores de dados. Em vez disso, você deve criar dinamicamente uma nova classe, ou sobrecarga __getattribute__, a fim de processar descritores de dados em instâncias.

 5
Author: Alex Gaynor, 2017-08-31 19:44:28

Eu fiz uma pergunta semelhante nesta pilha Overflow post para criar uma fábrica de classes que criou tipos simples. O resultado foi esta resposta que tinha uma versão de trabalho da fábrica de classe. Aqui está um trecho da Resposta:

def Struct(*args, **kwargs):
    def init(self, *iargs, **ikwargs):
        for k,v in kwargs.items():
            setattr(self, k, v)
        for i in range(len(iargs)):
            setattr(self, args[i], iargs[i])
        for k,v in ikwargs.items():
            setattr(self, k, v)

    name = kwargs.pop("name", "MyStruct")
    kwargs.update(dict((k, None) for k in args))
    return type(name, (object,), {'__init__': init, '__slots__': kwargs.keys()})

>>> Person = Struct('fname', 'age')
>>> person1 = Person('Kevin', 25)
>>> person2 = Person(age=42, fname='Terry')
>>> person1.age += 10
>>> person2.age -= 10
>>> person1.fname, person1.age, person2.fname, person2.age
('Kevin', 35, 'Terry', 32)
>>>

Você poderia usar alguma variação disto para criar valores padrão que é o seu objetivo (há também uma resposta nessa pergunta que lida com isso).

 4
Author: kjfletch, 2017-05-23 11:54:59

Não tenho a certeza se entendo completamente a pergunta, mas você pode modificar as propriedades da instância em tempo de execução com o built-in __dict__ da sua classe:

class C(object):
    def __init__(self, ks, vs):
        self.__dict__ = dict(zip(ks, vs))


if __name__ == "__main__":
    ks = ['ab', 'cd']
    vs = [12, 34]
    c = C(ks, vs)
    print(c.ab) # 12
 3
Author: Crescent Fresh, 2009-08-25 02:19:32
Como adicionar propriedades a uma classe python dinamicamente?
Diz que tens um objecto ao qual queres adicionar uma propriedade. Normalmente, eu quero usar propriedades quando eu preciso começar a gerenciar o acesso a um atributo em código que tem uso downstream, para que eu possa manter uma API consistente. Agora eu vou normalmente adicioná-los ao código fonte onde o objeto é definido, mas vamos assumir que você não tem esse acesso, ou você precisa realmente dinamicamente escolher suas funções programaticamente.

Criar uma classe

Usando um exemplo baseado na documentação para property, vamos criar uma classe de objeto com um atributo" escondido " e criar uma instância dele:

class C(object):
    '''basic class'''
    _x = None

o = C()
Em Python, esperamos que haja uma forma óbvia de fazer as coisas. No entanto, neste caso, vou mostrar duas maneiras: com a notação decoradora, e sem. Primeiro, sem a notação de decorador. Isto pode ser mais útil para a atribuição dinâmica de getters, setters, ou apagadores.

Dynamic (t. c. p.Monkey Patching)

Vamos criar alguns para a nossa turma.
def getx(self):
    return self._x

def setx(self, value):
    self._x = value

def delx(self):
    del self._x
E agora atribuímos isto à propriedade. Note que nós poderíamos escolher nossas funções programaticamente aqui, respondendo à pergunta dinâmica:
C.x = property(getx, setx, delx, "I'm the 'x' property.")

E utilização:

>>> o.x = 'foo'
>>> o.x
'foo'
>>> del o.x
>>> print(o.x)
None
>>> help(C.x)
Help on property:

    I'm the 'x' property.

Decoradores

Poderíamos fazer o mesmo que fizemos acima com a notação decoradora, mas neste caso, devemosnomear os métodos todos com o mesmo nome (e eu recomendaria mantê-lo the same as the attribute), so programmatic assignment is not so trivial as it is using the above method:

@property
def x(self):
    '''I'm the 'x' property.'''
    return self._x

@x.setter
def x(self, value):
    self._x = value

@x.deleter
def x(self):
    del self._x

E atribuir o objecto da propriedade com os seus conjuntos provisionados e apagadores para a classe:

C.x = x

E utilização:

>>> help(C.x)
Help on property:

    I'm the 'x' property.

>>> o.x
>>> o.x = 'foo'
>>> o.x
'foo'
>>> del o.x
>>> print(o.x)
None
 3
Author: Aaron Hall, 2016-07-04 12:16:36

A melhor maneira de conseguir é definindo __slots__. Assim, as tuas instâncias não podem ter novos atributos.

ks = ['ab', 'cd']
vs = [12, 34]

class C(dict):
    __slots__ = []
    def __init__(self, ks, vs): self.update(zip(ks, vs))
    def __getattr__(self, key): return self[key]

if __name__ == "__main__":
    c = C(ks, vs)
    print c.ab

Isso imprime 12

    c.ab = 33
Isso dá: AttributeError: 'C' object has no attribute 'ab'
 2
Author: nosklo, 2009-08-25 03:01:35

Apenas mais um exemplo de como obter o efeito desejado

class Foo(object):

    _bar = None

    @property
    def bar(self):
        return self._bar

    @bar.setter
    def bar(self, value):
        self._bar = value

    def __init__(self, dyn_property_name):
        setattr(Foo, dyn_property_name, Foo.bar)
Então agora podemos fazer coisas como:
>>> foo = Foo('baz')
>>> foo.baz = 5
>>> foo.bar
5
>>> foo.baz
5
 2
Author: Alexey Kuleshevich, 2014-05-09 21:41:06
Para aqueles que vêm dos motores de busca, Aqui estão as duas coisas que eu estava procurando ao falar sobre propriedades dinâmicas:
class Foo:
    def __init__(self):
        # we can dynamically have access to the properties dict using __dict__
        self.__dict__['foo'] = 'bar'

assert Foo().foo == 'bar'


# or we can use __getattr__ and __setattr__ to execute code on set/get
class Bar:
    def __init__(self):
        self._data = {}
    def __getattr__(self, key):
        return self._data[key]
    def __setattr__(self, key, value):
        self._data[key] = value

bar = Bar()
bar.foo = 'bar'
assert bar.foo == 'bar'

__dict__ é bom se você quiser colocar propriedades criadas dinamicamente. __getattr__ é bom apenas fazer algo quando o valor é necessário, como consultar um banco de dados. O conjunto / get combo é bom para simplificar o acesso aos dados armazenados na classe (como no exemplo acima).

Se você só quer uma propriedade dinâmica, dê uma olhada no propriedade () função incorporada.
 2
Author: tleb, 2017-08-02 12:06:13

Isto parece funcionar (mas veja abaixo):

class data(dict,object):
    def __init__(self,*args,**argd):
        dict.__init__(self,*args,**argd)
        self.__dict__.update(self)
    def __setattr__(self,name,value):
        raise AttributeError,"Attribute '%s' of '%s' object cannot be set"%(name,self.__class__.__name__)
    def __delattr__(self,name):
        raise AttributeError,"Attribute '%s' of '%s' object cannot be deleted"%(name,self.__class__.__name__)
Se precisar de um comportamento mais complexo, esteja à vontade para editar a sua resposta.

Editar

O seguinte seria provavelmente mais eficiente em termos de memória para grandes conjuntos de dados:

class data(dict,object):
    def __init__(self,*args,**argd):
        dict.__init__(self,*args,**argd)
    def __getattr__(self,name):
        return self[name]
    def __setattr__(self,name,value):
        raise AttributeError,"Attribute '%s' of '%s' object cannot be set"%(name,self.__class__.__name__)
    def __delattr__(self,name):
        raise AttributeError,"Attribute '%s' of '%s' object cannot be deleted"%(name,self.__class__.__name__)
 0
Author: David X, 2009-08-26 13:01:42

Para responder ao impulso principal da sua pergunta, você quer um atributo só de leitura de um dict como uma fonte de dados imutável:

O objectivo é criar uma classe mock que se comporte como um conjunto de resultados db.

Por exemplo, se uma pesquisa de base de dados retornar, usando uma expressão dict, {'ab':100, 'cd':200}, então eu gostaria de ver

>>> dummy.ab
100

Vou demonstrar como usar um namedtuple do Módulo collections para conseguir isto:

import collections

data = {'ab':100, 'cd':200}

def maketuple(d):
    '''given a dict, return a namedtuple'''
    Tup = collections.namedtuple('TupName', d.keys()) # iterkeys in Python2
    return Tup(**d)

dummy = maketuple(data)
dummy.ab
O

Devolve 100

 0
Author: Aaron Hall, 2015-02-06 02:04:54
class atdict(dict):
  def __init__(self, value, **kwargs):
    super().__init__(**kwargs)
    self.__dict = value

  def __getattr__(self, name):
    for key in self.__dict:
      if type(self.__dict[key]) is list:
        for idx, item in enumerate(self.__dict[key]):
          if type(item) is dict:
            self.__dict[key][idx] = atdict(item)
      if type(self.__dict[key]) is dict:
        self.__dict[key] = atdict(self.__dict[key])
    return self.__dict[name]



d1 = atdict({'a' : {'b': [{'c': 1}, 2]}})

print(d1.a.b[0].c)

E a saída é:

>> 1
 0
Author: Serhii Khachko, 2016-11-22 14:38:58

Poderá usar o seguinte código para actualizar os atributos da classe utilizando um objecto de dicionário:

class ExampleClass():
    def __init__(self, argv):
        for key, val in argv.items():
            self.__dict__[key] = val

if __name__ == '__main__':
    argv = {'intro': 'Hello World!'}
    instance = ExampleClass(argv)
    print instance.intro
 0
Author: Anthony Holloman, 2018-02-27 20:29:51

Simplificar a matemática ou ímpar argumentos, tais como ( start_x, start_y, end_x, end_y ) para ( x, y, w, h ) ie x, y, x + w, y + h ( às vezes exigindo min / max ou se w / h são negativos e a implementação de não gostar, eu vou subtrair x / y e abs w / h. etc.. ).

Anular os getters / setters internos é uma boa maneira de ir, mas o problema é que você precisa fazer isso para cada classe, ou pai a classe para essa base... Isto não funciona para mim, porque prefiro ser livre de escolher as crianças. / pais para 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 como eu acho que é tedioso para introduzir os dados, etc...

A Minha solução requer que você adicione 2 linhas extras acima da sua classe para criar uma classe base para a classe que você deseja adicionar as propriedades e, em seguida, 1 linha, e você tem a opção de adicionar callbacks para controlar os dados, informá-lo quando alterações de dados, restringir os dados que podem ser conjunto baseado no valor e / ou tipo de dados, e muito mais.

Você também tem a opção de usar _object.x, _object.x = valor, _object.GetX (), _object.SetX (valor) e eles são tratados de forma equivalente.

Além disso, os valores são os únicos dados não-estáticos que são atribuídos à instância de classe, mas a propriedade real é atribuída à classe significando as coisas que você não quer repetir, não precisa ser repetido... Você pode atribuir um valor padrão para que o getter não precisa dele cada o tempo, apesar de existir uma opção para substituir a predefinição padrão de valor, e não há outra opção para o getter retorna o raw valor armazenado substituindo padrão retorna ( nota: este método significa o valor bruto só é atribuído quando um valor é atribuído, caso contrário, não é Nenhum - quando o valor é Redefinido, em seguida, atribui Nenhum, etc.. )

Também existem muitas funções auxiliares - a primeira propriedade que é adicionada adiciona 2 ou mais ajudantes à classe para referenciar os valores da instância... Ele são ResetAccessors (_key,.. ) varargs repetido ( tudo pode ser repetido usando o primeiro nome args ) e SetAccessors( _key, _value ) com a opção de mais a ser adicionado para a classe principal para auxiliar na eficiência - aquelas previstas são: a forma de agrupar os acessores juntos, por isso, se você tende a repor um pouco de cada vez, a cada vez, você pode atribuí-los a um grupo e repor o grupo, em vez de repetir o nome chaves de cada vez, e mais.

O valor da instância / bruto armazenado é armazenado em classe., a turma. referências a classe do acessor que detém vars / valores / funções estáticas para a propriedade. _classe. é a propriedade em si que é chamada quando acessada através da classe de instância durante a configuração / obtenção, etc.

A _classe de acesso.__ pontos para a classe, mas porque é interno, precisa ser atribuído na classe, e é por isso que optei por usar __Nome = AccessorFunc( ... ) para atribuí-lo, uma única linha por propriedade com muitos argumentos opcionais a usar ( usando varargs riscados porque eles são mais fáceis e eficientes de identificar e manter )...

Eu também crio um monte de funções, como mencionado, algumas das quais usam a informação da função de acessor para que ela não precisa ser chamada ( como é um pouco inconveniente no momento - agora você precisa usar _classe..FunctionName (_class_ instance, args ) - dei a volta usando a pilha / traço para obter a referência da instância para obter o valor, adicionando as funções que executam isto bit marathon, ou adicionando os acessores ao objeto e usando o self ( chamado assim para apontar que eles são por exemplo e para manter o acesso ao self, a referência de classe AccessorFunc, e outras informações de dentro das definições de funções ).

Ainda não está pronto, mas é um fantástico apoio para os pés. Nota: Se você não usar _ _ Nome = AccessorFunc (... ) para criar as propriedades, Você não terá acesso à chave __ mesmo que eu a Defina dentro da função init. Se o fizeres, então ... não são problemas.

Também: Note que o nome e a chave são diferentes... O nome é 'formal', usado na criação do nome da função, e a chave é para armazenamento de dados e acesso. é a primeira classe.x onde minúsculas x é chave, o nome seria maiúsculo X de modo que GetX( ) é a função em vez de Getx () que parece um pouco estranho. isto permite o self.x para trabalhar e olhar apropriado, mas também permitir GetX () e olhar apropriado.

Tenho uma classe de exemplo configurada com chave / nome idêntico, e diferente para mostrar. a lot of helper functions created in order to output the data (Note: Not all of this is complete ) so you can see what is going on.

A lista actual de funções usando a chave: x, nome: x saídas como:

Isto não é de modo algum uma lista abrangente - há alguns que não chegaram a esta lista no momento do posting...
_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 a ser produzidos são:

Isto é para uma nova classe criada usando a classe de demonstração sem quaisquer dados atribuídos para além do nome (então pode ser saída ) 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 isto é depois de atribuir todas as propriedades _foo (excepto 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)                                                                                                                                                                                                   |

Note que devido a restrições de tipos de dados ou de Valor, alguns dados não foram atribuídos - isto é por design. O setter proíbe que os tipos ou valores de dados inválidos sejam atribuídos, mesmo que sejam atribuídos como um valor padrão ( a menos que você sobrepor o comportamento predefinido de protecção de valores)

O código não foi postado aqui porque não tinha espaço depois dos exemplos e explicações... Também porque vai mudar.

Por Favor, a ter em conta: no momento desta publicação, o ficheiro é confuso - isto irá mudar. Mas, se você executá-lo em Texto Sublime e compilá - lo, ou executá-lo a partir de Python, ele irá compilar e cuspir uma tonelada de informações-a parte AccessorDB não é feito ( que será usado para atualizar os Getters de impressão e Getkeyoutput helper functions along with being changed to an Instance function, probably put into a single function and renamed-look for it.. )

Seguinte: nem tudo é necessário para que ele execute - muitas das coisas comentadas na parte inferior é para mais informações usadas para depuração - ele pode não estar lá quando você baixá-lo. Se for, você deve ser capaz de descomentar e recompilar para obter mais informações.

Estou à procura de um trabalho para precisar da minha base de classe: passe, minha classe( MyClassBase):... - se souber de uma solução-publique-a.

A única coisa necessária na classe são o __ linhas - a str é para depuração, como é o init - eles podem ser removidos da Classe Demo, mas você vai precisar de comentar ou remover algumas das linhas abaixo ( _foo / 2 / 3 )..

As classes String, Dict e Util no topo são uma parte da minha biblioteca Python - elas não estão completas. Copiei umas coisas da biblioteca e ... criei alguns novos. O código completo irá ligar para a biblioteca completa e irá incluí - lo juntamente com o fornecimento de chamadas atualizadas e remoção do código ( na verdade, o único código que resta será a classe de demonstração e as declarações de impressão-o sistema AccessorFunc será movido para a biblioteca )...

Parte do ficheiro:

##
## 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 = { } )
Esta beleza torna incrivelmente fácil criar novas classes com propriedades dinamicamente adicionadas com funções de acesso / callbacks / tipo de dados / aplicação de valores, etc.

Por agora, o link está em (este link deve refletir alterações ao documento. ): https://www.dropbox.com/s/6gzi44i7dh58v61/dynamic_properties_accessorfuncs_and_more.py?dl=0

Também: se você não usar Texto Sublime, eu recomendo sobre o Notepad++, Atom, código Visual, e outros por causa de implementações de thread adequadas tornando-o muito, muito mais rápido de usar... Eu também estou trabalhando em um sistema de mapeamento de código IDE para ele-dê uma olhada: https://bitbucket.org/Acecool/acecoolcodemappingsystem/src/master/ (adicione Repo primeiro no Gestor de pacotes, depois instale o Plugin - quando a versão 1.0.0 estiver pronta, adicioná-la-ei à lista de plugins principal... )

Espero que esta solução ajude... e, como sempre: Só porque funciona, não faz com que seja correcto. Josh 'Acecool' Moser.
 0
Author: Acecool, 2018-08-31 16:56:43

A única forma de anexar dinamicamente uma propriedade é criar uma nova classe e a sua instância com a sua nova propriedade.

class Holder: p = property(lambda x: vs[i], self.fn_readonly)
setattr(self, k, Holder().p)
 -1
Author: M. Utku ALTINKAYA, 2009-08-25 02:29:19

Eu recentemente tive um problema semelhante, a solução que eu vim com usa __getattr__ e __setattr__ para as propriedades que eu quero a lidar, todo o resto é passado para os originais.

class C(object):
    def __init__(self, properties):
        self.existing = "Still Here"
        self.properties = properties

    def __getattr__(self, name):
        if "properties" in self.__dict__ and name in self.properties:
            return self.properties[name] # Or call a function, etc
        return self.__dict__[name]

    def __setattr__(self, name, value):
        if "properties" in self.__dict__ and name in self.properties:
            self.properties[name] = value
        else:
            self.__dict__[name] = value

if __name__ == "__main__":
    my_properties = {'a':1, 'b':2, 'c':3}
    c = C(my_properties)
    assert c.a == 1
    assert c.existing == "Still Here"
    c.b = 10
    assert c.properties['b'] == 10
 -1
Author: teeks99, 2014-04-29 17:52:55