Dekoratoren in der Python-Standardbibliothek (@speziell veraltet)
Lesezeit: 10 Minuten
Stefano Borini
Ich muss Routinen als veraltet markieren, aber anscheinend gibt es keinen Standard-Bibliotheksdekorator für veraltete Routinen. Mir sind Rezepte dafür und das Warnmodul bekannt, aber meine Frage ist: Warum gibt es für diese (häufige) Aufgabe keinen Standard-Bibliotheksdekorator?
Zusätzliche Frage: Gibt es in der Standardbibliothek überhaupt Standarddekorateure?
Ich verstehe die Möglichkeiten, dies zu tun, bin aber hierher gekommen, um zu erfahren, warum es nicht in der Standardbibliothek enthalten ist (wie ich annehme, dass dies beim OP der Fall ist) und sehe keine gute Antwort auf die eigentliche Frage
– SwimBikeRun
1. April 2019 um 14:57 Uhr
Warum kommt es so oft vor, dass auf Fragen dutzende Antworten gegeben werden, die nicht einmal versuchen, die Frage zu beantworten, und Dinge wie „Ich kenne Rezepte“ aktiv ignoriert? Es ist wahnsinnig!
– Catskul
2. Mai 2019 um 16:46
@Catskul wegen gefälschter Internetpunkte.
– Stefano Borini
2. Mai 2019 um 19:07 Uhr
@Catskul Nicht Warum Fragen sind überhaupt veraltet oder sollten sie nicht auf SO gestellt werden? Wie wir so oft sehen, neigen sie dazu, keine Antworten zu produzieren. Ich hätte diesen Kommentar nicht hinterlassen, wenn ich nicht alle deine gesehen hätte antwortet nicht Dekorateure 😉
– Wolf
27. Mai 2021 um 12:21 Uhr
Patrizio Bertoni
Hier ist ein Auszug, der von den von Leandro zitierten abgeändert wurde:
import warnings
import functools
def deprecated(func):
"""This is a decorator which can be used to mark functions
as deprecated. It will result in a warning being emitted
when the function is used."""
@functools.wraps(func)
def new_func(*args, **kwargs):
warnings.simplefilter('always', DeprecationWarning) # turn off filter
warnings.warn("Call to deprecated function {}.".format(func.__name__),
category=DeprecationWarning,
stacklevel=2)
warnings.simplefilter('default', DeprecationWarning) # reset filter
return func(*args, **kwargs)
return new_func
# Examples
@deprecated
def some_old_function(x, y):
return x + y
class SomeClass:
@deprecated
def some_old_method(self, x, y):
return x + y
Denn in einigen Interpretern kann die erste verfügbare Lösung (ohne Filterbehandlung) zu einer Unterdrückung der Warnung führen.
Warum nicht verwenden? functools.wraps anstatt den Namen und das Dokument so festzulegen?
– Maximilian
6. August 2015 um 14:40 Uhr
@Maximilian: Bearbeitet, um das hinzuzufügen, um zu verhindern, dass zukünftige Kopierer dieses Codes es auch falsch machen
– Erik
28. Juni 2016 um 3:59
Ich mag keinen Nebeneffekt (Ein-/Ausschalten des Filters). Es ist nicht die Aufgabe des Dekorateurs, darüber zu entscheiden.
– Kentzo
18. April 2017 um 17:48
beantwortet nicht die eigentliche Frage.
– Catskul
2. Mai 2019 um 16:41 Uhr
Ich stimme @Kentzo voll und ganz zu – das Deaktivieren von Filtern und das anschließende Zurücksetzen auf die Standardeinstellungen wird einigen Entwicklern unglaubliche Kopfschmerzen bereiten
– Aaron V
7. Dezember 2020 um 21:34
Laurent LAPORTE
Hier ist eine andere Lösung:
Dieser Dekorateur (eigentlich eine Dekorateurfabrik) ermöglicht es Ihnen, etwas zu geben Grund Nachricht. Es ist auch nützlicher, dem Entwickler durch die Angabe der Quelle bei der Diagnose des Problems zu helfen Dateinamen Und Zeilennummer.
BEARBEITEN: Dieser Code verwendet die Empfehlung von Zero: Ersetzen warnings.warn_explicit Zeile nach warnings.warn(msg, category=DeprecationWarning, stacklevel=2), wodurch die Funktionsaufrufseite und nicht die Funktionsdefinitionsseite gedruckt wird. Es erleichtert das Debuggen.
BEARBEITEN2: Diese Version ermöglicht es dem Entwickler, eine optionale „Grund“-Nachricht anzugeben.
import functools
import inspect
import warnings
string_types = (type(b''), type(u''))
def deprecated(reason):
"""
This is a decorator which can be used to mark functions
as deprecated. It will result in a warning being emitted
when the function is used.
"""
if isinstance(reason, string_types):
# The @deprecated is used with a 'reason'.
#
# .. code-block:: python
#
# @deprecated("please, use another function")
# def old_function(x, y):
# pass
def decorator(func1):
if inspect.isclass(func1):
fmt1 = "Call to deprecated class {name} ({reason})."
else:
fmt1 = "Call to deprecated function {name} ({reason})."
@functools.wraps(func1)
def new_func1(*args, **kwargs):
warnings.simplefilter('always', DeprecationWarning)
warnings.warn(
fmt1.format(name=func1.__name__, reason=reason),
category=DeprecationWarning,
stacklevel=2
)
warnings.simplefilter('default', DeprecationWarning)
return func1(*args, **kwargs)
return new_func1
return decorator
elif inspect.isclass(reason) or inspect.isfunction(reason):
# The @deprecated is used without any 'reason'.
#
# .. code-block:: python
#
# @deprecated
# def old_function(x, y):
# pass
func2 = reason
if inspect.isclass(func2):
fmt2 = "Call to deprecated class {name}."
else:
fmt2 = "Call to deprecated function {name}."
@functools.wraps(func2)
def new_func2(*args, **kwargs):
warnings.simplefilter('always', DeprecationWarning)
warnings.warn(
fmt2.format(name=func2.__name__),
category=DeprecationWarning,
stacklevel=2
)
warnings.simplefilter('default', DeprecationWarning)
return func2(*args, **kwargs)
return new_func2
else:
raise TypeError(repr(type(reason)))
Sie können diesen Dekorateur für verwenden Funktionen, Methoden Und Klassen.
Hier ist ein einfaches Beispiel:
@deprecated("use another function")
def some_old_function(x, y):
return x + y
class SomeClass(object):
@deprecated("use another method")
def some_old_method(self, x, y):
return x + y
@deprecated("use another class")
class SomeOldClass(object):
pass
some_old_function(5, 3)
SomeClass().some_old_method(8, 9)
SomeOldClass()
Du wirst kriegen:
deprecated_example.py:59: DeprecationWarning: Call to deprecated function or method some_old_function (use another function).
some_old_function(5, 3)
deprecated_example.py:60: DeprecationWarning: Call to deprecated function or method some_old_method (use another method).
SomeClass().some_old_method(8, 9)
deprecated_example.py:61: DeprecationWarning: Call to deprecated class SomeOldClass (use another class).
SomeOldClass()
EDIT3: Dieser Dekorator ist jetzt Teil der veralteten Bibliothek:
Funktioniert, nun ja – ich bevorzuge es, das zu ersetzen warn_explicit Linie mit warnings.warn(msg, category=DeprecationWarning, stacklevel=2) Dadurch wird die Funktionsaufrufseite und nicht die Funktionsdefinitionsseite gedruckt. Es erleichtert das Debuggen.
@LaurentLAPORTE Ich weiß. CC-BY-SO erlaubt keine Nutzung innerhalb der GPLv3 (aufgrund des Share-Alike-Bits), weshalb ich Sie frage, ob Sie bereit wären, diesen Code speziell zusätzlich unter einer GPL-kompatiblen Lizenz zu veröffentlichen. Wenn nicht, ist das in Ordnung und ich werde Ihren Code nicht verwenden.
– Gerrit
9. Juli 2017 um 14:27
beantwortet nicht die eigentliche Frage.
– Catskul
2. Mai 2019 um 16:42 Uhr
@DannyVarod Ich weiß, aber für Code ist CC-BY-SA noch restriktiver als GPL. Als ich die Frage stellte, arbeitete ich an einer GPL-Bibliothek. GPL-Bibliotheken können GPL-Code oder freizügigeren Code verwenden, GPL-Bibliotheken können dies jedoch nicht Da ich CC-BY-SA-Code verwende, konnte ich dieses Code-Snippet nicht verwenden. (Und CC-BY-SA wurde sowieso nie für Code verwendet; SO würde es gut tun, Codeschnipsel in Benutzerbeiträgen unter etwas Freizügigerem zu lizenzieren, denn so wie es jetzt ist, können die meisten Benutzer Codeschnipsel, die sie auf SO finden, nicht verwenden.)
– Gerrit
9. Mai 2021 um 20:23
Stevoisiak
Wie Myon vorgeschlagen hat, können Sie das installieren deprecation Paket dafür.
Der deprecation Die Bibliothek bietet eine deprecated Dekorateur und a fail_if_not_removed Dekorateur für Ihre Tests.
Installation
pip install deprecation
Beispielverwendung
import deprecation
@deprecation.deprecated(deprecated_in="1.0", removed_in="2.0",
current_version=__version__,
details="Use the bar function instead")
def foo():
"""Do some stuff"""
return 1
Ich schätze, der Grund liegt darin, dass Python-Code nicht statisch verarbeitet werden kann (wie es bei C++-Compilern der Fall war) und man vor der Verwendung einiger Dinge keine Warnung erhalten kann, bevor man ihn tatsächlich verwendet. Ich halte es nicht für eine gute Idee, Benutzer Ihres Skripts mit einer Reihe von Nachrichten zu spammen: „Warnung: Dieser Entwickler dieses Skripts verwendet eine veraltete API“.
Aktualisieren: Sie können jedoch einen Dekorator erstellen, der die ursprüngliche Funktion in eine andere umwandelt. Die neue Funktion markiert/prüft den Schalter, um anzuzeigen, dass diese Funktion bereits aufgerufen wurde, und zeigt nur dann eine Meldung an, wenn der Schalter in den Ein-Zustand geschaltet wird. Und/oder beim Beenden wird möglicherweise eine Liste aller veralteten Funktionen gedruckt, die im Programm verwendet werden.
Vielen Dank, ich verwende dies, um den Benutzer an die richtige Stelle zu leiten, anstatt nur die veraltete Nachricht anzuzeigen!
– Deutscher Attanasio
5. Februar 2018 um 22:03
beantwortet nicht die eigentliche Frage.
– Catskul
2. Mai 2019 um 16:42 Uhr
Python ist ein dynamisch getippte Sprache. Es ist nicht erforderlich, den Typ statisch als Variable oder Argumenttyp für die Funktion zu deklarieren.
Da es dynamisch ist, wird alles zur Laufzeit verarbeitet. Auch wenn eine Methode veraltet ist, wird sie nur zur Laufzeit oder während der Interpretation bekannt sein.
verwenden Missbilligung Modul zum Verwerfen von Methoden.
Deprecation ist eine Bibliothek, die automatisierte Deprekationen ermöglicht. Es bietet die veraltet() Decorator, um Funktionen zu umschließen und entsprechende Warnungen sowohl in der Dokumentation als auch über Python bereitzustellen Warnungen System, sowie die deprecation.fail_if_not_removed() Dekorator für Testmethoden, um sicherzustellen, dass veralteter Code schließlich entfernt wird.
test.py: DeprecatedWarning: foo is deprecated. Use bar instead
foo()
Foo
Bar
Vielen Dank, ich verwende dies, um den Benutzer an die richtige Stelle zu leiten, anstatt nur die veraltete Nachricht anzuzeigen!
– Deutscher Attanasio
5. Februar 2018 um 22:03
beantwortet nicht die eigentliche Frage.
– Catskul
2. Mai 2019 um 16:42 Uhr
UPDATE: Ich denke, es ist besser, wenn wir DeprecationWarning nur beim ersten Mal anzeigen jede Codezeile und wenn wir eine Nachricht senden können:
import inspect
import traceback
import warnings
import functools
import time
def deprecated(message: str=""):
"""
This is a decorator which can be used to mark functions
as deprecated. It will result in a warning being emitted
when the function is used first time and filter is set for show DeprecationWarning.
"""
def decorator_wrapper(func):
@functools.wraps(func)
def function_wrapper(*args, **kwargs):
current_call_source="|".join(traceback.format_stack(inspect.currentframe()))
if current_call_source not in function_wrapper.last_call_source:
warnings.warn("Function {} is now deprecated! {}".format(func.__name__, message),
category=DeprecationWarning, stacklevel=2)
function_wrapper.last_call_source.add(current_call_source)
return func(*args, **kwargs)
function_wrapper.last_call_source = set()
return function_wrapper
return decorator_wrapper
@deprecated('You must use my_func2!')
def my_func():
time.sleep(.1)
print('aaa')
time.sleep(.1)
def my_func2():
print('bbb')
warnings.simplefilter('always', DeprecationWarning) # turn off filter
print('before cycle')
for i in range(5):
my_func()
print('after cycle')
my_func()
my_func()
my_func()
Ergebnis:
before cycle
C:/Users/adr-0/OneDrive/Projects/Python/test/unit1.py:45: DeprecationWarning: Function my_func is now deprecated! You must use my_func2!
aaa
aaa
aaa
aaa
aaa
after cycle
C:/Users/adr-0/OneDrive/Projects/Python/test/unit1.py:47: DeprecationWarning: Function my_func is now deprecated! You must use my_func2!
aaa
C:/Users/adr-0/OneDrive/Projects/Python/test/unit1.py:48: DeprecationWarning: Function my_func is now deprecated! You must use my_func2!
aaa
C:/Users/adr-0/OneDrive/Projects/Python/test/unit1.py:49: DeprecationWarning: Function my_func is now deprecated! You must use my_func2!
aaa
Process finished with exit code 0
Wir können einfach auf den Warnpfad klicken und zur Zeile in PyCharm gehen.
beantwortet nicht die eigentliche Frage.
– Catskul
2. Mai 2019 um 16:43 Uhr
14501400cookie-checkDekoratoren in der Python-Standardbibliothek (@speziell veraltet)yes
jetzt gibt es eine Missbilligung Paket
– Myon
1. November 2017 um 21:13 Uhr
Ich verstehe die Möglichkeiten, dies zu tun, bin aber hierher gekommen, um zu erfahren, warum es nicht in der Standardbibliothek enthalten ist (wie ich annehme, dass dies beim OP der Fall ist) und sehe keine gute Antwort auf die eigentliche Frage
– SwimBikeRun
1. April 2019 um 14:57 Uhr
Warum kommt es so oft vor, dass auf Fragen dutzende Antworten gegeben werden, die nicht einmal versuchen, die Frage zu beantworten, und Dinge wie „Ich kenne Rezepte“ aktiv ignoriert? Es ist wahnsinnig!
– Catskul
2. Mai 2019 um 16:46
@Catskul wegen gefälschter Internetpunkte.
– Stefano Borini
2. Mai 2019 um 19:07 Uhr
@Catskul Nicht Warum Fragen sind überhaupt veraltet oder sollten sie nicht auf SO gestellt werden? Wie wir so oft sehen, neigen sie dazu, keine Antworten zu produzieren. Ich hätte diesen Kommentar nicht hinterlassen, wenn ich nicht alle deine gesehen hätte antwortet nicht Dekorateure 😉
– Wolf
27. Mai 2021 um 12:21 Uhr