Frage

Das Ziel ist, eine Mock-Klasse, die verhält sich wie ein db resultset zu erstellen.

So zum Beispiel, wenn eine Datenbankabfrage zurückgibt, einen dict Ausdruck verwendet, {'ab':100, 'cd':200}, dann würde ich gerne sehen:

>>> dummy.ab
100

Zuerst dachte ich, vielleicht könnte ich es auf diese Weise tun:

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

aber c.ab kehrt eine Eigenschaft Objekt statt.

mit setattr die k = property(lambda x: vs[i]) Linie zu ersetzen, ist nicht von Nutzen überhaupt.

Also, was ist der richtige Weg, um eine Instanz Eigenschaft zur Laufzeit erstellen?

P. S. Ich bin mir dessen bewusst eine Alternative präsentiert in Wie die __getattribute__ Methode verwendet wird?

War es hilfreich?

Lösung

Ich nehme ich diese Antwort erweitern sollte, jetzt, wo ich bin älter und weiser und weiß, was los ist. Besser spät als nie.

Sie können eine Eigenschaft zu einer Klasse dynamisch hinzufügen. Aber das ist der Haken: Sie es hinzufügen müssen die Klasse

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

Ein property ist eigentlich eine einfache Implementierung eines Ding namens ein Descriptor . Es ist ein Objekt, das benutzerdefinierte bietet für ein bestimmtes Attribut Umgang mit auf einer bestimmten Klasse . Kinda wie ein Weg, ein großer if Baum aus __getattribute__ zu Faktor.

Als ich für foo.b im Beispiel fragen oben, sieht Python, dass die b auf die Klasse implementiert definiert die Descriptor Protokoll -Welche nur bedeutet, es ist ein Objekt mit einem __get__, __set__ oder __delete__ Verfahren. Die Descriptor Anspruch Verantwortung für dieses Attribut Handhabung, so Python Foo.b.__get__(foo, Foo) nennt, und der Rückgabewert wird als der Wert des Attributs zurück an Sie weitergegeben. Im Falle von property, jede dieser Methoden nur Anrufe der fget, fset oder fdel Sie an den property Konstruktor übergeben.

Deskriptoren sind wirklich Art und Weise der Python von der Sanitär seiner gesamten OO Umsetzung auszusetzen. In der Tat ist es eine andere Art von Descriptor sogar häufiger als 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>

Die bescheidene Methode ist nur eine andere Art von Deskriptor. Seine __get__ Angriffe auf die anrufende Instanz als erstes Argument; in der Tat, es tut dies:

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

Wie auch immer, ich vermute, das ist, warum Deskriptoren nur auf Klassen arbeiten: sie sind eine Formalisierung der Sachen, die Kräfte Klassen in dem ersten Platz. Sie sind auch die Ausnahme von der Regel: Sie können offensichtlich assign Deskriptoren zu einer Klasse und Klassen sind selbst Instanzen type! In der Tat, Foo.b noch zu lesen versucht, ruft property.__get__; es ist nur idiomatisch für Deskriptoren selbst zurückzukehren, wenn sie als Klassenattribute abgerufen.

Ich denke, es ist ziemlich cool, dass praktisch alle OO-System Python in Python ausgedrückt werden. :)

Oh, und ich schrieb eine wortreich Blog-Post über Deskriptoren eine Weile zurück, wenn Sie interessiert sind.

Andere Tipps

  

Das Ziel ist, eine Mock-Klasse, die verhält sich wie ein db resultset zu erstellen.

Also, was Sie wollen, ist ein Wörterbuch, in dem Sie eine [ ‚b‘] als a.b buchstabieren können?

Das ist ganz einfach:

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

Es scheint, dass Sie dieses Problem lösen könnten viel einfacher mit einem namedtuple , da Sie die gesamte Liste der Felder im voraus wissen.

from collections import namedtuple

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

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

foo2 = Foo()  # error

Wenn Sie unbedingt benötigen, um Ihren eigenen Setter zu schreiben, werden Sie den metaprogramming auf Klassenebene zu tun haben; property() funktioniert nicht auf Instanzen.

Sie brauchen nicht eine Eigenschaft dafür zu verwenden. Nur __setattr__ außer Kraft setzen, um sie nur gelesen werden.

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!
  

Wie fügt Eigenschaft auf eine Python-Klasse dynamisch?

Sagen Sie ein Objekt haben, dass Sie eine Eigenschaft hinzufügen möchten. Normalerweise mag ich Eigenschaften verwenden, wenn ich Zugriff auf ein Attribut in Code beginnen muß die Verwaltung, die Downstream-Nutzung hat, so dass ich eine konsistente API halten kann. Jetzt werde ich in der Regel fügen sie dem Quellcode, in dem das Objekt definiert ist, aber nehmen wir an, Sie nicht, dass der Zugang haben, oder Sie brauchen, um wirklich dynamisch Ihre Funktionen programmatisch zu wählen.

Erstellen Sie eine Klasse

Anhand eines Beispiels auf der Grundlage der Dokumentation für property , lassen Sie uns erstellen eine Klasse von Objekten mit einem Attribut „versteckt“ und eine Instanz davon erstellen:

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

o = C()

In Python, erwarten wir dort eine offensichtliche Art und Weise, Dinge zu tun sein. Doch in diesem Fall werde ich zwei Möglichkeiten, um zu zeigen: mit Dekorateur Notation, und ohne. Zuerst ohne Dekorateur Notation. Dies kann nützlich für die dynamische Zuweisung von Getter, Setter oder Löscher sein.

Dynamische (auch bekannt als Affe Patchen)

Lassen Sie uns einige für unsere Klasse erstellen:

def getx(self):
    return self._x

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

def delx(self):
    del self._x

Und jetzt weisen wir diese auf die Eigenschaft. Beachten Sie, dass wir unsere Funktionen hier programmatisch wählen könnte, die dynamische Frage zu beantworten:

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

Und Nutzung:

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

    I'm the 'x' property.

Dekorateure

Wir könnten das gleiche tun wie wir oben mit Dekorateur Notation tat, aber in diesem Fall haben wir müssen Namen, um die Methoden alle den gleichen Namen (und ich würde empfehlen, es das gleiche wie das Attribut zu halten ), so programmatische Zuordnung ist nicht so trivial, wie es das obige Verfahren wird unter Verwendung von:

@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

und weisen Sie die Eigenschaft Objekt mit seinen provisioniert Setter und Löscher zur Klasse:

C.x = x

Und Nutzung:

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

Sie können keine neue property() zu einer Instanz zur Laufzeit hinzufügen, da Eigenschaftsdaten Deskriptoren sind. Stattdessen müssen Sie dynamisch eine neue Klasse erstellen, oder Überlastung __getattribute__, um Prozessdaten-Deskriptoren auf Instanzen.

Nicht sicher, ob ich völlig verstehe die Frage, aber Sie können beispielsweise Eigenschaften zur Laufzeit mit dem eingebauten in __dict__ Ihrer Klasse ändern:

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

Der beste Weg zu erreichen, ist durch __slots__ definieren. Auf diese Weise Ihre Instanzen können keine neuen Attribute haben.

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

Das druckt 12

    c.ab = 33

Das gibt: AttributeError: 'C' object has no attribute 'ab'

Nur ein weiteres Beispiel dafür, wie gewünschten Effekt zu erzielen

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)

So, jetzt können wir wie Dinge tun:

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

Sie können den folgenden Code-Update-Klasse verwenden Attribute ein Dictionary-Objekt mit:

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

Das scheint zu funktionieren (aber siehe unten):

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

Wenn Sie ein komplexeres Verhalten benötigen, können Sie Ihre Antwort zu bearbeiten.

Bearbeiten

In der folgenden würde wahrscheinlich speichereffizienter für große Datensätze sein:

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

Um die Hauptstoßrichtung Ihrer Frage zu beantworten, die Sie wollen eine schreibgeschützte Attribut aus einer dict als unveränderliche Datenquelle:

  

Das Ziel ist, eine Mock-Klasse, die verhält sich wie ein db resultset zu erstellen.

     

So zum Beispiel, wenn eine Datenbankabfrage zurückgibt, ein dict Ausdruck verwendet wird,   {'ab':100, 'cd':200}, dann würde ich sehen

>>> dummy.ab
100

Ich werde zeigen, wie ein namedtuple vom collections Modul verwenden, um zu erreichen ihn nur:

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

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

Und der Ausgang ist:

>> 1

Erweiterung der Idee von 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)

Ausgabe:

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

Obwohl viele Antworten gegeben werden, konnte ich nicht finden, die ich bin glücklich mit. Ich dachte, meine eigene Lösung aus, die property Arbeit für den dynamischen Fall macht. Die Quelle der ursprüngliche Frage zu beantworten:

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

etwas, das funktioniert für mich ist dies:

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)

Output

a
aa

Dies ist ein wenig anders als das, was OP wollte, aber ich ratterte mein Hirn, bis ich eine Arbeitslösung erhielt, also bin ich hier für den nächsten Mann setzen / gal

brauchte ich eine Art und Weise dynamische Getter und Setter angeben.

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)

Ich weiß, dass meine Felder vor der Zeit so im meine Eigenschaften gehen zu erstellen. HINWEIS: Sie diese pro Instanz nicht tun können, werden diese Eigenschaften in der Klasse vorhanden !!!

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

Lassen Sie uns testen es jetzt ..

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

ist verwirrend es? Ja, leider konnte ich nicht mit sinnvollen realen Welt Beispiele kommen. Auch dies ist nicht für das Licht hearted.

Die einzige Weg, um dynamisch eine Eigenschaft zu befestigen ist, eine neue Klasse und ihre Instanz mit dem neuen Objekt zu erstellen.

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

Ich lief vor kurzem in ein ähnliches Problem, die Lösung, dass ich mit Anwendungen kam __getattr__ und __setattr__ für die Eigenschaften, dass ich es will, zu handhaben alles anderes auf die Originale übergeben wird.

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

Eine Menge der gelieferten Antworten erfordert so viele Zeilen pro Objekt, dh / und / oder - was ich würde eine hässliche oder langweilige Umsetzung betrachten, weil der Eintönigkeit für mehrere Eigenschaften erforderlich, usw. Ich ziehe siedendes Ding niedrig zu halten / Vereinfachung sie, bis sie nicht mehr vereinfacht werden kann oder bis sie dient nicht viel Zweck, dies zu tun.

Kurz gesagt: in abgeschlossenen Arbeiten, wenn ich 2 Zeilen Code wiederholen, ich es in der Regel in eine Funktion einzelne Zeile Helfer konvertieren, und so weiter ... vereinfache ich Mathe oder ungeradee Argumente wie (start_x, start_y, end_x, end_y) bis (x, y, w, h), dh x, y, x + w, y + h (manchmal erfordert min / max oder wenn w / h negativ sind und die Umsetzung mag es nicht, werde ich subtrahieren von x / y und abs w / h. etc ..).

den internen Getter / Setter Aufschalten ist ok Weg zu gehen, aber das Problem ist, dass Sie brauchen, dass für jede Klasse zu tun, oder einen Elternteil der Klasse dieser Basis ... Das ist für mich nicht funktioniert, wie ich würde lieber frei sein, die Kinder / Eltern für die Vererbung zu wählen, untergeordneten Knoten, etc.

Ich habe eine Lösung geschaffen, die die Frage beantwortet, ohne einen Dict Datentyp unter Verwendung der Daten zu liefern, wie ich das finde mühsam zu sein, die Daten einzugeben, etc ...

Meine Lösung erfordert, dass Sie zwei zusätzliche Linien über Ihre Klasse hinzufügen, um eine Basisklasse für die Klasse erstellen Sie per um die Eigenschaften zu, dann 1 Zeile hinzufügen möchten, und Sie haben die Möglichkeit, Rückrufe hinzufügen, um die Daten zu steuern, informieren Sie wenn Datenänderungen, die Daten beschränken, die basierend auf dem Wert und / oder Datentyp, und vieles mehr eingestellt werden können.

Sie haben auch die Möglichkeit zur Verwendung _object.x, _object.x = Wert, _object.GetX (), _object.SetX (Wert) und sie in äquivalenter Weise behandelt werden.

Darüber hinaus sind die Werte, die nur nicht-statischen Daten, die dem Klasseninstanz zugeordnet sind, aber die tatsächliche Eigenschaft wird der Klasse zugeordnet, die Dinge bedeutet, dass Sie nicht zu wiederholen wollen, müssen nicht wiederholt werden. .. Sie können einen Standardwert zuweisen, damit der Getter es nicht jedes Mal braucht, obwohl es eine Option ist die Standard-Standardwert, und es ist eine weitere Option, so dass die Getter liefert den rohen gespeicherten Wert durch zwingende Standarderklärungen (Anmerkung außer Kraft zu setzen : diese Methode bedeutet, dass der Rohwert nur zugewiesen wird, wenn ein Wert zugewiesen wird, sonst ist es keine - wenn der Wert zurückgesetzt wird, dann weist sie keine, etc ..)

Es gibt viele Hilfsfunktionen zu - die erste Eigenschaft, die hinzugefügt wird fügt 2 oder so Helfer auf die Klasse zur Referenzierung der Instanzwerte ... Sie sind ResetAccessors (_key, ..) varargs wiederholt (alle wiederholt werden kann mit der erstgenannte hat args) und SetAccessors (_key, _value) mit der Möglichkeit, mehr zu der Hauptklasse zu aide Effizienz hinzugefügt werden - diejenigen, geplant ist: ein Weg zur Gruppe Accessoren zusammen, so dass, wenn Sie neigen dazu, ein paar zu einer Zeit zurückgesetzt jedes Mal, man kann sie zu einer Gruppe zuweisen und die Gruppe zurückzusetzen, anstatt den Namen Schlüssel jedes Mal zu wiederholen, und vieles mehr.

Die Instanz / raw gespeicherte Wert wird in Klasse gespeichert. , die __CLASS. Referenzen der Accessorklasse, die für die Eigenschaft statische Vars / Werte / Funktionen enthält. _Klasse. ist die Eigenschaft selbst, die während beim Zugriff über die Instanz der Klasse Einstellung / bekommen, etc.

genannt ist

Die Accessor _class .__ verweist auf die Klasse, sondern weil es intern braucht es in der Klasse zugeordnet werden, weshalb ich entschieden __Name = AccessorFunc (...) zu verwenden, um es zuzuweisen, eine einzelne Zeile pro Objekt mit vielen optionalen Argumenten zu verwenden (unter Verwendung von Schlüsseln varargs, weil sie einfacher und effizienter sind, zu identifizieren und zu pflegen) ...

Ich schaffe auch viele Funktionen, wie erwähnt, Informationen, von denen einige Verwendung Accessorfunktion so dass es nicht aufgerufen werden muss (wie es ein wenig unbequem ist im Moment - jetzt müssen Sie verwenden _class .FunctionName (_class_instance, args) -. ich habe um mit dem Stapel / trace die Instanz Bezug zu greifen, den Wert packen die durch HinzufügenFunktionen, die entweder dieses Bit Marathon laufen, oder indem Sie die Zugriffsmethoden auf das Objekt hinzufügen und selbst verwenden (dies nannten sie für die Instanz sind aufzuzeigen und den Zugang zu Selbst behalten, Bezug der AccessorFunc Klasse und andere Informationen innerhalb der Funktion Definitionen).

Es ist nicht ganz fertig, aber es ist ein fantastischer Fuß-hold. Hinweis: Wenn Sie die Eigenschaften erstellen nicht, Sie haben keinen Zugriff verwenden __Name = AccessorFunc (...) zum __ Schlüssel, obwohl ich es in der init-Funktion definieren. Wenn Sie das tun, dann gibt es keine Probleme.

Sie auch: Beachten Sie, dass Name und Schlüssel sind unterschiedlich ... Name ‚formal‘ ist, verwendet in Funktion Name Creation, und der Schlüssel ist für die Datenspeicherung und den Zugang. dh _class.x wo Klein x ist der Schlüssel, wäre der Name in Großbuchstaben X sein, so dass GetX () die Funktion statt getX (), die ein wenig seltsam aussieht. dies ermöglicht self.x zu arbeiten und das Aussehen angemessen, sondern auch GetX () und das Aussehen angemessen ist.

erlauben

Ich habe ein Beispiel-Klasse mit Schlüssel / Namen identisch, und verschiedene einrichten zu zeigen. viele Helfer, um die Daten zur Ausgabe erstellt Funktionen (Hinweis: Nicht alle diese abgeschlossen ist). so können Sie sehen, was los ist,

Die aktuelle Liste der Funktionen mit der Taste: x, Name: X-Ausgänge wie:

Dies ist keineswegs eine umfassende Liste - es gibt ein paar, die es nicht auf diesem zum Zeitpunkt der Buchung gemacht haben ...

_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

Einige der Daten ausgegeben wird:

Dies ist für eine völlig neue Klasse ohne Daten mit Hilfe der Demo-Klasse erstellt zugewiesen anderen als den Namen (so kann es ausgegeben werden), die _foo ist, den Variablennamen habe ich ...

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

Und das ist nach all _foo Eigenschaften (außer den Namen) die folgenden Werte in der gleichen Reihenfolge zuweisen: '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)                                                                                                                                                                                                   |

Beachten Sie, dass aufgrund der eingeschränkten Datentypen oder Wertebeschränkungen wurden einige Daten nicht belegt - dies ist konstruktionsbedingt. Der Setter verbietet schlechte Daten-Typen oder Werte von zugeordnet wird, auch aus als Standardwert zugewiesen wird (es sei denn, Sie das Standardwert Schutzverhalten außer Kraft setzen)

Der Code wurde hier nicht geschrieben, weil ich nicht Raum nach den Beispielen und Erklärungen habe ... auch, weil es ändern wird.

Bitte beachten Sie: im Zeitpunkt dieser Veröffentlichung, die Datei ist etwas chaotisch - das wird sich ändern. Aber, wenn Sie es in Sublime Text laufen und kompilieren Sie sie, oder führen Sie es aus Python, wird es kompilieren und ausspucken eine Tonne von Informationen - der AccessorDB Abschnitt nicht getan (die verwendet wird, um den Druck Getter und GetKeyOutput Helfer zu aktualisieren Funktionen zusammen mit auf eine Instanz Funktion geändert wird, wahrscheinlich eine einzelne Funktion setzen in und umbenannt - Look für sie ..)

Next: Nicht alles, was erforderlich ist, um es zu laufen - viel kommentierten Sachen an der Unterseite für weitere Informationen verwendeten für das Debugging - es kann nicht sein, da, wenn Sie es herunterladen. Wenn ja, sollten Sie uncomment der Lage sein und neu kompilieren, um weitere Informationen zu erhalten.

Ich bin auf der Suche nach einem Work-around zu benötigen MyClassBase: Pass MyClass (MyClassBase.): ... - wenn Sie von einer Lösung wissen - post it

Das einzige, was in der Klasse notwendig sind, die __ Linien - die str ist für das Debuggen wie die init - können sie aus dem Demo-Klasse entfernt werden, aber Sie werden Notwendigkeit zu kommentieren oder einige Zeilen weiter unten (_foo / 2/3) ..

entfernen

Die Schnur, Dict und Util Klassen an der Spitze sind ein Teil meiner Python-Bibliothek - sie nicht vollständig sind. Ich kopierte ein paar Dinge, über die ich von der Bibliothek benötigt, und ich erstellt ein paar neue. Der vollständige Code wird auf die komplette Bibliothek verbinden und es zusammen mit der Bereitstellung von aktualisierten Anrufen umfassen wird und den Code zu entfernen (eigentlich die einzige Code links wird die Demo-Klasse und die print-Anweisungen - das AccessorFunc System wird in die Bibliothek verschoben werden). ..

Ein Teil der Datei:

##
## 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 = { } )

Diese Schönheit macht es unglaublich einfach, neue Klassen zu erstellenmit dynamisch hinzugefügt Eigenschaften mit AccessorFuncs / Rückrufe / Datentyp / Wert Durchsetzung etc.

Für den Moment ist die Verbindung an (dieser Link sollte Änderungen an dem Dokument widerzuspiegeln.): https://www.dropbox.com/s/6gzi44i7dh58v61/dynamic_properties_accessorfuncs_and_more.py?dl=0

Also: Wenn Sie nicht Sublime Text verwenden, ich habe es über Notepad ++ empfehlen, Atom, visuellen Code und andere wegen richtiger Einfädeln Implementierungen es viel zu machen, viel schneller zu bedienen ... Ich arbeite auch an einem IDE -ähnlichen Code Mapping-System für sie - zu sehen: https://bitbucket.org/ ACECOOL / acecoolcodemappingsystem / src / Master / (Add Repo in Package Manager zuerst, dann Plugin installieren - wenn Version 1.0.0 fertig ist, ich es in die Haupt-Plugin-Liste hinzufügen werden ...)

Ich hoffe, dass diese Lösung hilft ... und wie immer:

Nur weil es funktioniert, macht es nicht richtig - Josh 'ACECOOL' Moser

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top