frame对象f_back属性 黑科技的味道

274 views
Skip to first unread message

coder vx

unread,
Nov 22, 2017, 4:31:16 AM11/22/17
to python-cn(华蟒用户组,CPyUG 邮件列表)
通过frame对象的f_back,可以回溯到之前任意的调用栈上,这没有什么好玩的地方.但是frame对象有两个属性f_locals,f_builtins.居然可以被修改.即子函数可以修改父函数的可变局部变量和内建方法.
import sys


def g():
    frame = sys._getframe()
    caller = frame.f_back
    print "caller's local namespace: ", caller.f_locals
    caller.f_locals['a'][0] = 100
    caller.f_locals['b'] = 4
    caller.f_builtins['list'] = tuple


def f():
    a = [1, 2]
    b = 2
    print "before call g()!a = {}, b={}".format(a, b)
    g()
    print "after call g()!a = {}, b={}".format(a, b)
    c = list([3, 4])
    print c


f()
输出为:
before call g()!a = [1, 2], b=2
caller's local namespace:  {'a': [1, 2], 'b': 2}
after call g()!a = [100, 2], b=2
(3, 4)


虽然绝大多数情况下,这个黑科技应该是埋坑用的. 但总感觉可以利用这个特性做点什么?
就像 1. object.__subclasses__() 可以用来逃逸python沙箱   2.frame的f_back可以实现尾递归优化一样

Leo Jay

unread,
Nov 22, 2017, 5:25:38 AM11/22/17
to python-cn:CPyUG
想到两个用处,
1. 模拟 3.6 新加的 Literal String Interpolation 里的最简单的情况
def f(s):
frame = sys._getframe()
caller = frame.f_back
return s.format(**caller.f_locals)

def test_f():
a = 'hello'
b = 'world'
print(f('{a} {b}!'))

会输出:
hello world!

2. 类构造函数参数自动赋值到 self 上
def auto_init_params():
frame = sys._getframe()
caller = frame.f_back
obj = caller.f_locals['self']
for k, v in caller.f_locals.items():
if k != 'self':
setattr(obj, k, v)

class Foo(object):
def __init__(self, a, b, c):
auto_init_params()
print(self.a, self.b, self.c)

foo = Foo(1, 2, 5)
会输出:
(1, 2, 5)
> --
> 邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
> 规则: http://code.google.com/p/cpyug/wiki/PythonCn
> 详情: http://code.google.com/p/cpyug/wiki/CpyUg
> 严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
> ---
> 您收到此邮件是因为您订阅了Google网上论坛上的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
> 要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+...@googlegroups.com
> 要发帖到此群组,请发送电子邮件至pyth...@googlegroups.com
> 要查看更多选项,请访问https://groups.google.com/d/optout

yegle

unread,
Nov 22, 2017, 1:15:30 PM11/22/17
to pyth...@googlegroups.com
开眼了…

> 要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+unsubscribe@googlegroups.com
> 要发帖到此群组,请发送电子邮件至python-cn@googlegroups.com
> 要查看更多选项,请访问https://groups.google.com/d/optout


--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
详情: http://code.google.com/p/cpyug/wiki/CpyUg
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了 Google 网上论坛的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+unsubscribe@googlegroups.com
要向此群组发帖,请发送电子邮件至 pyth...@googlegroups.com
要查看更多选项,请访问 https://groups.google.com/d/optout



--

YS.Zou

unread,
Nov 22, 2017, 8:22:48 PM11/22/17
to pyth...@googlegroups.com
这个黑科技应该是埋坑用的

这不是埋坑,是杀人于无形啊 。

感觉能用在 元类相关场景, mixin,DSL (通过 __doc__ 生成相关方法属性,而不是通过方法属性生成 doc) 等地方,但是具体地,在这之前,思维中还完全没有它的存在,后面脑子中可以把 ``locals`` 本身作为一个可以运用的工具。其实真的时不时会碰到“动态属性”的需求,以前没多想,就直接套一层“壳”再处理了。

对于 ``g()`` ,它的输入(指使用 f_back)像是一套状态,从这点来说,有点像 javascript 中的 this 。







--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
详情: http://code.google.com/p/cpyug/wiki/CpyUg
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了Google网上论坛上的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+unsubscribe@googlegroups.com
要发帖到此群组,请发送电子邮件至python-cn@googlegroups.com
要查看更多选项,请访问https://groups.google.com/d/optout



--
进出自由才是游戏者的生存之道。

http://www.zouyesheng.com
Message has been deleted

shhgs

unread,
Nov 22, 2017, 8:27:35 PM11/22/17
to pyth...@googlegroups.com
双截棍用的好就是仁者无敌,不会用只能自己揍自己了。

Features are design to be abused.

3b295

unread,
Nov 22, 2017, 10:19:16 PM11/22/17
to python-cn(华蟒用户组,CPyUG 邮件列表)
我认为这个用法没有那么危险。它类似下面的代码:
def g2():
nonlocal a, b, list
    a[0] = 100
b = 4
list = tuple
区别就是g()可以动态的设置 a, b, list 。而nonlocal是关键字,需要写死在代码里。
global nonlocal 本身就是个比较常见的操作。g()的用法只是它们的更灵活版本。它只是一个带有副作用的正常函数。


在 2017年11月22日星期三 UTC+8下午5:31:16,coder vx写道:

Shell Xu

unread,
Nov 22, 2017, 11:49:36 PM11/22/17
to CUPG
我觉得你们这是拿着锤子找钉子。。。

> 要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+unsubscribe@googlegroups.com
> 要发帖到此群组,请发送电子邮件至python-cn@googlegroups.com
> 要查看更多选项,请访问https://groups.google.com/d/optout

--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
详情: http://code.google.com/p/cpyug/wiki/CpyUg
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了 Google 网上论坛的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+unsubscribe@googlegroups.com

要向此群组发帖,请发送电子邮件至 pyth...@googlegroups.com
要查看更多选项,请访问 https://groups.google.com/d/optout



--
彼節者有間,而刀刃者無厚;以無厚入有間,恢恢乎其於游刃必有餘地矣。
blog: http://shell909090.org/

Mengyang Li

unread,
Nov 23, 2017, 12:07:41 AM11/23/17
to pyth...@googlegroups.com
感觉类似于C里面写个指针操作自己的栈,因为call conversions 是已知的所以可以用指针算出所有frame然后直接访问。debugger就是利用这个功能做到的啊
Best regards,
ᶘ ᵒᴥᵒᶅ
Mengyang Li

coder vx

unread,
Nov 23, 2017, 12:35:44 AM11/23/17
to python-cn(华蟒用户组,CPyUG 邮件列表)
nonlocal 只适应用于内部函数。利用nonlocal,类似于词法作用域,安全可靠很多. f_locals更像动态作用域,好比js的this,灵活危险很多.

在 2017年11月23日星期四 UTC+8上午11:19:16,3b295写道:

熊巍迤

unread,
Nov 23, 2017, 1:19:15 AM11/23/17
to pyth...@googlegroups.com
谢谢指出。想了一下,我的确想错了。nonlocal 拿到的只是函数定义时的闭包作用域, f_locals 拿到的是函数真正运行时的环境,这都不是一个东西。

--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
详情: http://code.google.com/p/cpyug/wiki/CpyUg
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了Google网上论坛上“python-cn(华蟒用户组,CPyUG 邮件列表)”群组中的主题。
要退订此主题,请访问https://groups.google.com/d/topic/python-cn/bJHTBI9vhwc/unsubscribe
要退订此群组及其所有主题,请发送电子邮件到python-cn+unsubscribe@googlegroups.com

est

unread,
Nov 28, 2017, 8:54:09 AM11/28/17
to pyth...@googlegroups.com
玩多了小心内存泄漏。。记得文档上说这玩意某个姿势2.6之前就会漏无止境。。

--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
详情: http://code.google.com/p/cpyug/wiki/CpyUg
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了Google网上论坛上的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+unsubscribe@googlegroups.com
Reply all
Reply to author
Forward
0 new messages