Pergunta

O objetivo é criar uma classe falsa que se comporta como um conjunto de resultados db.

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

>>> dummy.ab
100

No começo eu pensei que talvez eu poderia 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 retorna um objeto de propriedade em vez.

Substituir a linha setattr com k = property(lambda x: vs[i]) é de nenhum uso em tudo.

Então, o que é o caminho certo para criar uma propriedade de instância em tempo de execução?

P.S. Estou ciente de uma alternativa apresentada em Como é usado o método __getattribute__?

Foi útil?

Solução

Suponho que deveria expandir esta resposta, agora que estou mais velho e mais sábio e sabe o que está acontecendo. Melhor tarde do que nunca.

Você pode adicionar uma propriedade a uma classe dinamicamente. Mas esse é o problema: você tem que adicioná-lo ao class

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

A property é realmente uma simples implementação de uma coisa chamada descritor . É um objeto que fornece personalizado manipulação para um determinado atributo, em uma determinada classe . Kinda como uma maneira de fator de uma árvore enorme if fora do __getattribute__.

Quando peço foo.b no exemplo acima, Python vê que o b definido nos implementos classe do protocolo de descritor -que significa apenas que é um objeto com um __get__, __set__, ou método __delete__. O reivindicações descritor responsabilidade para lidar com esse atributo, então Python chama Foo.b.__get__(foo, Foo), eo valor de retorno é passado de volta para você como o valor do atributo. No caso de property, cada um desses métodos apenas chama a fget, fset, ou fdel você passado para o construtor property.

Os descritores são realmente maneira de expor o encanamento de toda a sua implementação OO do Python. Na verdade, há 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 humilde é apenas outro tipo de descritor. Seus tachas __get__ na instância chamando como o primeiro argumento; com efeito, ele faz isso:

def __get__(self, instance, owner):
    return functools.partial(self.function, instance)

De qualquer forma, eu suspeito que é por isso que descritores só funcionam em classes: eles são uma formalização do material que alimenta classes em primeiro lugar. Eles são ainda a excepção à regra: você pode descritores obviamente atribuir a uma classe, e as classes são, elas próprias instâncias de type! Na verdade, tentando ler Foo.b ainda chama property.__get__; é apenas idiomática para descritores para si voltar quando acessadas como atributos de classe.

Eu acho que é muito legal que praticamente todos os sistema de OO do Python pode ser expresso em Python. :)

Oh, e eu escrevi um prolixo blog sobre descritores um tempo atrás se você estiver interessado.

Outras dicas

O objetivo é criar uma classe falsa que se comporta como um conjunto de resultados db.

Então, o que você quer é um dicionário onde pode significar um [ 'b'] como a.b?

É fácil:

class atdict(dict):
    __getattr__= dict.__getitem__
    __setattr__= dict.__setitem__
    __delattr__= dict.__delitem__

Parece que você poderia resolver este problema muito mais simples com um namedtuple , desde que você sabe 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ê absolutamente precisa escrever seu próprio setter, você vai ter que fazer o metaprogramming no nível de classe; property() não funciona em instâncias.

Você não precisa usar uma propriedade para isso. Apenas substituir __setattr__ para torná-los somente leitura.

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!

Como adicionar propriedades a uma classe python dinamicamente?

Digamos que você tenha um objeto que você deseja adicionar uma propriedade para. Normalmente, eu quero usar propriedades quando eu preciso para começar a gerenciar o acesso a um atributo no código que tem o uso a jusante, para que eu possa manter uma API consistente. Agora eu normalmente adicioná-los ao código fonte onde o objeto está definido, mas vamos supor que você não tem esse acesso, ou você precisa realmente dinamicamente escolher suas funções de programação.

Crie uma classe

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

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

o = C()

Em Python, esperamos que haja uma maneira óbvia de fazer as coisas. No entanto, neste caso, eu vou mostrar duas maneiras: com decorador de notação, e sem. Em primeiro lugar, sem notação decorador. Isto pode ser mais útil para a atribuição dinâmica de getters, setters, ou Deleters.

Dinâmico (A.K.A. Macaco Patching)

Vamos criar alguns para nossa classe:

def getx(self):
    return self._x

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

def delx(self):
    del self._x

E agora nós atribua-os a propriedade. Note que pudéssemos escolher nossas funções programaticamente aqui, respondendo à pergunta dinâmico:

C.x = property(getx, setx, delx, "I'm the 'x' property.")

E uso:

>>> 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

Nós poderíamos fazer o mesmo que fizemos anteriormente com a notação decorador, mas, neste caso, nós deve nomear os métodos todos o mesmo nome (e eu recomendo mantendo-o mesmo que o atributo ), a atribuição de modo programático não é tão trivial como ele está usando o método acima:

@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 objeto de propriedade com seus setters provisionados e Deleters para a classe:

C.x = x

E uso:

>>> 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

Eu fiz uma pergunta similary sobre este post Stack Overflow para criar uma fábrica de classes que criou tipos simples. O resultado foi esta resposta que teve 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 desta para criar valores padrão, que é o seu objetivo (também há uma resposta em que lida com esta questão).

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

Não tenho certeza se eu entendo completamente a pergunta, mas você pode modificar propriedades de instância em tempo de execução com o built-in __dict__ de 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

Para quem vem de motores de busca, aqui estão as duas coisas que eu estava procurando quando se fala de dinâmico propriedades:

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ê quer colocar propriedades criadas dinamicamente. __getattr__ é bom apenas para fazer algo quando é necessário o valor, como consulta um banco de dados. O set / get combinação é boa para simplificar o acesso aos dados armazenados na classe (como no exemplo acima).

Se você só deseja uma propriedade dinâmica, ter um olhar para o ( ) built-in função.

A melhor maneira de conseguir é através da definição de __slots__. Dessa forma, suas instâncias não pode 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

que imprime 12

    c.ab = 33

Isso dá: AttributeError: 'C' object has no attribute 'ab'

Apenas mais um exemplo de como conseguir 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

Você pode usar o seguinte código à classe de atualização atributos usando um objeto 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

Isso 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 você precisar de um comportamento mais complexo, fique à vontade para editar a sua resposta.

editar

O seguinte seria provavelmente mais memória-eficiente 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__)

Para responder o principal impulso da sua pergunta, você quer um atributo só de leitura a partir de um dicionário como uma fonte de dados imutáveis:

O objetivo é criar uma classe falsa que se comporta como um conjunto de resultados db.

Assim, por exemplo, se uma consulta de banco de dados retorna, usando uma expressão dict, {'ab':100, 'cd':200}, então eu iria ver

>>> dummy.ab
100

Vou demonstrar como usar um namedtuple do módulo collections para realizar apenas isso:

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

retornos 100

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

Estendendo a idéia de kjfletch

# This is my humble contribution, extending the idea to serialize
# data from and to tuples, comparison operations and allowing functions
# as default values.

def Struct(*args, **kwargs):
    FUNCTIONS = (types.BuiltinFunctionType, types.BuiltinMethodType, \
                 types.FunctionType, types.MethodType)
    def init(self, *iargs, **ikwargs):
        """Asume that unamed args are placed in the same order than
        astuple() yields (currently alphabetic order)
        """
        kw = list(self.__slots__)

        # set the unnamed args
        for i in range(len(iargs)):
            k = kw.pop(0)
            setattr(self, k, iargs[i])

        # set the named args
        for k, v in ikwargs.items():
            setattr(self, k, v)
            kw.remove(k)

        # set default values
        for k in kw:
            v = kwargs[k]
            if isinstance(v, FUNCTIONS):
                v = v()
            setattr(self, k, v)

    def astuple(self):
        return tuple([getattr(self, k) for k in self.__slots__])

    def __str__(self):
        data = ['{}={}'.format(k, getattr(self, k)) for k in self.__slots__]
        return '<{}: {}>'.format(self.__class__.__name__, ', '.join(data))

    def __repr__(self):
        return str(self)

    def __eq__(self, other):
        return self.astuple() == other.astuple()

    name = kwargs.pop("__name__", "MyStruct")
    slots = list(args)
    slots.extend(kwargs.keys())
    # set non-specific default values to None
    kwargs.update(dict((k, None) for k in args))

    return type(name, (object,), {
        '__init__': init,
        '__slots__': tuple(slots),
        'astuple': astuple,
        '__str__': __str__,
        '__repr__': __repr__,
        '__eq__': __eq__,
    })


Event = Struct('user', 'cmd', \
               'arg1', 'arg2',  \
               date=time.time, \
               __name__='Event')

aa = Event('pepe', 77)
print(aa)
raw = aa.astuple()

bb = Event(*raw)
print(bb)

if aa == bb:
    print('Are equals')

cc = Event(cmd='foo')
print(cc)

Output:

<Event: user=pepe, cmd=77, arg1=None, arg2=None, date=1550051398.3651814>
<Event: user=pepe, cmd=77, arg1=None, arg2=None, date=1550051398.3651814>
Are equals
<Event: user=None, cmd=foo, arg1=None, arg2=None, date=1550051403.7938335>

Embora muitas respostas são dadas, eu não poderia encontrar um Estou feliz com ele. Eu descobri a minha própria solução que torna o trabalho property para o caso dinâmico. A fonte de responder à pergunta original:

#!/usr/local/bin/python3

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

class DP(dict):
  def __init__(self):
    super().__init__()
    for k,v in INITS.items():
        self[k] = v 

def _dict_set(dp, key, value):
  dp[key] = value

for item in INITS.keys():
  setattr(
    DP,
    item,
    lambda key: property(
      lambda self: self[key], lambda self, value: _dict_set(self, key, value)
    )(item)
  )

a = DP()
print(a)  # {'ab': 100, 'cd': 200}
a.ab = 'ab100'
a.cd = False
print(a.ab, a.cd) # ab100 False

Algo que funciona para mim é esta:

class C:
    def __init__(self):
        self._x=None

    def g(self):
        return self._x

    def s(self, x):
        self._x = x

    def d(self):
        del self._x

    def s2(self,x):
        self._x=x+x

    x=property(g,s,d)


c = C()
c.x="a"
print(c.x)

C.x=property(C.g, C.s2)
C.x=C.x.deleter(C.d)
c2 = C()
c2.x="a"
print(c2.x)

saída

a
aa

Isto é um pouco diferente do que o OP queria, mas eu sacudiu meu cérebro até que eu tenho uma solução de trabalho, então eu estou colocando aqui para o próximo cara / gal

Eu precisava de uma maneira de especificar setters dinâmicas e getters.

class X:
    def __init__(self, a=0, b=0, c=0):
        self.a = a
        self.b = b
        self.c = c

    @classmethod
    def _make_properties(cls, field_name, inc):
        _inc = inc

        def _get_properties(self):
            if not hasattr(self, '_%s_inc' % field_name):
                setattr(self, '_%s_inc' % field_name, _inc)
                inc = _inc
            else:
                inc = getattr(self, '_%s_inc' % field_name)

            return getattr(self, field_name) + inc

        def _set_properties(self, value):
            setattr(self, '_%s_inc' % field_name, value)

        return property(_get_properties, _set_properties)

Eu sei que meus campos antes do tempo, então eu estou indo para criar minhas propriedades. NOTA: você não pode fazer isso instância por, essas propriedades existirá na classe !!!

for inc, field in enumerate(['a', 'b', 'c']):
    setattr(X, '%s_summed' % field, X._make_properties(field, inc))

Vamos testar tudo agora ..

x = X()
assert x.a == 0
assert x.b == 0
assert x.c == 0

assert x.a_summed == 0  # enumerate() set inc to 0 + 0 = 0
assert x.b_summed == 1  # enumerate() set inc to 1 + 0 = 1
assert x.c_summed == 2  # enumerate() set inc to 2 + 0 = 2

# we set the variables to something
x.a = 1
x.b = 2
x.c = 3

assert x.a_summed == 1  # enumerate() set inc to 0 + 1 = 1
assert x.b_summed == 3  # enumerate() set inc to 1 + 2 = 3
assert x.c_summed == 5  # enumerate() set inc to 2 + 3 = 5

# we're changing the inc now
x.a_summed = 1 
x.b_summed = 3 
x.c_summed = 5

assert x.a_summed == 2  # we set inc to 1 + the property was 1 = 2
assert x.b_summed == 5  # we set inc to 3 + the property was 2 = 5
assert x.c_summed == 8  # we set inc to 5 + the property was 3 = 8

É confuso? Sim, desculpe, eu não poderia vir acima com qualquer exemplos significativas do mundo real. Além disso, este não é para o hearted claro.

Apenas maneira de anexar uma propriedade dinâmica é a criação de uma nova classe e sua instância com sua nova propriedade.

class Holder: p = property(lambda x: vs[i], self.fn_readonly)
setattr(self, k, Holder().p)

Recentemente, tive um problema semelhante, a solução que eu vim com usos __getattr__ e __setattr__ para as propriedades que eu quero que lidar, tudo 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

Muitas das respostas fornecidas exigem tantas linhas por propriedade, isto é, / e / ou - o que eu considero uma implementação feio ou tedioso por causa da repetitividade necessário para várias propriedades, etc. Eu prefiro manter as coisas em ebulição baixo / simplificadoras -los até que eles não podem ser simplificadas mais ou até que não serve muito propósito de fazê-lo.

Em resumo: em obras concluídas, se eu repetir 2 linhas de código, eu normalmente convertê-lo em uma função auxiliar de linha única, e assim por diante ... I simplificar a matemática ou argumentos ímpares como (start_x, start_y, end_x, end_y) para (x, y, w, h) isto é, X, Y, X + W, Y + h (por vezes necessitando min / max ou se W / h são negativa e a execução não gostar, vou subtrair de X / Y e abs w / h. etc ..).

Substituindo os getters / setters internos é uma forma ok para ir, mas o problema é que você precisa fazer isso para cada classe, ou pai a classe para que a base ... Isso não funciona para mim como eu preferem ser livres para escolher as crianças / pais por herança, nós filhos, etc.

Eu criei uma solução que responde à pergunta sem usar um Dict-tipo de dados para fornecer os dados que eu achar que para ser tedioso para inserir 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 para, em seguida, uma linha por e você tem a opção de adicionar retornos de chamada para controlar os dados, informá-lo quando alterações de dados, restringir os dados que podem ser definidos com base no valor e / ou do 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 dados só não estáticos que são atribuídos para a instância da classe, mas a propriedade real é atribuído à classe o que significa que as coisas que você não deseja repetir, não precisa ser repetido. .. Você pode atribuir um valor padrão para o getter não precisa dela cada vez que, embora exista uma opção para substituir o valor padrão padrão, e não há outra opção para que o getter retorna o valor armazenado raw, substituindo retornos padrão (nota : este método significa que o valor bruto só é atribuído um valor quando está atribuído, caso contrário, é Nenhum - quando o valor é reposta, então atribui Nenhum, etc ..)

Existem muitas funções auxiliares também - a primeira propriedade que é adicionado acrescenta 2 ou mais ajudantes para a classe para fazer referência os valores de instância ... Eles são ResetAccessors (_Key, ..) VarArgs repetido (tudo pode ser repetido usando o args primeira nomeados) e SetAccessors (_Key, _Value) com a opção de mais sendo adicionados à classe principal para auxiliar na eficiência - as previstas são: a maneira de acessores agrupar, por isso, se você tende a redefinir um pouco de cada vez , de cada vez, você pode atribuí-los a um grupo e redefinir o grupo em vez de repetir as chaves denominadas de cada vez, e muito mais.

A / valor armazenado raw instância é armazenado em classe. , o __CLASS. referências a classe de acessor que detém Vars / valores / funções estáticas para a propriedade. _classe. é a própria propriedade, que é chamado quando acessado via a classe instância durante a configuração / recebendo, etc.

O acessor _class .__ aponta para a classe, mas porque é interna que precisa ser atribuído na classe que é por isso que eu optou por usar __Name = AccessorFunc (...) para atribuir a ele, uma única linha por propriedade com muitos argumentos opcional para usar (usando varargs com chave, porque eles são mais fácil e eficiente para identificar e manter) ...

Eu também criar uma série de funções, como mencionado, alguns dos quais uso acessor informações função para que ele não precisa ser chamado (como é um pouco inconveniente no momento - agora você precisa usar _class .FunctionName (_class_instance, args) -. Eu fui em torno de usar a pilha / trace para agarrar a referência de instância para agarrar o valor adicionando ofunções que quer executar esta maratona pouco, ou adicionando o acessores para o objeto e usando auto (nomeado este ressaltar que eles são para a instância e para reter o acesso ao auto, a referência de classe AccessorFunc e outras informações de dentro da função definições).

Não é bem feito, mas é um fantástico pé-hold. Nota: Se você não usar __Name = AccessorFunc (...) para criar as propriedades, você não terá acesso à chave __ mesmo que eu defini-lo dentro da função init. Se o fizer, então não há problemas.

Além disso: Note que o nome ea chave são diferentes ... Nome é 'formal', usado em Nome da Função Criação, e é a chave para o armazenamento de dados e acesso. ie _class.x onde minúsculas x é a chave, o nome seria maiúscula X para que GetX () é a função em vez de getX (), que parece um pouco estranho. isso permite que self.x de trabalho e olhar adequado, mas também permitir que GetX () e olhar apropriado.

Eu tenho uma classe de exemplo configurado com chave / nome idêntico e diferente para mostrar. um monte de funções auxiliares criadas, a fim de saída de dados (Nota: Nem tudo isso é completa). assim você pode ver o que está acontecendo

A lista atual de funções usando chave: x, name: saídas X como:

Esta é de nenhuma maneira uma lista exaustiva - há alguns que não fizeram isso neste no momento da postagem ...

_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 sendo saída é:

Esta é uma marca nova classe criado usando a classe de demonstração sem dados atribuídos diferente do nome (por isso 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 esta é depois de atribuir todos _foo propriedades (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)                                                                                                                                                                                                   |

Note que por causa da restrição de dados de tipos ou restrições de valor, alguns dados não foi atribuído - este é por design. O setter proíbe maus dados tipos ou valores que está sendo atribuído, mesmo de ser designado como um valor padrão (a menos que você substituir o comportamento de proteção valor padrão)

O código não foi postado aqui porque eu não tenho espaço após os exemplos e explicações ... Também porque ele vai mudar.

Observação: no momento desta postagem, o arquivo é confuso - isso vai mudar. Mas, se você executá-lo em Sublime Texto 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 impressão e GetKeyOutput helper funções, juntamente com sendo alterado para uma função Instância, provavelmente, colocar em uma única função e renomeado - olhar para ele ..)

Next: Nem tudo é necessário para que ele seja executado - um monte de coisas comentou no fundo é para mais informações utilizadas para depurar - pode não estar lá quando você baixá-lo. Se for, você deve ser capaz de uncomment e recompilar para obter mais informações.

Eu estou procurando um trabalho em torno de precisar MyClassBase: passagem, MyClass (MyClassBase):. ... - se você sabe de uma solução - postá-lo

A única coisa necessária na classe são os __ linhas - o str é para depurar como é o init - eles podem ser removidos a partir da classe de demonstração, mas você vai necessidade de se 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 - eles não estão completos. Copiei sobre algumas coisas que eu precisava da biblioteca, e criei alguns novos. O código completo vai ligar para a biblioteca completa e vai incluí-lo juntamente com o fornecimento chamadas atualizados e remover o código (na verdade, o único código esquerda será a classe de demonstração e as demonstrações de impressão - o sistema AccessorFunc serão movidos 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 = { } )

Esta beleza torna incrivelmente fácil para criar novas classescom propriedades adicionadas dinamicamente com AccessorFuncs / retornos de chamada /-tipo de dados / aplicação de valor, etc.

Por enquanto, o link está no (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 texto Sublime, eu recomendo-o sobre Notepad ++, Atom, Visual Código, e outros por causa de implementações de threading adequadas tornando muito, muito mais rápido para uso ... Eu também estou trabalhando em um IDE sistema de mapeamento de código -como para ele - dar uma olhada em: https://bitbucket.org/ Acecool / acecoolcodemappingsystem / src / master / (Adicione Repo em Package Manager em primeiro lugar, em seguida, Instalar Plugin - quando a versão 1.0.0 está pronto, eu vou adicioná-lo à lista de plug-in principal ...)

Espero que esta solução ajuda ... e, como sempre:

Só porque ele funciona, não faz isso direito - Josh 'Acecool' Moser

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top