有没有办法在 Python 中直接引用命名空间及其属性?



我正在考虑这个问题一段时间了,我真的认为从方法代码内部直接引用方法对象会很方便,或者更一般地说:从内部引用命名空间。让我们看一下我当前的代码:

def do_stuff(args):
logtarget, someargs = process_input(args)
processed_data = do_other_stuff(someargs, outputdir)
log("Template string".format(processed_data), outputdir=outputdir,  filename="resultfile.txt")
def do_other_stuff(someargs, logtarget):
step = process_data(someargs)
if requires_manual_postproceccing(step):
log(step, outputdir=outputdir, filename="handle manually.txt")
return get_result(step)
def log(message, outputdir="default", filename="default.txt"):
with open("{}/{}".format(outputdir, filename), "a") as file:
file.write(message)

如您所见,我正在传递输出目录,我什至没有提到do_stuff和do_other_stuff也可能记录内容(但由于只要脚本正常运行,我就不需要这些日志,我并不真正关心它的位置)。如果可以设置一次参数,然后在日志消息中访问它,那不是很好吗?目标由脚本处理,因此我无法对其进行硬编码。

由于 outputdir 是在函数(命名空间)中处理的,因此我们无法从其他函数(命名空间)访问它,除非我们使用glogal关键字 whitch - 毕竟我读过它 - 我希望永远不必使用。我的直觉告诉我要这样处理这个问题:

def do_stuff(args):
outputdir, someargs = process_input(args)
log.outputdir = outputdir
processed_data = do_other_stuff(someargs)
log(processed_data.format("somehow"), filename="resultfile.txt")
def do_other_stuff(someargs):
step = process_data(someargs)
if requires_manual_posproceccing(step):
log(step, filename="handle manually.txt")
return get_result(step)
def log(message, filename="default.txt"):
with open("{}/{}".format(this.outputdir, filename), "a") as file:
file.write(message)

它更容易阅读,使用更少的参数,并且不会招致奇怪的行为和错误 - 但它显然不起作用。现在我知道我可以(应该?)使用一个花哨的日志记录库,或者至少编写一个记录器类,这样我就可以使用logger = Logger(outputdir)而不是在方法中使用self。但是保持它苗条和扁平是Python的编码方式,直到现在我可以很容易地遵循规则"每当你看到一个类使用__init__以外的一种方法时,它应该只是一个函数。此外,即使我使用了该记录器类或日志记录库,我仍然需要传递该实例。

处理此问题的最佳方法是否真的是使用方法的名称而不是this,并在有人装饰我的函数时冒问题的风险,或者有没有办法直接引用当前命名空间及其属性?要么我不知道正确的词来搜索这个,要么它太低而无法记录,或者它不存在。


[编辑:] 实际上,我真正想做的(但不知道我想要它)是装饰(oop-cecorate,而不是Python的馅饼装饰)log函数。但我仍然会遇到同样的问题,因为log = decorate(log)只会影响当前的命名空间。dir返回当前命名空间而不是全局命名空间,因此只要不想使用global,除了创建和传递可调用对象(callbackfunction)之外,实际上没有其他方法。现在有两个答案,我无法轻易决定哪一个更清楚。Martin Bonner 建议的可调用类适用于标准 Python,并且只创建一个可调用的而不是两个。另一方面,我采用的解决方案是一个get_log函数,它返回一个函数,因为它更清晰,避免使用除__init__以外的一种方法创建类,并且需要更少的代码:

def get_log(outerdir):
def log(message, filename="default.txt"):
with open("{}/{}".format(outputdir, filename), "a") as file:
file.write(message)
return log

如果我们通过创建一个可以添加到任何函数中的饼装饰器来使其更加通用,我们基本上只是重新创建 heemayl 建议的partial函数,所以我们开始了。这里没有发明的最 Python 方法,并且使用最少的代码。

如果我理解正确,您正在寻找一种方法来使outputdir对所有调用log的静态调用。如果是这样,您可以利用functools.partial

from functools import partial
log_with_outputdir = partial(log, outputdir='/path/to/outputdir')

现在,您可以像log一样调用log_with_outputdir,而无需参数outputdir因为它已经应用

将函数和一些数据绑定在一起的正确方法是使用类。 您甚至可以通过使函数__call__来使其行为与当前解决方案非常相似:

class Logger(object):
def __init__(self)
self.outputdir="default"
def __call__(self, message, filename="default.txt"):
with open("{}/{}".format(self.outputdir, filename), "a") as file:
file.write(message)
log = Logger()
def do_stuff(args):
outputdir, someargs = process_input(args)
log.outputdir = outputdir
processed_data = do_other_stuff(someargs)
log(processed_data.format("somehow"), filename="resultfile.txt")
...

最新更新