@autoproperty

Code-Stücke können hier veröffentlicht werden.
Antworten
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

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 :D
TUFKAB – the user formerly known as blackbird
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

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.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

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
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
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. :-)
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

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
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
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.
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

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 :-)
TUFKAB – the user formerly known as blackbird
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

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.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

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
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

[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.
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Du musst ja nicht jedesmal die Metaklasse importieren und setzen.

Erstelle einfach eine "Basis"-Klasse, z.B.

Code: Alles auswählen

class autoproperty(object):
     __metaclass__ = PropMeta
und lass dann alle deine Objekte von dieser erben.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Antworten