Python-Funktionsattribute – Verwendung und Missbrauch [closed]

Lesezeit: 8 Minuten

Nicht viele sind sich dieser Funktion bewusst, aber die Funktionen (und Methoden) von Python können es haben Attribute. Erblicken:

>>> def foo(x):
...     pass
...     
>>> foo.score = 10
>>> dir(foo)
['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__get__', '__getattribute__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name', 'score']
>>> foo.score
10
>>> foo.score += 1
>>> foo.score
11

Was sind die möglichen Verwendungen und Missbräuche dieser Funktion in Python? Eine gute Verwendung, die mir bekannt ist, ist PLY‘s Verwendung des Dokumentstrings, um eine Syntaxregel mit einer Methode zu verknüpfen. Aber was ist mit benutzerdefinierten Attributen? Gibt es gute Gründe, sie zu verwenden?

  • Kasse PEP 232.

    – Benutzer140352

    17. Juli 2009 um 18:36 Uhr

  • Ist das sehr überraschend? Im Allgemeinen unterstützen Python-Objekte Ad-hoc-Attribute. Manche natürlich nicht, besonders solche mit eingebautem Typ. Für mich scheinen diejenigen, die dies nicht unterstützen, die Ausnahmen zu sein, nicht die Regel.

    – Allourcode

    27. November 2012 um 7:01 Uhr


  • Eine Anwendung in Django: Passen Sie die Admin-Änderungsliste an

    – Grijesh Chauhan

    15. November 2013 um 13:27 Uhr

  • @GrijeshChauhan Ich bin zu dieser Frage gekommen, nachdem ich diese Dokumente gesehen habe!

    – Alexander Suraphel

    27. Dezember 2015 um 14:03 Uhr

  • Schade, dass dies geschlossen ist, ich wollte hinzufügen, dass Sie alle benutzerdefinierten Ausnahmen anhängen können, die die Funktion auslösen könnte, um einen einfachen Zugriff zu ermöglichen, wenn Sie sie im aufrufenden Code abfangen. Ich würde ein anschauliches Beispiel geben, aber das geht am besten in einer Antwort.

    – Will Hardy

    14. März 2017 um 15:59 Uhr


Normalerweise verwende ich Funktionsattribute als Speicher für Anmerkungen. Angenommen, ich möchte im Stil von C # schreiben (wodurch angegeben wird, dass eine bestimmte Methode Teil der Webdienstschnittstelle sein soll).

class Foo(WebService):
    @webmethod
    def bar(self, arg1, arg2):
         ...

dann kann ich es definieren

def webmethod(func):
    func.is_webmethod = True
    return func

Wenn dann ein Webservice-Aufruf eintrifft, schaue ich die Methode nach, überprüfe, ob die zugrunde liegende Funktion das is_webmethod-Attribut hat (der tatsächliche Wert ist irrelevant) und lehne den Dienst ab, wenn die Methode nicht vorhanden ist oder nicht über das Web aufgerufen werden soll.

  • Glauben Sie, dass das Nachteile hat? zB Was, wenn zwei Bibliotheken versuchen, dasselbe Ad-hoc-Attribut zu schreiben?

    – Allourcode

    27. November 2012 um 6:58 Uhr

  • Ich dachte daran, genau das zu tun. Dann habe ich mich selbst gestoppt. “Ist das eine schlechte Idee?” Ich fragte mich. Dann wanderte ich zu SO hinüber. Nach einigem herumfummeln habe ich diese Frage/Antwort gefunden. Ich bin mir immer noch nicht sicher, ob das eine gute Idee ist.

    – Allourcode

    27. November 2012 um 7:05 Uhr

  • Dies ist definitiv die legitimste Verwendung von Funktionsattributen aller Antworten (Stand November 2012). Die meisten (wenn nicht alle) anderen Antworten verwenden Funktionsattribute als Ersatz für globale Variablen; Sie werden jedoch den globalen Zustand NICHT los, was genau das Problem mit globalen Variablen ist. Dies ist anders, denn sobald der Wert festgelegt ist, ändert er sich nicht; es ist konstant. Eine schöne Folge davon ist, dass Sie nicht auf Synchronisationsprobleme stoßen, die globalen Variablen innewohnen. Ja, Sie können Ihre eigene Synchronisierung bereitstellen, aber das ist der Punkt: Sie ist nicht automatisch sicher.

    – Allourcode

    27. November 2012 um 7:17 Uhr


  • In der Tat, sage ich, solange das Attribut das Verhalten der betreffenden Funktion nicht ändert, ist es gut. Vergleichen mit .__doc__

    – Dima Tisnek

    12. Dezember 2012 um 12:34 Uhr

  • Dieser Ansatz kann auch verwendet werden, um eine Ausgabebeschreibung an die dekorierte Funktion anzuhängen, die in Python 2.* fehlt.

    – Juh_

    15. Oktober 2013 um 13:37 Uhr

Python Funktionsattribute Verwendung und Missbrauch closed
mipadi

Ich habe sie als statische Variablen für eine Funktion verwendet. Zum Beispiel bei folgendem C-Code:

int fn(int i)
{
    static f = 1;
    f += i;
    return f;
}

Ich kann die Funktion ähnlich in Python implementieren:

def fn(i):
    fn.f += i
    return fn.f
fn.f = 1

Dies würde definitiv in das Ende des “Missbrauchs”-Spektrums fallen.

  • Interessant. Gibt es andere Möglichkeiten, statische Variablen in Python zu implementieren?

    – Eli Bendersky

    3. Dezember 2008 um 20:39 Uhr

  • -1, würde dies mit einem Generator in Python implementiert werden.

    Benutzer3850

    6. Dezember 2008 um 20:45 Uhr

  • Das ist ein ziemlich schlechter Grund, diese Antwort abzulehnen, die eine Analogie zwischen C und Python demonstriert und nicht die bestmögliche Art und Weise zum Schreiben dieser bestimmten Funktion befürwortet.

    – Robert Rossney

    6. Oktober 2009 um 7:19 Uhr

  • @RobertRossney Aber wenn Generatoren der richtige Weg sind, dann ist dies eine schlechte Verwendung von Funktionsattributen. Wenn ja, dann ist das ein Missbrauch. Ich bin mir jedoch nicht sicher, ob ich Missbrauch positiv bewerten soll, da die Frage auch danach fragt: P

    – Allourcode

    27. November 2012 um 7:27 Uhr

  • @hobs Ich sehe nicht, inwiefern es sich um einen Missbrauch gemäß PEP 232 handelt. PEP 232 bietet einige Anwendungsfälle für den Mechanismus, scheint jedoch nicht zu empfehlen, die Verwendung auf diese Anwendungsfälle zu beschränken.

    – Jewgeni Sergejew

    14. Oktober 2014 um 4:30 Uhr

Sie können Objekte auf die JavaScript-Weise erstellen … Es macht keinen Sinn, aber es funktioniert 😉

>>> def FakeObject():
...   def test():
...     print "foo"
...   FakeObject.test = test
...   return FakeObject
>>> x = FakeObject()
>>> x.test()
foo

  • +1 Ein schönes Beispiel für einen Missbrauch dieser Funktion, was eines der Dinge ist, nach denen in der Frage gefragt wurde.

    – Michael Dunn

    26. Juli 2010 um 13:22 Uhr

  • Wie unterscheidet sich das von mipadis Antwort? Scheint dasselbe zu sein, außer dass der Attributwert anstelle eines int eine Funktion ist.

    – Allourcode

    27. November 2012 um 7:04 Uhr

  • ist def test() wirklich nötig?

    – Keerthana Prabhakaran

    9. März 2018 um 5:13 Uhr

Ich benutze sie sparsam, aber sie können ziemlich praktisch sein:

def log(msg):
   log.logfile.write(msg)

Jetzt kann ich verwenden log in meinem gesamten Modul und leiten Sie die Ausgabe einfach per Einstellung um log.logfile. Es gibt viele, viele andere Möglichkeiten, dies zu erreichen, aber diese ist leicht und schmutzig einfach. Und obwohl es beim ersten Mal komisch roch, bin ich zu dem Schluss gekommen, dass es besser riecht als ein Global logfile Variable.

Funktionsattribute können verwendet werden, um leichte Closures zu schreiben, die Code und zugehörige Daten zusammenschließen:

#!/usr/bin/env python

SW_DELTA = 0
SW_MARK  = 1
SW_BASE  = 2

def stopwatch():
   import time

   def _sw( action = SW_DELTA ):

      if action == SW_DELTA:
         return time.time() - _sw._time

      elif action == SW_MARK:
         _sw._time = time.time()
         return _sw._time

      elif action == SW_BASE:
         return _sw._time

      else:
         raise NotImplementedError

   _sw._time = time.time() # time of creation

   return _sw

# test code
sw=stopwatch()
sw2=stopwatch()
import os
os.system("sleep 1")
print sw() # defaults to "SW_DELTA"
sw( SW_MARK )
os.system("sleep 2")
print sw()
print sw2()

1.00934004784

2.00644397736

3.01593494415

  • Warum Push-Funktionen, wenn wir Klassen zur Hand haben? Und vergessen wir nicht, dass Klassen eine Funktion emulieren können.

    – muhuk

    7. Dezember 2008 um 17:47 Uhr

  • Auch time.sleep(1) ist besser als os.system('sleep 1')

    – Boris Gorelik

    16. August 2010 um 5:53 Uhr


  • @bgbg Stimmt, obwohl es in diesem Beispiel nicht ums Schlafen geht.

    – Allourcode

    27. November 2012 um 7:12 Uhr

  • Dies ist definitiv ein Missbrauch; die Verwendung von Funktionen hier ist völlig unentgeltlich. muhuk hat genau recht: Klassen sind die bessere Lösung.

    – Allourcode

    27. November 2012 um 7:14 Uhr

  • Ich würde auch fragen: “Was ist der Vorteil gegenüber einer Klasse?” um dem Nachteil entgegenzuwirken, dass dies für viele Python-Programmierer nicht so offensichtlich ist.

    – cjs

    12. Dezember 2018 um 0:30 Uhr

1647536770 708 Python Funktionsattribute Verwendung und Missbrauch closed
DiogoNeves

Ich habe diesen Hilfs-Decorator erstellt, um Funktionsattribute einfach festzulegen:

def with_attrs(**func_attrs):
    """Set attributes in the decorated function, at definition time.
    Only accepts keyword arguments.
    E.g.:
        @with_attrs(counter=0, something='boing')
        def count_it():
            count_it.counter += 1
        print count_it.counter
        print count_it.something
        # Out:
        # >>> 0
        # >>> 'boing'
    """
    def attr_decorator(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            return fn(*args, **kwargs)

        for attr, value in func_attrs.iteritems():
            setattr(wrapper, attr, value)

        return wrapper

    return attr_decorator

Ein Anwendungsfall besteht darin, eine Sammlung von Fabriken zu erstellen und den Datentyp abzufragen, den sie auf Funktionsmetaebene erstellen können.
Zum Beispiel (sehr dumm):

@with_attrs(datatype=list)
def factory1():
    return [1, 2, 3]

@with_attrs(datatype=SomeClass)
def factory2():
    return SomeClass()

factories = [factory1, factory2]

def create(datatype):
    for f in factories:
        if f.datatype == datatype:
            return f()
    return None

  • Warum Push-Funktionen, wenn wir Klassen zur Hand haben? Und vergessen wir nicht, dass Klassen eine Funktion emulieren können.

    – muhuk

    7. Dezember 2008 um 17:47 Uhr

  • Auch time.sleep(1) ist besser als os.system('sleep 1')

    – Boris Gorelik

    16. August 2010 um 5:53 Uhr


  • @bgbg Stimmt, obwohl es in diesem Beispiel nicht ums Schlafen geht.

    – Allourcode

    27. November 2012 um 7:12 Uhr

  • Dies ist definitiv ein Missbrauch; die Verwendung von Funktionen hier ist völlig unentgeltlich. muhuk hat genau recht: Klassen sind die bessere Lösung.

    – Allourcode

    27. November 2012 um 7:14 Uhr

  • Ich würde auch fragen: “Was ist der Vorteil gegenüber einer Klasse?” um dem Nachteil entgegenzuwirken, dass dies für viele Python-Programmierer nicht so offensichtlich ist.

    – cjs

    12. Dezember 2018 um 0:30 Uhr

Manchmal verwende ich ein Attribut einer Funktion, um bereits berechnete Werte zwischenzuspeichern. Sie können auch einen generischen Decorator haben, der diesen Ansatz verallgemeinert. Beachten Sie Parallelitätsprobleme und Nebeneffekte solcher Funktionen!

  • Ich mag diese Idee! Ein häufigerer Trick zum Zwischenspeichern berechneter Werte besteht darin, ein Diktat als Standardwert eines Attributs zu verwenden, das der Aufrufer niemals bereitstellen soll – da Python dies nur einmal beim Definieren der Funktion auswertet, können Sie Daten dort speichern und festhalten um herum. Während die Verwendung von Funktionsattributen weniger offensichtlich ist, fühlt es sich für mich deutlich weniger hacky an.

    – Soren Björnstad

    9. August 2019 um 23:44 Uhr

1005090cookie-checkPython-Funktionsattribute – Verwendung und Missbrauch [closed]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy