Question

Le but est de créer une classe fantaisie qui se comporte comme un db resultset.

Ainsi, par exemple, si une requête renvoie la base de données, en utilisant une expression dict, {'ab':100, 'cd':200}, je voudrais voir:

>>> dummy.ab
100

Au début, je pensais que je pouvais le faire de cette façon:

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

mais c.ab retourne un objet de propriété au lieu.

Remplacement de la ligne de setattr avec k = property(lambda x: vs[i]) est d'aucune utilité.

Alors, quelle est la bonne façon de créer une propriété d'instance lors de l'exécution?

P.S. Je suis au courant d'une alternative présentée dans Comment est la méthode utilisée __getattribute__?

Était-ce utile?

La solution

Je suppose que je devrais développer cette réponse, maintenant que je suis plus vieux et plus sage et de savoir ce qui se passe. Mieux vaut tard que jamais.

peut ajouter une propriété à une classe dynamique. Mais ce qui est le hic: vous devez l'ajouter à la class

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

A property est en fait une mise en œuvre simple d'une chose appelée descripteur . Il est un objet qui fournit la gestion personnalisée pour un attribut donné, sur une classe donnée . Un peu comme un moyen de tenir un énorme arbre if sur __getattribute__.

Quand je demande foo.b dans l'exemple ci-dessus, Python voit que le b défini sur la classe implémente protocole descripteur -qui signifie simplement qu'il est un objet avec un __get__, __set__ ou méthode __delete__. Le descripteur revendique la responsabilité de la manipulation de cet attribut, donc Python appelle Foo.b.__get__(foo, Foo), et la valeur de retour est passé de nouveau à vous en tant que valeur de l'attribut. Dans le cas de property, chacune de ces méthodes appelle simplement le fget, fset ou fdel vous avez passé au constructeur de property.

Descripteurs sont vraiment la façon de Python d'exposer la plomberie de sa mise en œuvre entière OO. En fait, il y a un autre type de descripteur encore plus fréquent 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>

La méthode humble est juste un autre type de descripteur. Ses bords de __get__ sur l'instance d'appel comme premier argument; en effet, il le fait:

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

Quoi qu'il en soit, je soupçonne que c'est pourquoi les descripteurs ne fonctionnent que sur les classes: ils sont une formalisation des choses que les classes de pouvoirs en premier lieu. Ils sont même l'exception à la règle: vous pouvez assigner des descripteurs évidemment à une classe, et les classes elles-mêmes sont des instances de type! En fait, en essayant de lire Foo.b appelle encore property.__get__; il est juste idiomatiques pour les descripteurs de se retourner quand on y accède comme attributs de classe.

Je pense qu'il est assez cool que la quasi-totalité du système OO Python peut être exprimé en Python. :)

Oh, et je l'ai écrit un blog verbeux sur les descripteurs un certain temps si vous êtes intéressé.

Autres conseils

  

Le but est de créer une classe fantaisie qui se comporte comme un db resultset.

Alors qu'est-ce que vous voulez est un dictionnaire où vous pouvez épeler un [ « b »] comme a.b?

C'est facile:

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

Il semble que vous pouvez résoudre ce problème beaucoup plus simplement avec un namedtuple , puisque vous savez la liste complète des champs à l'avance.

from collections import namedtuple

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

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

foo2 = Foo()  # error

Si vous avez absolument besoin d'écrire votre propre setter, vous aurez à faire le metaprogramming au niveau de la classe; property() ne fonctionne pas sur les instances.

Vous n'avez pas besoin d'utiliser une propriété pour cela. Il suffit de passer outre __setattr__ pour les rendre en lecture seule.

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!
  

Comment ajouter la propriété à une classe python dynamique?

Disons que vous avez un objet que vous souhaitez ajouter une propriété à. En règle générale, je veux utiliser les propriétés quand je dois commencer à gérer l'accès à un attribut dans le code qui a l'utilisation en aval, afin que je puisse maintenir une API cohérente. Maintenant, je vais généralement les ajouter au code source où l'objet est défini, mais supposons que vous n'avez pas accès, ou vous devez choisir vraiment dynamiquement vos fonctions par programme.

Créer une classe

En utilisant un exemple basé sur la property, nous allons créer une classe d'objet avec un attribut « caché » et créer une instance de celui-ci:

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

o = C()

En Python, nous nous attendons à ce être une façon évidente de faire les choses. Cependant, dans ce cas, je vais montrer deux façons: avec la notation de décorateur, et sans. Tout d'abord, sans notation de décorateur. Cela peut être plus utile pour l'affectation dynamique des getters, setters, ou les suppresseurs.

Dynamique (alias Monkey Patcher)

Créons un peu pour notre classe:

def getx(self):
    return self._x

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

def delx(self):
    del self._x

Et maintenant, nous attribuons ces à la propriété. Notez que nous pourrions choisir nos fonctions ici par programmation, répondant à la question dynamique:

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

utilisation:

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

    I'm the 'x' property.

Décorateurs

Nous pourrions faire la même chose que nous avons fait précédemment avec la notation de décorateur, mais dans ce cas, nous doit nommer les méthodes tout le même nom (et je vous recommande de garder la même chose que l'attribut ), il est donc affectation programmatique est pas si trivial que l'utilisation du procédé ci-dessus:

@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

Et affecter l'objet de la propriété avec ses setters provisionnés et les suppresseurs à la classe:

C.x = x

utilisation:

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

J'ai posé une question href="https://stackoverflow.com/questions/1264833/python-class-factory-to-produce-simple-struct-like-classes"> similairement pour créer une usine de classe qui a créé des types simples. Le résultat était cette réponse qui avait une version de travail de l'usine de classe. Voici un extrait de la réponse:

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

Vous pouvez utiliser une variante de cette option pour créer des valeurs par défaut qui est votre objectif (il y a aussi une réponse à cette question qui traite de ce sujet).

Vous ne pouvez pas ajouter une nouvelle property() à une instance lors de l'exécution, parce que les propriétés sont des descripteurs de données. Au lieu de cela, vous devez créer dynamiquement une nouvelle classe ou __getattribute__ de surcharge afin de traiter les descripteurs de données sur les instances.

Je ne sais pas si je comprends complètement la question, mais vous pouvez modifier les propriétés d'instance à l'exécution avec le haut-__dict__ de votre 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

Pour ceux qui viennent des moteurs de recherche, voici les deux choses que je recherchais quand on parle de dynamiques propriétés:

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__ est bon si vous voulez mettre des propriétés créées dynamiquement. __getattr__ est bon de faire quelque chose que lorsque la valeur est nécessaire, comme une base de données requête. Le set / get combo est bon de simplifier l'accès aux données stockées dans la classe (comme dans l'exemple ci-dessus).

Si vous voulez seulement une propriété dynamique, un regard sur la propriété ( ) fonction intégrée.

La meilleure façon de réaliser est en définissant __slots__. De cette façon, vos instances ne peut pas avoir de nouveaux attributs.

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

qui imprime 12

    c.ab = 33

Cela donne: AttributeError: 'C' object has no attribute 'ab'

Juste un autre exemple comment obtenir un effet désiré

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)

Alors maintenant, nous pouvons faire des choses comme:

>>> foo = Foo('baz')
>>> foo.baz = 5
>>> foo.bar
5
>>> foo.baz
5

Vous pouvez utiliser le code suivant pour mettre à jour les attributs de classe à l'aide d'un objet dictionnaire:

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

Cela semble fonctionner (mais voir ci-dessous):

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

Si vous avez besoin d'un comportement plus complexe, vous pouvez modifier votre réponse.

modifier

Ce qui suit serait probablement plus efficace mémoire pour les grands ensembles de données:

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

Pour répondre à l'objectif principal de votre question, vous voulez un attribut de lecture seule d'un dict comme source de données immuable:

  

Le but est de créer une classe fantaisie qui se comporte comme un db resultset.

     

Ainsi, par exemple, si une requête renvoie la base de données, en utilisant une expression dict,   {'ab':100, 'cd':200}, alors je voir

>>> dummy.ab
100

Je vais vous montrer comment utiliser un namedtuple du module collections pour accomplir ceci:

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

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

Et la sortie est:

>> 1

L'extension de l'idée 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)

Sortie:

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

Bien que de nombreuses réponses sont données, je ne pouvais pas trouver que je suis heureux. Je me suis ma propre solution qui rend le travail de property pour le cas dynamique. La source pour répondre à la question initiale:

#!/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

Quelque chose qui fonctionne pour moi est la suivante:

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)

Sortie

a
aa

Ceci est un peu différent de ce que OP voulait, mais je secoué mon cerveau jusqu'à ce que je suis arrivé une solution de travail, donc je suis en train ici pour le gars à côté / gal

Il me fallait un moyen de spécifier setters dynamiques et 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)

Je sais que mes champs avance afin im va créer mes propriétés. REMARQUE: vous ne pouvez pas le faire par instance, ces propriétés existeront sur la classe !!!

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

Testons tout maintenant ..

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

Est-il confus? Oui, désolé, je ne pouvais pas venir avec des exemples du monde réel significatives. En outre, ce n'est pas pour le cœur léger.

La seule façon d'attacher dynamiquement une propriété est de créer une nouvelle classe et son instance avec votre nouvelle propriété.

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

J'ai récemment rencontré un problème similaire, la solution que je suis venu avec des utilisations __getattr__ et __setattr__ pour les propriétés que je veux à gérer, tout le reste se transmet aux originaux.

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

Beaucoup des réponses fournies exigent tant de lignes par propriété, par exemple / et / ou - ce que je considère comme une mise en œuvre laid ou fastidieux à cause de répétitivité nécessaire pour plusieurs propriétés, etc. Je préfère garder les choses bouillir / simplifier jusqu'à ce qu'ils ne peuvent pas être simplifiées plus ou jusqu'à ce qu'il ne sert pas à grand-chose à faire.

En bref: dans les travaux terminés, si je le répète 2 lignes de code, je convertir généralement en une fonction d'aide d'une seule ligne, et ainsi de suite ... je simplifie les arguments mathématiques ou impair tels que (start_x, start_y, end_x, end_y) à (x, y, w, h), à savoir x, y, x + w, y + h (nécessitant parfois min / max ou si w / h sont négatives et la mise en oeuvre ne l'aime pas, je retranche à partir de x / y et w abs / h. etc ..).

Surcharger les getters internes / setters est un moyen d'aller ok, mais le problème est que vous devez le faire pour toutes les classes, ou d'un parent de la classe à cette base ... Cela ne fonctionne pas pour moi comme je l'avais préfèrent être libres de choisir les enfants / parents pour l'héritage, les nœuds enfants, etc.

J'ai créé une solution qui répond à la question sans utiliser Dict données de type pour fournir les données que je trouve que pour être fastidieux d'entrer les données, etc ...

Ma solution vous oblige à ajouter 2 lignes supplémentaires au-dessus de votre classe pour créer une classe de base pour la classe que vous souhaitez ajouter les propriétés à, puis 1 ligne par et vous avez la possibilité d'ajouter des callbacks pour contrôler les données, vous informer lorsque les données changent, limitent les données qui peuvent être fixés en fonction de la valeur et / ou de type de données, et bien plus encore.

Vous avez également la possibilité d'utiliser _object.x, _object.x = valeur, _object.GetX (), _object.SetX (valeur) et ils sont traités de manière équivalente.

En outre, les valeurs sont les seules données non statiques qui sont affectés à l'instance de classe, mais la propriété réelle est attribué à la classe qui signifie que les choses que vous ne voulez pas répéter, ne pas besoin d'être répétées. .. Vous pouvez attribuer une valeur par défaut de sorte que le getter n'a pas besoin chaque fois, bien qu'il y ait une option pour remplacer la valeur par défaut par défaut, et il y a une autre option de sorte que le getter retourne la valeur stockée brute en remplaçant le rendement par défaut (note : cette méthode signifie que la valeur brute est attribué uniquement lorsqu'une valeur est affectée, sinon il est Aucun - lorsque la valeur est remis à zéro, il attribue None, etc ..)

Il y a beaucoup de fonctions d'aide aussi - la première propriété qui est ajouté ajoute 2 ou si des aides à la classe pour référencer les valeurs d'instance ... Ils sont ResetAccessors (_key, ..) VarArgs répétées (tout peut être répété en utilisant la premier nommé args) et SetAccessors (_key, _value) avec l'option de plus ajoutés à la classe principale d'aide en matière d'efficacité - ceux prévus sont: une façon de regrouper accesseurs ensemble, donc si vous avez tendance à réinitialiser un peu à la fois , à chaque fois, vous pouvez les affecter à un groupe et remettre le groupe au lieu de répéter les clés nommées à chaque fois, et plus encore.

L'instance / première valeur stockée est stockée à classe. , le __CLASS. fait référence à la classe accesseur qui détient vars / valeurs / fonctions statiques pour la propriété. _classe. est la propriété elle-même qui est appelé quand on y accède par la classe d'instance pendant le réglage / obtenir, etc.

Le accesseurs de .__ des points à la classe, mais parce qu'il est interne, il doit être affecté à la classe qui est la raison pour laquelle je choisi d'utiliser __Nom = AccessorFunc (...) pour l'affecter, une seule ligne par propriété avec de nombreux arguments optionnels à utiliser (en utilisant varargs à clé parce qu'ils sont plus faciles et plus efficaces pour identifier et maintenir) ...

Je crée aussi beaucoup de fonctions, comme mentionné, dont certains utilisent informations de fonction accesseur donc il n'a pas besoin d'être appelé (comme il est un peu gênant au moment - en ce moment, vous devez utiliser _class .FunctionName (_class_instance, args) -. Je suis en utilisant autour de la pile / trace pour saisir la référence d'instance pour saisir la valeur par adjonction,fonctions qui soit exécutent ce marathon bits, ou en ajoutant les accesseurs à l'objet et à l'aide d'auto (appelé ce à signaler qu'ils sont pour l'instance et de conserver l'accès à soi-même, la référence de classe AccessorFunc, et d'autres informations à partir de la fonction définitions).

Il est pas tout à fait fait, mais il est un pied-attente fantastique. Remarque: Si vous n'utilisez pas __Nom = AccessorFunc (...) pour créer les propriétés, vous n'aurez pas accès à la clé __ même si je le définis dans la fonction init. Si vous le faites, alors il n'y a aucun problème.

Aussi: Notez que le nom et la clé sont différentes ... Le nom est « formel », utilisé dans le champ Nom de la fonction Création, et la clé est pour le stockage et l'accès aux données. à savoir _class.x où x minuscule est la clé, le nom serait en majuscule X de sorte que GetX () est la fonction au lieu de GetX () qui semble un peu étrange. cela permet self.x de travailler et de regarder approprié, mais aussi permettre GetX () et regardez approprié.

J'ai une classe d'exemple mis en place avec la clé / nom identique et différent de montrer. un grand nombre de fonctions d'aide créés pour la sortie des données. (Note: Pas tout cela est terminé) afin que vous puissiez voir ce qui se passe

La liste des fonctions à l'aide clé: x, nom: sorties X comme:

est pas une liste complète - il y a quelques-unes qui ne l'ont pas fait sur ce au moment de l'affichage ...

_instance.SetAccessors( _key, _value [ , _key, _value ] .. )                   Instance Class Helper Function: Allows assigning many keys / values on a single line - useful for initial setup, or to minimize lines.    In short: Calls this.Set<Name>( _value ) for each _key / _value pairing.
_instance.ResetAccessors( _key [ , _key ] .. )                                 Instance Class Helper Function: Allows resetting many key stored values to None on a single line.                                           In short: Calls this.Reset<Name>() for each name provided.


Note: Functions below may list self.Get / Set / Name( _args ) - self is meant as the class instance reference in the cases below - coded as this in AccessorFuncBase Class.

this.GetX( _default_override = None, _ignore_defaults = False )                 GET:            Returns    IF ISSET: STORED_VALUE .. IF IGNORE_DEFAULTS: None  .. IF PROVIDED: DEFAULT_OVERRIDE ELSE: DEFAULT_VALUE       100
this.GetXRaw( )                                                                 RAW:            Returns    STORED_VALUE                                                                                                     100
this.IsXSet( )                                                                  ISSET:          Returns    ( STORED_VALUE != None )                                                                                         True

this.GetXToString( )                                                            GETSTR:         Returns    str( GET )                                                                                                       100
this.GetXLen( _default_override = None, _ignore_defaults = False )              LEN:            Returns    len( GET )                                                                                                       3
this.GetXLenToString( _default_override = None, _ignore_defaults = False )      LENSTR:         Returns    str( len( GET ) )                                                                                                3
this.GetXDefaultValue( )                                                        DEFAULT:        Returns    DEFAULT_VALUE                                                                                                    1111

this.GetXAccessor( )                                                            ACCESSOR:       Returns    ACCESSOR_REF ( self.__<key> )                                                                                    [ AccessorFuncBase ] Key: x : Class ID: 2231452344344 : self ID: 2231448283848        Default: 1111       Allowed Types: {"<class 'int'>": "<class 'type'>", "<class 'float'>": "<class 'type'>"}     Allowed Values: None
this.GetXAllowedTypes( )                                                        ALLOWED_TYPES:  Returns    Allowed Data-Types                                                                                               {"<class 'int'>": "<class 'type'>", "<class 'float'>": "<class 'type'>"}
this.GetXAllowedValues( )                                                       ALLOWED_VALUES: Returns    Allowed Values                                                                                                   None

this.GetXHelpers( )                                                             HELPERS:        Returns    Helper Functions String List - ie what you're reading now...                                                     THESE ROWS OF TEXT
this.GetXKeyOutput( )                                                           Returns information about this Name / Key                                                                                                   ROWS OF TEXT
this.GetXGetterOutput( )                                                        Returns information about this Name / Key                                                                                                   ROWS OF TEXT

this.SetX( _value )                                                             SET:            STORED_VALUE Setter - ie Redirect to __<Key>.Set                                                                            N / A
this.ResetX( )                                                                  RESET:          Resets STORED_VALUE to None                                                                                                 N / A

this.HasXGetterPrefix( )                                                        Returns Whether or Not this key has a Getter Prefix...                                                                                      True
this.GetXGetterPrefix( )                                                        Returns Getter Prefix...                                                                                                                    Get

this.GetXName( )                                                                Returns Accessor Name - Typically Formal / Title-Case                                                                                       X
this.GetXKey( )                                                                 Returns Accessor Property Key - Typically Lower-Case                                                                                        x
this.GetXAccessorKey( )                                                         Returns Accessor Key - This is to access internal functions, and static data...                                                             __x
this.GetXDataKey( )                                                             Returns Accessor Data-Storage Key - This is the location where the class instance value is stored..                                         _x

Certaines des données étant la sortie est:

Ceci est pour une toute nouvelle classe créée en utilisant la classe de démonstration sans données affectées autre que le nom (il peut donc être sortie) qui est _foo, le nom de la variable je ...

_foo         --- MyClass: ---- id( this.__class__ ): 2231452349064 :::: id( this ): 2231448475016

    Key       Getter Value        | Raw Key   Raw / Stored Value       | Get Default Value             Default Value            | Get Allowed Types             Allowed Types                                                              | Get Allowed Values            Allowed Values                                                                                                                                                                                                                   |

    Name:     _foo                | _Name:    _foo                     | __Name.DefaultValue( ):       AccessorFuncDemoClass    | __Name.GetAllowedTypes( )     <class 'str'>                                                              | __Name.GetAllowedValues( )    Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    x:        1111                | _x:       None                     | __x.DefaultValue( ):          1111                     | __x.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __x.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    y:        2222                | _y:       None                     | __y.DefaultValue( ):          2222                     | __y.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __y.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    z:        3333                | _z:       None                     | __z.DefaultValue( ):          3333                     | __z.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __z.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Blah:     <class 'int'>       | _Blah:    None                     | __Blah.DefaultValue( ):       <class 'int'>            | __Blah.GetAllowedTypes( )     <class 'str'>                                                              | __Blah.GetAllowedValues( )    Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Width:    1                   | _Width:   None                     | __Width.DefaultValue( ):      1                        | __Width.GetAllowedTypes( )    (<class 'int'>, <class 'bool'>)                                            | __Width.GetAllowedValues( )   Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Height:   0                   | _Height:  None                     | __Height.DefaultValue( ):     0                        | __Height.GetAllowedTypes( )   <class 'int'>                                                              | __Height.GetAllowedValues( )  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)                                                                                                                                                                                                   |
    Depth:    2                   | _Depth:   None                     | __Depth.DefaultValue( ):      2                        | __Depth.GetAllowedTypes( )    Saved Value Restricted to Authorized Values ONLY                           | __Depth.GetAllowedValues( )   (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)                                                                                                                                                                                                   |


this.IsNameSet( ):    True      this.GetName( ):     _foo                     this.GetNameRaw( ):    _foo                     this.GetNameDefaultValue( ):    AccessorFuncDemoClass    this.GetNameLen( ):    4    this.HasNameGetterPrefix( ):    <class 'str'>                                this.GetNameGetterPrefix( ):    None
this.IsXSet( ):       False     this.GetX( ):        1111                     this.GetXRaw( ):       None                     this.GetXDefaultValue( ):       1111                     this.GetXLen( ):       4    this.HasXGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetXGetterPrefix( ):       None
this.IsYSet( ):       False     this.GetY( ):        2222                     this.GetYRaw( ):       None                     this.GetYDefaultValue( ):       2222                     this.GetYLen( ):       4    this.HasYGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetYGetterPrefix( ):       None
this.IsZSet( ):       False     this.GetZ( ):        3333                     this.GetZRaw( ):       None                     this.GetZDefaultValue( ):       3333                     this.GetZLen( ):       4    this.HasZGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetZGetterPrefix( ):       None
this.IsBlahSet( ):    False     this.GetBlah( ):     <class 'int'>            this.GetBlahRaw( ):    None                     this.GetBlahDefaultValue( ):    <class 'int'>            this.GetBlahLen( ):    13   this.HasBlahGetterPrefix( ):    <class 'str'>                                this.GetBlahGetterPrefix( ):    None
this.IsWidthSet( ):   False     this.GetWidth( ):    1                        this.GetWidthRaw( ):   None                     this.GetWidthDefaultValue( ):   1                        this.GetWidthLen( ):   1    this.HasWidthGetterPrefix( ):   (<class 'int'>, <class 'bool'>)              this.GetWidthGetterPrefix( ):   None
this.IsDepthSet( ):   False     this.GetDepth( ):    2                        this.GetDepthRaw( ):   None                     this.GetDepthDefaultValue( ):   2                        this.GetDepthLen( ):   1    this.HasDepthGetterPrefix( ):   None                                         this.GetDepthGetterPrefix( ):   (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
this.IsHeightSet( ):  False     this.GetHeight( ):   0                        this.GetHeightRaw( ):  None                     this.GetHeightDefaultValue( ):  0                        this.GetHeightLen( ):  1    this.HasHeightGetterPrefix( ):  <class 'int'>                                this.GetHeightGetterPrefix( ):  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

Et ce, après l'attribution de toutes les propriétés _foo (sauf le nom) les valeurs suivantes dans le même ordre: 'string', 1.0, True, 9, 10, Faux

this.IsNameSet( ):    True      this.GetName( ):     _foo                     this.GetNameRaw( ):    _foo                     this.GetNameDefaultValue( ):    AccessorFuncDemoClass    this.GetNameLen( ):    4    this.HasNameGetterPrefix( ):    <class 'str'>                                this.GetNameGetterPrefix( ):    None
this.IsXSet( ):       True      this.GetX( ):        10                       this.GetXRaw( ):       10                       this.GetXDefaultValue( ):       1111                     this.GetXLen( ):       2    this.HasXGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetXGetterPrefix( ):       None
this.IsYSet( ):       True      this.GetY( ):        10                       this.GetYRaw( ):       10                       this.GetYDefaultValue( ):       2222                     this.GetYLen( ):       2    this.HasYGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetYGetterPrefix( ):       None
this.IsZSet( ):       True      this.GetZ( ):        10                       this.GetZRaw( ):       10                       this.GetZDefaultValue( ):       3333                     this.GetZLen( ):       2    this.HasZGetterPrefix( ):       (<class 'int'>, <class 'float'>)             this.GetZGetterPrefix( ):       None
this.IsBlahSet( ):    True      this.GetBlah( ):     string Blah              this.GetBlahRaw( ):    string Blah              this.GetBlahDefaultValue( ):    <class 'int'>            this.GetBlahLen( ):    11   this.HasBlahGetterPrefix( ):    <class 'str'>                                this.GetBlahGetterPrefix( ):    None
this.IsWidthSet( ):   True      this.GetWidth( ):    False                    this.GetWidthRaw( ):   False                    this.GetWidthDefaultValue( ):   1                        this.GetWidthLen( ):   5    this.HasWidthGetterPrefix( ):   (<class 'int'>, <class 'bool'>)              this.GetWidthGetterPrefix( ):   None
this.IsDepthSet( ):   True      this.GetDepth( ):    9                        this.GetDepthRaw( ):   9                        this.GetDepthDefaultValue( ):   2                        this.GetDepthLen( ):   1    this.HasDepthGetterPrefix( ):   None                                         this.GetDepthGetterPrefix( ):   (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
this.IsHeightSet( ):  True      this.GetHeight( ):   9                        this.GetHeightRaw( ):  9                        this.GetHeightDefaultValue( ):  0                        this.GetHeightLen( ):  1    this.HasHeightGetterPrefix( ):  <class 'int'>                                this.GetHeightGetterPrefix( ):  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

_foo         --- MyClass: ---- id( this.__class__ ): 2231452349064 :::: id( this ): 2231448475016

    Key       Getter Value        | Raw Key   Raw / Stored Value       | Get Default Value             Default Value            | Get Allowed Types             Allowed Types                                                              | Get Allowed Values            Allowed Values                                                                                                                                                                                                                   |

    Name:     _foo                | _Name:    _foo                     | __Name.DefaultValue( ):       AccessorFuncDemoClass    | __Name.GetAllowedTypes( )     <class 'str'>                                                              | __Name.GetAllowedValues( )    Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    x:        10                  | _x:       10                       | __x.DefaultValue( ):          1111                     | __x.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __x.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    y:        10                  | _y:       10                       | __y.DefaultValue( ):          2222                     | __y.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __y.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    z:        10                  | _z:       10                       | __z.DefaultValue( ):          3333                     | __z.GetAllowedTypes( )        (<class 'int'>, <class 'float'>)                                           | __z.GetAllowedValues( )       Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Blah:     string Blah         | _Blah:    string Blah              | __Blah.DefaultValue( ):       <class 'int'>            | __Blah.GetAllowedTypes( )     <class 'str'>                                                              | __Blah.GetAllowedValues( )    Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Width:    False               | _Width:   False                    | __Width.DefaultValue( ):      1                        | __Width.GetAllowedTypes( )    (<class 'int'>, <class 'bool'>)                                            | __Width.GetAllowedValues( )   Saved Value Restrictions Levied by Data-Type                                                                                                                                                                                     |
    Height:   9                   | _Height:  9                        | __Height.DefaultValue( ):     0                        | __Height.GetAllowedTypes( )   <class 'int'>                                                              | __Height.GetAllowedValues( )  (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)                                                                                                                                                                                                   |
    Depth:    9                   | _Depth:   9                        | __Depth.DefaultValue( ):      2                        | __Depth.GetAllowedTypes( )    Saved Value Restricted to Authorized Values ONLY                           | __Depth.GetAllowedValues( )   (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)                                                                                                                                                                                                   |

Notez qu'en raison de types de données à des restrictions ou des restrictions de valeur, certaines données n'a pas été attribué - c'est par la conception. Le poseur interdit les mauvais types de données ou des valeurs d'être affecté, même d'être affecté comme valeur par défaut (sauf si vous remplacez le comportement de la protection de la valeur par défaut)

Le code n'a pas été posté ici parce que je n'ai pas la place après les exemples et explications ... Aussi parce que cela va changer.

S'il vous plaît noter: au moment de cette annonce, le fichier est en désordre - cela va changer. Mais, si vous exécutez en mode texte sublime et compilez, ou l'exécuter à partir de Python, il va compiler et cracher une tonne d'informations - la partie AccessorDB ne se fait pas (qui sera utilisé pour mettre à jour les accesseurs d'impression et aide GetKeyOutput fonctions tout en étant changés en fonction de l'instance, sans doute mis en une seule fonction et renommé - chercher ..)

suivant: Pas tout est nécessaire pour son exécution - beaucoup de choses commenté au fond est pour plus d'informations utilisées pour le débogage - il ne peut pas être là quand vous le téléchargez. Dans ce cas, vous devriez être en mesure de décommenter et recompiler pour obtenir plus d'informations.

Je cherche un travail autour de besoin MyClassBase: passer, MyClass (MyClassBase):. ... - si vous connaissez une solution - post it

La seule chose nécessaire dans la classe sont les lignes __ - str est pour le débogage comme est le init - ils peuvent être retirés de la classe de démonstration mais vous besoin de commenter ou supprimer certaines des lignes ci-dessous (_foo / 2/3) ..

La chaîne, les classes Dict et Util au sommet font partie de ma bibliothèque Python - ils ne sont pas complets. Je recopié quelques choses que je avais besoin de la bibliothèque, et j'ai créé quelques nouvelles. Le code complet reliera à la bibliothèque complète et inclure ainsi que de fournir des appels mis à jour et la suppression du code (en fait, le seul code à gauche sera la classe de démonstration et les états d'impression - le système AccessorFunc sera déplacé à la bibliothèque). ..

Une partie du fichier:

##
## MyClass Test AccessorFunc Implementation for Dynamic 1-line Parameters
##
class AccessorFuncDemoClassBase( ):
    pass
class AccessorFuncDemoClass( AccessorFuncDemoClassBase ):
    __Name      = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'Name',      default = 'AccessorFuncDemoClass',  allowed_types = ( TYPE_STRING ),                    allowed_values = VALUE_ANY,                 documentation = 'Name Docs',        getter_prefix = 'Get',  key = 'Name',       allow_erroneous_default = False,    options = { } )
    __x         = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'X',         default = 1111,                     allowed_types = ( TYPE_INTEGER, TYPE_FLOAT ),       allowed_values = VALUE_ANY,                 documentation = 'X Docs',           getter_prefix = 'Get',  key = 'x',          allow_erroneous_default = False,    options = { } )
    __Height    = AccessorFuncBase( parent = AccessorFuncDemoClassBase, name = 'Height',    default = 0,                        allowed_types = TYPE_INTEGER,                       allowed_values = VALUE_SINGLE_DIGITS,       documentation = 'Height Docs',      getter_prefix = 'Get',  key = 'Height',     allow_erroneous_default = False,    options = { } )

Cette beauté rend incroyablement facile de créer de nouvelles classesavec des propriétés ajoutées dynamiquement avec AccessorFuncs / callbacks / données de type / application de la valeur, etc.

Pour l'instant, le lien est à (Ce lien doit refléter les modifications du document.): https://www.dropbox.com/s/6gzi44i7dh58v61/dynamic_properties_accessorfuncs_and_more.py?dl=0

Aussi: Si vous ne l'utilisez Sublime Text, je le recommande sur Notepad ++, Atom, code visuel, et d'autres en raison de mises en œuvre de filetage appropriés rendant beaucoup, beaucoup plus rapide à utiliser ... Je travaille également sur un IDE système de cartographie de code -comme pour lui - jetez un oeil à: https://bitbucket.org/ Acecool / acecoolcodemappingsystem / src / master / (Ajouter Repo package Manager, puis installer le plugin - lorsque la version 1.0.0 est prêt, je vais l'ajouter à la liste principale du plugin ...)

J'espère que cette solution aide ... et, comme toujours:

Juste parce que cela fonctionne, ne le rend pas droit - Josh 'Acecool Moser

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top