|
|
|
Hallo,
wir mchten in einer Klasse eine Reihe von Attributen konsistent speichern; d.h. es gibt Beschrnkungen fr die verschiedenen Attribute. Die Idee ist, das durch Properties zu machen: Class Cfg: def __init__(self); self._myprop = 1.23 [...] @property def myprop(self) return self._myprop @myprop.setter def myprop(self, val): if val > self._maxprop: # als Beispiel raise ValueError() self._myprop = val Das Unschne daran ist, dass die Initialisierung der Property im __init__ und damit physisch weit entfernt vom Rest erfolgt. Das ist, wenn man viele (>>20) Attribute hat, nicht mehr bersichtlich. Wie bringt man die enger zusammen? Ein @myprop.init gibt es ja offensichtlich nicht und kann man auch nicht so ohne weiteres anlegen, oder? Oder was wre ein sinnvolles Pattern hier? Schne Gre Ole |
|
|
|
Hallo Ole,
leider habe ich selbst auch noch keine Erfahrung mit der Bibliothek gemacht und ich bin mir auch nicht sicher, ob sie deinen Fall abdeckt, aber kennst du pydantic? Falls deine Klasse nur ein Datenkontainer ist, knnte ich mir gut vorstellen, dass die Bibliothek das macht, was du willst, falls der Aspekt nur ein kleiner Aspekt ist, ist pydantic vllt. doch nichts fr dich. Viele Gre, Julian On 26/05/2020 17:44, ?l? ?tr???h?r wrote: [..] |
|
|
Am 26.05.20 um 17:44 schrieb ?l? ?tr???h?r:
> Wie bringt man die enger zusammen? Ein @myprop.init gibt es ja > offensichtlich nicht und kann man auch nicht so ohne weiteres anlegen, > oder? Oder was wre ein sinnvolles Pattern hier? Du knntest eine eigene "Property" class implementieren, die einen weiteren Docorator "initialisiere" hat. Allerdings bleibt immer noch das Problem, dass Du diese Funktion in __init__ irgendwie aufrufen musst. Du msstest in __init__ hergehen und alle properies der Klasse (self.__class__) finden und deren initalizer aufrufen. Ich habe die genau Funktionsweise von Properties nicht im Kopf, aber irgendwie sollte das gehen. Vielleicht schaust Du man in den PEP zu properties, dort gibt es sicher Details. Allerdings gibt es mindestens zwei Haken: 1. Wenn die initializer in eine bestimmten Reihenfolge aufgerufen werden mssen, dann musst Du sie doch wieder benennen. Denn sonst bekommstt Du keine Reihenfolge. 2. Wie ruft man die iniatlizer berhaupt auf? |
|
|
Am 26.05.2020 um 17:44 schrieb ?l? ?tr???h?r:
> Hallo, > wir mchten in einer Klasse eine Reihe von Attributen konsistent > speichern; d.h. es gibt Beschrnkungen fr die verschiedenen Attribute. > Die Idee ist, das durch Properties zu machen: Also die Properties verwirren mich hier. Das Beispiel an einer Stelle auch... [siehe etwas weiter unten] Darum eine andere Frage: Gelten die Beschrnkungen eines Attributs fr alle Instanzen der Klasse? Falls Ja, die Beschrnkungen als Klassenattribute einfach hinschreiben? class Cfg(object): def __init__(self): self._myprop = 1.23 # hier wirklich .myprop ? @property def myprop(self): return self._myprop _maxprop = 1.24 @myprop.setter def myprop(self, val): if val > self._maxprop: # als Beispiel raise ValueError() self._myprop = val if __name__ == '__main__': versuch = Cfg() print(versuch.myprop) # gibt 1.23 aus versuch.myprop = 1 print(versuch.myprop) # gibt 1 aus versuch.myprop = 1.25 # wirft ValueError print(versuch.myprop) Gre, Andreas [..] |
|
|
Hallo allerseits, hallo Ole,
evtl. knnte man das auch mit dem descriptor-protokoll lsen, so ha ich das bei einem sehr aufwendigen Projekt gemacht. Sehr gutes Tutorial (englisch): update vom selben Autor: Dann kannst du sowas machen: class Foo: myprop = Cfg(init=1.23) Gre Gregor Am 26.05.20 um 17:44 schrieb ?l? ?tr???h?r: [..] |
|
|
Am Mi Mai 27 2020, 10:27:31 schrieb Hartmut Goebel:
[..] > 1. Wenn die initializer in eine bestimmten Reihenfolge aufgerufen werden > mssen, dann musst Du sie doch wieder benennen. Denn sonst bekommstt Du > keine Reihenfolge. Die Reihenfolge kann durch die Positionierung in der Klasse bestimmt werden: >>> class A: .... foo = 1 .... bar = 2 .... >>> class B: .... bar = 2 .... foo = 1 .... >>> vars(A).keys() dict_keys(['__module__', 'foo', 'bar', '__dict__', '__weakref__', '__doc__']) >>> vars(B).keys() dict_keys(['__module__', 'bar', 'foo', '__dict__', '__weakref__', '__doc__']) > 2. Wie ruft man die iniatlizer berhaupt auf? Da bentigt man die Mithilfe der Eigentmer(meta)klasse. Nachfolgend eine einfache Implementierung, die die Properties anhand ihrer Klasse identifiziert: $ cat init_property.py missing = object() class myproperty(property): finit = None default = missing def initializer(self, f): self.finit = f return self def init(self, owner): if self.finit is not None: self.finit(owner) elif self.default is not missing: # eventuell "_" + self.name, um den Aufruf des Setters # zu vermeiden setattr(owner, self.name, self.default) def __set_name__(self, owner, name): self.name = name class Cfg: @classmethod def myproperties(cls): return [p for p in vars(cls).values() if isinstance(p, myproperty)] def __init__(self): for p in self.myproperties(): p.init(self) @myproperty def foo(self): return self._foo @foo.setter def foo(self, value): assert 0 <= value < 100 self._foo = value @foo.initializer def foo(self): self._foo = 42 @myproperty def bar(self): return self._bar @bar.setter def bar(self, value): assert isinstance(value, int) self._bar = value bar.default = 123 c = Cfg() print(c.foo) # 42, im Initializer gesetzt print(c.bar) # 123, default-Attribut c.foo = 24 # OK c.bar = "spam" # Exception $ python3.8 init_property.py 42 123 Traceback (most recent call last): File "init_property.py", line 59, in <module> c.bar = "spam" File "init_property.py", line 50, in bar assert isinstance(value, int) AssertionError $ Wer's gerne eleganter htte, knnte sich ja mal den Quellcodeder dataclasses zu Gemte fhren... |
|
|
Am 27.05.20 um 17:13 schrieb Peter Otten:
> Die Reihenfolge kann durch die Positionierung in der Klasse bestimmt werden: Knnte man machen, allerdings wrde ich mich nicht darauf verlassen, dass die Reihenfolge in `vars(A).keys()` immer stimmt. Kannst Du mit eine Doku dazu zeigen, ich habe nichts gefunden. Allerdings hat mich Deine Mail noch auf einen ganz anderen Ansatz gebracht: class A: _myprop = 1.23 @property def myprop(self): return self._myprop @myprop.setter def myprop(self, value): if value < 2.5: self._myprop = value a = A() print(a.myprop) a.myprop = 2.1 print(a.myprop) |
|
|
Am So Mai 31 2020, 10:13:43 schrieb Hartmut Goebel:
> Am 27.05.20 um 17:13 schrieb Peter Otten: > > Die Reihenfolge kann durch die Positionierung in der Klasse bestimmt werden: > Knnte man machen, allerdings wrde ich mich nicht darauf verlassen, > dass die Reihenfolge in `vars(A).keys()` immer stimmt. Kannst Du mit > eine Doku dazu zeigen, ich habe nichts gefunden. Was Knackiges kann ich auch nicht vorweisen, nur mit dem Verweis auf die PEP 520 ? Preserving Class Attribute Definition Order bei deren Enstehung wohl noch nicht bekannt war, dass `dict`s die insertion order erhalten. [..] > print(a.myprop) > a.myprop = 2.1 > print(a.myprop) Das hat den Vorteil, dass man sich nur auf Standard-Konstrukte verlsst. Fr mutable defaults muss man das allerdings modifizieren. |
|