如何在 "class" 对象中实现 "decorator" 功能?
How to implement "decorator" functionality in a "class" object?
我正在尝试构建一个抑制 stdout 和 stderr 的 class。 当用作 with statement
时我将其关闭,但我想扩展功能也可以用作装饰器,我可以用它来抑制函数的输出。是否可以将所有内容完全包含在 class 中,或者包装器是否需要成为 class 之外的函数?
我正在尝试遵循这些资源,但很难适应我的情况:
https://stackabuse.com/pythons-classmethod-and-staticmethod-explained/
import os,sys, functools
class Suppress(object):
def __init__(self, show_stdout=False, show_stderr=False):
self.show_stdout = show_stdout
self.show_stderr = show_stderr
self.original_stdout = None
self.original_stderr = None
def __enter__(self):
devnull = open(os.devnull, "w")
# Suppress streams
if not self.show_stdout:
self.original_stdout = sys.stdout
sys.stdout = devnull
if not self.show_stderr:
self.original_stderr = sys.stderr
sys.stderr = devnull
def __exit__(self, *args, **kwargs):
# Restore streams
if not self.show_stdout:
sys.stdout = self.original_stdout
if not self.show_stderr:
sys.stderr = self.original_stderr
def __call__(self, *args, **kwargs):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
with self(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
return decorator
with Suppress(show_stdout=False, show_stderr=False):
print("stdout", file=sys.stdout)
print("stderr", file=sys.stderr)
我正在尝试将此功能作为装饰器:
@Suppress(show_stdout=True)
def f(x, y):
print(x, file=sys.stdout)
print(y, file=sys.stderr)
return x*y
a = f(1,2)
# 1
# a = 2
我有一个类似的装饰器(虽然非常丑陋)用于 matplotlib
风格的包装器。但是,这必须使用外部函数并且不在 class.
内
# # Decorators
# def stylize(style="seaborn-white"):
# def decorator(func):
# @functools.wraps(func)
# def wrapper(*args, **kwargs):
# with plt.style.context(style):
# return func(*args, **kwargs)
# return wrapper
# return decorator
# # Wrappers
# def subplots_wrapper(style="seaborn-white", *args, **kwargs):
# @stylize(style)
# def inner_wrapper(*args, **kwargs):
# return plt.subplots(*args, **kwargs)
# return inner_wrapper(*args, **kwargs)
如果您只使用不带参数的 with self
,它会起作用:
def __call__(self, function):
@functools.wraps(function)
def decorated(*args, **kwargs):
with self:
return function(*args, **kwargs)
return decorated
您可以通过组合 contextlib
中的各种片段来定义它。简而言之,这使用 ExitStack
将请求的重定向上下文管理器组合成单个上下文管理器,并使用 ContextDecorator
将生成的上下文管理器也用作装饰器。
from contextlib import ExitStack, ContextDecorator, redirect_stdout, redirect_stderr
import sys
from os import devnull
class Suppress(ContextDecorator, ExitStack):
def __init__(self, show_stdout=False, show_stderr=False, **kwargs):
super().__init__(**kwargs)
self.redirections = []
if show_stdout:
self.redirections.append(redirect_stdout)
if show_stderr:
self.redirections.append(redirect_stderr)
def __enter__(self):
rv = super().__enter__()
if self.redirections:
f = rv.enter_context(open(devnull, "w"))
for r in self.redirections:
rv.enter_context(r(f))
return rv
__init__
存储列表中需要的 类 redirect_stdout
和 redirect_stderr
。
__enter__
,如果请求了任何重定向,则打开适当的接收器并进行适当的重定向。作为退出堆栈,Suppress
将负责确保重定向结束并关闭接收器。
我正在尝试构建一个抑制 stdout 和 stderr 的 class。 当用作 with statement
时我将其关闭,但我想扩展功能也可以用作装饰器,我可以用它来抑制函数的输出。是否可以将所有内容完全包含在 class 中,或者包装器是否需要成为 class 之外的函数?
我正在尝试遵循这些资源,但很难适应我的情况:
https://stackabuse.com/pythons-classmethod-and-staticmethod-explained/
import os,sys, functools
class Suppress(object):
def __init__(self, show_stdout=False, show_stderr=False):
self.show_stdout = show_stdout
self.show_stderr = show_stderr
self.original_stdout = None
self.original_stderr = None
def __enter__(self):
devnull = open(os.devnull, "w")
# Suppress streams
if not self.show_stdout:
self.original_stdout = sys.stdout
sys.stdout = devnull
if not self.show_stderr:
self.original_stderr = sys.stderr
sys.stderr = devnull
def __exit__(self, *args, **kwargs):
# Restore streams
if not self.show_stdout:
sys.stdout = self.original_stdout
if not self.show_stderr:
sys.stderr = self.original_stderr
def __call__(self, *args, **kwargs):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
with self(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
return decorator
with Suppress(show_stdout=False, show_stderr=False):
print("stdout", file=sys.stdout)
print("stderr", file=sys.stderr)
我正在尝试将此功能作为装饰器:
@Suppress(show_stdout=True)
def f(x, y):
print(x, file=sys.stdout)
print(y, file=sys.stderr)
return x*y
a = f(1,2)
# 1
# a = 2
我有一个类似的装饰器(虽然非常丑陋)用于 matplotlib
风格的包装器。但是,这必须使用外部函数并且不在 class.
# # Decorators
# def stylize(style="seaborn-white"):
# def decorator(func):
# @functools.wraps(func)
# def wrapper(*args, **kwargs):
# with plt.style.context(style):
# return func(*args, **kwargs)
# return wrapper
# return decorator
# # Wrappers
# def subplots_wrapper(style="seaborn-white", *args, **kwargs):
# @stylize(style)
# def inner_wrapper(*args, **kwargs):
# return plt.subplots(*args, **kwargs)
# return inner_wrapper(*args, **kwargs)
如果您只使用不带参数的 with self
,它会起作用:
def __call__(self, function):
@functools.wraps(function)
def decorated(*args, **kwargs):
with self:
return function(*args, **kwargs)
return decorated
您可以通过组合 contextlib
中的各种片段来定义它。简而言之,这使用 ExitStack
将请求的重定向上下文管理器组合成单个上下文管理器,并使用 ContextDecorator
将生成的上下文管理器也用作装饰器。
from contextlib import ExitStack, ContextDecorator, redirect_stdout, redirect_stderr
import sys
from os import devnull
class Suppress(ContextDecorator, ExitStack):
def __init__(self, show_stdout=False, show_stderr=False, **kwargs):
super().__init__(**kwargs)
self.redirections = []
if show_stdout:
self.redirections.append(redirect_stdout)
if show_stderr:
self.redirections.append(redirect_stderr)
def __enter__(self):
rv = super().__enter__()
if self.redirections:
f = rv.enter_context(open(devnull, "w"))
for r in self.redirections:
rv.enter_context(r(f))
return rv
__init__
存储列表中需要的 类 redirect_stdout
和 redirect_stderr
。
__enter__
,如果请求了任何重定向,则打开适当的接收器并进行适当的重定向。作为退出堆栈,Suppress
将负责确保重定向结束并关闭接收器。