【问题标题】:Apply function decorator on print function across all files without having to import and/or reapply?在所有文件的打印功能上应用功能装饰器,而无需导入和/或重新应用?
【发布时间】:2018-02-08 18:51:41
【问题描述】:

编辑:我第一次尝试问这个问题可能有点不专注/措辞不佳,这是对我正在尝试做的事情的更好解释:

我正在尝试修改 python 运行的整个环境的打印函数的默认行为,而不必修改正在运行的每个文件。

我正在尝试装饰打印功能(我知道有很多方法可以做到这一点,例如覆盖它,但这不是我要问的问题)所以我可以让它打印出一些调试信息并强制它总是冲洗。我是这样做的:

def modify_print(func):
    # I made this so that output always gets flushed as it won't by default
    # within the environment I'm using, I also wanted it to print out some
    # debugging information, doesn't really matter much in the context of this
    # question
    def modified_print(*args,**kwargs):
        return func(f"some debug prefix: ",flush=True,*args,**kwargs)
    return modified_print

print = modify_print(print)
print("Hello world") # Prints "some debug prefix Hello World"

但是,我正在尝试在整个应用程序中修改此行为。我知道我可以手动装饰/覆盖/导入每个文件中的打印功能,但是我想知道是否有某种方法可以全局配置我的 python 环境以在任何地方装饰这个功能。我能想到的唯一方法是编辑 python 源代码并构建修改后的版本。

编辑: 这是我想要实现的行为,感谢 Match 的帮助。 它会在您在 python 环境中调用打印函数的任何地方打印出行号和文件名。这意味着您不必在所有文件中手动导入或覆盖任何内容。

https://gist.github.com/MichaelScript/444cbe5b74dce2c01a151d60b714ac3a

import site
import os
import pathlib
# Big thanks to Match on StackOverflow for helping me with this
# see https://stackoverflow.com/a/48713998/5614280

# This is some cool hackery to overwrite the default functionality of
# the builtin print function within your entire python environment
# to display the file name and the line number as well as always flush 
# the output. It works by creating a custom user script and placing it 
# within the user's sitepackages file and then overwriting the builtin.

# You can disable this behavior by running python with the '-s' flag.


# We could probably swap this out by reading the text from a python file
# which would make it easier to maintain larger modifications to builtins
# or a set of files to make this more portable or to modify the behavior
# of more builtins for debugging purposes.
customize_script = """
from inspect import getframeinfo,stack
def debug_printer(func):
    # I made this so that output always gets flushed as it won't by default
    # within the environment I'm running it in. Also it will print the
    # file name and line number of where the print occurs
    def debug_print(*args,**kwargs):
        frame = getframeinfo(stack()[1][0])
        return func(f"{frame.filename} : {frame.lineno} ", flush=True,*args,**kwargs)
    return debug_print

__builtins__['print'] = debug_printer(print)
"""

# Creating the user site dir if it doesn't already exist and writing our
# custom behavior modifications
pathlib.Path(site.USER_SITE).mkdir(parents=True, exist_ok=True)
custom_file = os.path.join(site.USER_SITE,"usercustomize.py")
with open(custom_file,'w+') as f:
    f.write(customize_script)

【问题讨论】:

  • 只需使用上面的代码作为包装器 - 即在重新定义 print 之后,然后转到 import 并运行您的 real 应用程序。
  • 是的,但是打印功能不会在每个文件中被覆盖,除非在每个单独的文件中手动导入或覆盖它。换句话说:修改python运行的整个环境的print函数的默认行为。

标签: python python-3.x


【解决方案1】:

您可以使用site 模块中的usercustomize 脚本来实现类似的功能。

首先,找出您的用户站点包目录在哪里:

python3 -c "import site; print(site.USER_SITE)"

/home/foo/.local/lib/python3.6/site-packages

接下来,在该目录中,创建一个名为 usercustomize.py 的脚本 - 现在无论何时运行 python,此脚本都会首先运行。

替换 print 的一种*方法是覆盖 __builtins__ 字典并用新方法替换它 - 类似于:

from functools import partial
old_print = __builtins__['print']

__builtins__['print'] = partial(old_print, "Debug prefix: ", flush=True)

把它放到usercustomize.py 脚本中,你应该会看到所有的python 脚本都被覆盖了。您可以通过使用-s 标志调用python 来暂时禁用调用此脚本。

*(不确定这是否是正确的方法 - 可能有更好的方法 - 但重点是您可以使用 usercustomize 提供您选择的任何方法)。

【讨论】:

  • 嘿,非常感谢!我对您的解决方案感到非常满意。我用我编写的脚本更新了我的问题,它会自动执行此操作并打印一些调试信息,希望你也能发现它有用!
【解决方案2】:

没有真正的理由在这里定义装饰器,因为您只是打算将它应用于单个预定函数。只需直接定义修改后的 print 函数,将其包裹在 __builtins__.print 周围以避免递归。

def print(*args, **kwargs):
    __builtins.__print(f"some debug prefix: ", flush=True, *args, **kwargs)

print("Hello world") # Prints "some debug prefix Hello World"

您可以使用functools.partial 来简化此操作。

import functools
print = functools.partial(__builtins.__print, f"some debug prefix: ", flush=True)

【讨论】:

  • 是的,我知道你可以做到。我的问题更多是关于如何全局修改该打印功能,因此我不必在每个文件中导入/执行该操作。
猜你喜欢
  • 2014-12-15
  • 2018-06-02
  • 2021-11-11
  • 2018-07-11
  • 1970-01-01
  • 2021-01-17
  • 1970-01-01
  • 2016-09-27
  • 2015-07-07
相关资源
最近更新 更多