如何在函数中使用 dir() 作为默认参数

李88

我无法弄清楚我做错了什么。似乎我无法使用 dir() 作为函数输入的默认参数

def print_all_vars(arg=dir()):
    for i in arg:
        print(i)

foo=1

如果我使用

print_all_vars()

给出输出

__builtins__
__cached__
__doc__
__file__
__loader__
__name__
__package__
__spec__

print_all_vars(dir())

输出

__builtins__
foo
print_all_vars
布宜诺斯艾利斯

所以 - 首先,发生了什么 -

包含该def语句的行仅运行一次,当包含该函数的模块首次导入时(或在交互式提示中) - 无论如何,用作默认参数值的任何表达式都被评估一次,并且它们的结果对象保留为该参数的默认值。

因此,您的dir()调用将被执行,并且结果列表 -dir包含您的示例函数的模块的命名空间上的a被保存。(Python初学者最常见的相关错误是尝试将空列表或字典([]{})作为参数默认值:相同的列表或字典将在函数的生命周期内重复使用)。

这解释了为什么您会在输出中看到一些值,如果您dir在交互式提示中使用 a 调用它,则不会显示这些值,例如__package____spec__

现在,你真正的问题是:

...我实际上是在尝试创建 MATLAB 的 save 函数的模拟,该函数将所有现有变量保存到以后可以调用的外部文件中 –

因此,即使您dir()会被延迟执行,当仅调用该函数时,它仍然会失败:它仍然会从定义该函数的模块中检索变量名称,而不是在调用方上检索。

这样做的编码模式是:

def print_all_vars(arg=None):
    if arg is None:
        arg = dir()
    ...

(这是在函数体上强制将空字典列表作为默认参数的最常见方法)

但即便如此,或者如果您将自己的变量名列表显式传递给函数,您仍然只有一个字符串列表 - 而不是需要您想要保存的 Python 对象。

并且 - 如果您想在默认情况下从调用方检索变量,则使用此字符串列表存在一个共同问题:您需要能够访问调用方代码的命名空间,以便检索变量名称存在那里,然后检索其内容以保存。

在 Python 中知道“谁调用了你的函数”的方法是一种高级的东西,我什至不确定它是否保证适用于所有 Python 实现——但它肯定适用于最常见的(cPython、Pypy、Jython) ) 甚至一些被认为是较小的(例如 Brython):

您调用sys._getframe()来检索当前正在执行的代码(即函数本身中的代码)的框架对象-该框架对象将具有一个f_back属性,该属性指向调用您的函数的代码的框架对象框架对象在其一侧具有分别引用作为f_globals和的普通字典运行的代码的globals和locals变量的引用f_locals

您可以根据需要在调用者代码上“保存”和“恢复”全局变量的内容 - 但您不能更新 - 使用纯 Python 代码 - 局部变量。

所以,只是默认列出调用者代码上的全局变量 - 你可以这样做:

import sys


def print_all_vars(arg=None):
    if arg is None:
        arg = list(sys.get_frame.f_back.f_globals.keys())
    print (arg)

能够正确保存和还原这些变量是另一个问题-正如您在注释中所看到的,您可以pickle用来序列化许多Python对象-但调用者名称空间将具有模块名称(例如mathnp`等)。 ) 通常不能被腌制 - 因此您必须采用一种策略来检测、注释使用的模块并通过对检索到的所有对象进行进一步内省来恢复它们。

无论如何,尝试这里的信息应该会让你走上你想要的轨道。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章