如果我定义一个函数:
def f(x):
return x+3
Run Code Online (Sandbox Code Playgroud)
我以后可以将对象存储为函数的属性,如下所示:
f.thing="hello!"
Run Code Online (Sandbox Code Playgroud)
我想从函数本身的代码中做到这一点.问题是,如何从内部获取对函数的引用?
我正在阅读Flatten(一个不规则的)列表列表,并决定采用它作为Python练习 - 我偶尔会重写一个小函数,而不是参考原文,只是为了练习.我第一次尝试这个,我有类似以下内容:
def flat(iterable):
try:
iter(iterable)
except TypeError:
yield iterable
else:
for item in iterable:
yield from flatten(item)
Run Code Online (Sandbox Code Playgroud)
这对于list包含数字的嵌套s 这样的基本结构很有效,但是字符串会使它崩溃,因为字符串的第一个元素是单字符字符串,第一个元素本身,第一个元素本身就是它,依此类推.检查上面链接的问题,我意识到这解释了检查字符串.这给了我以下内容:
def flatter(iterable):
try:
iter(iterable)
if isinstance(iterable, str):
raise TypeError
except TypeError:
yield iterable
else:
for item in iterable:
yield from flatten(item)
Run Code Online (Sandbox Code Playgroud)
现在它也适用于字符串.但是,我随后回忆起a list可以包含对自身的引用.
>>> lst = []
>>> lst.append(lst)
>>> lst
[[...]]
>>> lst[0][0][0][0] is lst
True
Run Code Online (Sandbox Code Playgroud)
因此,字符串不是唯一可能导致此类问题的类型.在这一点上,我开始寻找一种方法来防止这个问题,而无需进行明确的类型检查.
下面flattener.py接踵而至.flattish()是一个只检查字符串的版本.flatten_notype()检查对象的第一个项目的第一个项目是否等于自身以确定递归.flatten()执行此操作然后检查对象或其第一个项目的第一个项目是否是另一个项目的实例.的Fake类基本上只定义了序列的包装.测试每个函数的行的注释在表单中描述结果should be `desired_result` [> `undesired_actual_result`] …
在C++中我们有静态关键字,在循环中是这样的:
for(int x=0; x<10; x++)
{
for(int y=0; y<10; y++)
{
static int number_of_times = 0;
number_of_times++;
}
}
Run Code Online (Sandbox Code Playgroud)
这里静态number_of_times初始化一次.我怎么能在python 3.x中做同样的事情?
编辑:由于大多数人感到困惑,我想指出我给出的代码只是C++静态用法的一个例子.我真正的问题是我想在函数中只初始化一个时间变量,因为我不希望它是全局的(等等!)或默认参数..
我已经尝试在Python 2.6中执行此操作,它确实"有效":
>>> def f(i='I'): return i
...
>>> f.func_defaults = (10,)
>>> f()
10
Run Code Online (Sandbox Code Playgroud)
但这是官方指定的行为,还是我遇到了特定于实现的行为?
我有一堆函数(在任何类之外),我在其上设置了属性,比如funcname.fields = 'xxx'.我希望我可以从函数内部访问这些变量self.fields,但当然它告诉我:
全局名称'self'未定义
那么......我该怎么办?我可以访问一些神奇的变量吗?喜欢__this__.fields?
有几个人问过"为什么?".您可能不同意我的推理,但我有一组函数,所有函数都必须共享相同的签名(只接受一个参数).在大多数情况下,这一个参数足以进行所需的计算.但是,在一些有限的情况下,需要一些额外的信息.我决定只在功能上设置它们,以便很容易被忽略,而不是强迫每个函数接受一长串未使用的变量.
虽然,现在我发现**kwargs如果你不关心额外的args ,你可以使用它作为最后一个参数.那好吧...
编辑:实际上,我没有写的一些功能,宁愿不修改接受额外的args.通过"传入"额外的args作为属性,我的代码可以使用我的自定义函数,利用额外的args,以及不需要额外args的第三方代码.
谢谢你的快速答案:)
从2.4(类的2.6)开始,python允许你用另一个函数来装饰一个函数:
def d(func): return func
@d
def test(first): pass
Run Code Online (Sandbox Code Playgroud)
这是一种方便的语法糖.您可以使用装饰器做各种各样的整洁的东西,而不会弄乱.但是,如果你想找出装饰的原始功能,你必须跳过箍(喜欢Cls.method.__func__.__closure__[0].cell_contents或更糟).
我发现自己希望有一个更好的方法,并发现在python-dev上有一些关于添加一个变量的讨论,该变量被称为__decorated__装饰器返回的[new]函数.然而,似乎没有去任何地方.
作为一个冒险的人,并且有大约4年的相当重的python经验,我想我会考虑__decorated__在python编译器源中实现,只是为了看看它是怎么回事.
说实话,我从来没有钻研过引擎盖下的C,所以我的第一个小时就是试图弄清楚底层C代码是如何工作的.首先,什么是最好的资源来了解我必须改变/添加的内容__decorator__?
其次,如果装饰器返回一个新函数,那么__decorated__只返回原始的装饰函数.但是,如果装饰器返回原始函数,会发生什么?以下是我能想到的三个选项(第三个是我最喜欢的):
__decorator__.__decorator__但将其设置为无.__decorator__无论如何,添加并将其设置为原始功能.所以,如果它发生了,你认为最好的选择是什么?
更新:
其他人提请我注意我错过的情景.当装饰器既不返回原始函数也不返回包装原始函数的函数时会发生什么?那时没有任何东西持有对原始函数的引用,它将被垃圾收集.(感谢Oddthinking!)
那么在那种情况下,我认为我仍然会选择第三种方案.装饰器返回的对象将获得一个__decorated__引用原始函数的名称.这意味着它不会被垃圾收集.
对我来说,类定义中的函数完全消失是因为你装饰它,这似乎很奇怪.在我看来,更有理由__decorated__为每个装饰者申请一个属性.然而,我的直觉更有可能是错误的,并且当前的行为是大多数人所期望的. 有什么想法吗?
请考虑以下示例:
def main():
a = 'predefined'
variables = {'a':'dynamic'}
locals().update(variables)
print a
if __name__ == '__main__':
main()
Run Code Online (Sandbox Code Playgroud)
运行脚本时,我希望看到:
dynamic
Run Code Online (Sandbox Code Playgroud)
但我知道
predefined
Run Code Online (Sandbox Code Playgroud)
为什么?我怎样才能获得动态值?
我问的原因是:我有一个程序,它接受许多输入参数,冗长的变量名称.我希望简单地"解包" argparse解析器在一次调用中收到的任何内容locals().update(...)
def main():
a = 'predefined'
parser = argparse.ArgumentParser(description='My program')
parser.add_argument('-a', type=int, default=a, required=False);
# Hoping to avoid typing lines like the following for every parameter:
# a = parser.parse_args().a
input_variables = vars(parser.parse_args())
locals().update(input_variables)
# Process stuff using the parameter names directly, e.g.
print a
Run Code Online (Sandbox Code Playgroud)