Seite 1 von 1
@autoproperty
Verfasst: Sonntag 3. Juni 2007, 23:17
von mitsuhiko
Also das ist eher proof-of-concept als für den wirklichen Einsatz gedacht. Was macht es?
Code: Alles auswählen
class Foo(object):
def __init__(self, initial):
self.foo = initial
def _get_foo(self):
return self._foo
def _set_foo(self, value):
self._foo = value
foo = property(_get_foo, _set_foo, 'The docstring')
del _get_foo, _set_foo
wird zu
Code: Alles auswählen
class Foo(object):
def __init__(self, initial):
self.foo = initial
@autoproperty
def foo():
'''The docstring'''
def fget(self):
return self._foo
def fset(self, value):
self._foo = value
Code ist hier:
http://lucumr.pocoo.org/trac/repos/autoproperty.py
Anmerkungen erwünscht
Verfasst: Sonntag 3. Juni 2007, 23:33
von veers
Hm, ich Frage gerade ob das Sinn macht. Daher ob es wirklich einfacher zu lesen/verstehen? Wenn ich mir dann noch ansehe wie hacky die Implementierung ist muss ich sagen dass ich die explizite Definition bevorzuge.
Es ist aber ein schönes Beispiel dafür wie weit man in Python gehen kann.
Re: @autoproperty
Verfasst: Sonntag 3. Juni 2007, 23:37
von gerold
blackbird hat geschrieben:Anmerkungen erwünscht
Hallo blackbird!
Normalerweise vermeide ich Dekoratoren wie die Pest, aber das scheint kein so schlechter Verwendungszweck dafür zu sein. Finde ich wirklich gut. Das kommt den Properties unter Visual Basic .NET sehr nahe. Besonders gefällt mir, dass man nicht zwei oder drei mal einen Docstring schreiben muss. Wie es derzeit ist: einer für den Getter, einer für den Setter und dann noch für das Property.
Nur der Name "@autoproperty" kommt mir noch komisch vor. Ich hätte vielleicht "@propertydef" oder so was ähnliches genommen. Das beginnt mit "property" und zeigt schon nach vier Zeichen auf, für was der Name steht.
Die "auto"-Namen könnte man beim schnellen Durchlesen/Scannen leicht mit Begriffen wie "@autocommit", "@autoexpand", usw. verwechseln.
Wäre schön, wenn so etwas direkt ins Python integriert wäre.
mfg
Gerold
Verfasst: Montag 4. Juni 2007, 00:09
von BlackJack
Ohne viel Magie und nicht viel länger:
Code: Alles auswählen
class A(object):
def __init__(self, spam):
self._spam = spam
@apply
def spam():
def fget(self):
return self._spam
def fset(self, value):
self._spam = value
doc = 'some docs'
return property(**locals())
Wenn das `apply()` nicht gefällt, kann man ja irgendwo vorher ``autoproperty = apply`` schreiben.
Verfasst: Montag 4. Juni 2007, 08:03
von gerold
BlackJack hat geschrieben:Ohne viel Magie und nicht viel länger
Hallo BlackJack!
Das ist auch nicht schlecht. Der Wermutstropfen ist, dass "apply" seit Version 2.3 "deprecated" ist. Es hat wohl niemand daran gedacht, dass man damit so ein Konstrukt zusammen bringt. Gibt es alternativen zu "apply"?
mfg
Gerold
Verfasst: Montag 4. Juni 2007, 08:46
von BlackJack
Man kann es sich selber schreiben:
Code: Alles auswählen
def apply_(func, *args, **kwargs):
return func(*args, **kwargs)
Und dabei dann vielleicht auch gleich einen schöneren Namen geben, der eher nach `property()` klingt.
Verfasst: Montag 4. Juni 2007, 08:57
von mitsuhiko
Code: Alles auswählen
def autoproperty(f):
return property(doc=f.__doc__, **f())
@autoproperty
def foo():
"""foo doc"""
def fget(self): return 42
def fset(self, value): pass
return locals()
Das geht natürlich auch. Mein Codebeispiel im ersten Post ist auch, wie gesagt, proof-of-concept und nicht ernsthafter Code
Re: @autoproperty
Verfasst: Montag 4. Juni 2007, 13:36
von Y0Gi
gerold hat geschrieben:Besonders gefällt mir, dass man nicht zwei oder drei mal einen Docstring schreiben muss. Wie es derzeit ist: einer für den Getter, einer für den Setter und dann noch für das Property.
Muss man das? Den Docstring bekommt doch `property` als letztes Argument.
Re: @autoproperty
Verfasst: Montag 4. Juni 2007, 14:17
von gerold
Y0Gi hat geschrieben:Muss man das? Den Docstring bekommt doch `property` als letztes Argument.
Hallo Y0Gi!
Nein, das muss man nicht. Aber es kommt schon mal vor, dass sich Getter, Setter und Property-Definition auf mehrere Seiten verteilen. Der Docstring ist in erster Linie **für mich**. Ich möchte einen Code von oben nach unten durchscannen können und anhand der Docstrings oder Kommentare wissen, was sich so tut. Wenn aber der zugehörige Docstring erst eine oder zwei Seiten weiter unten auftaucht, dann bringt er mir nichts mehr.
Der Docstrings in der Property-Definition ist dann nur noch für den Benutzer des Properties interessant, aber nicht mehr für mich. Deshalb haben meine Getter und Setter auch einen Docstring. Auch deshalb, weil manche Getter und Setter (intern) auch ab und zu noch als reine Funktionen angesprochen werden. Z.B. um Standardwerte einer Funktion anzusprechen, auf die man bei der Verwendung von "property" nicht zu kommt.
lg
Gerold
Verfasst: Dienstag 5. Juni 2007, 16:10
von EyDu
[quote="EyDu"]Also wenn sich hier nicht direkt eine Metaklasse anbietet. Sorry wegen des unkommentierten Codes, aber ist gerade knapp mit der Zeit...
Code: Alles auswählen
class PropMeta(type):
def __new__(mcls, name, bases, clsdict):
for name, value in clsdict.iteritems():
try:
name = value._property_name
except AttributeError:
pass
else:
clsdict[name] = property(**value())
return super(PropMeta, mcls).__new__(mcls, name, bases, clsdict)
def propdec(function):
function._property_name = function.__name__
return function
class Spam(object):
__metaclass__ = PropMeta
def __init__(self, value):
self.value = value
print self.aproperty
self.aproperty = 4
print self.aproperty
@propdec
def aproperty():
def fget(self):
return self.value**2
def fset(self, value):
self.value = value
doc = "some value"
return locals()
Der Dekorator ließe sich noch locker um einen property-Namen erweitern, aber da hatte ich jetzt keine Lust zu.
Edit:
Das mein Beispiel funktioniert sieht man ja, aber ich frage mich, ob es sich dafür wirklich lohnt, jedes mal das entsprechende Modul zu importieren, die Metaklasse zu setzen und dann noch die Konflikte mit eventuell anderen benötigten Metaklassen zu lösen.
Verfasst: Dienstag 5. Juni 2007, 17:34
von birkenfeld
Du musst ja nicht jedesmal die Metaklasse importieren und setzen.
Erstelle einfach eine "Basis"-Klasse, z.B.
und lass dann alle deine Objekte von dieser erben.