V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
zerh925
V2EX  ›  Python

[python]能知道函数的外层调用函数吗?

  •  
  •   zerh925 · 2015-05-21 10:28:10 +08:00 · 3018 次点击
    这是一个创建于 3473 天前的主题,其中的信息可能已经有所发展或是发生改变。
    def foo():
        print 'foo'
    
    def bar():
        foo()
    
    def run():
        foo()
    

    我有办法知道知道foo()每次是被什么函数调用吗?

    比如被bar()调用和被run()调用做不同的操作。

    或者我能知道foo()每次被调用是程序运行以来第几次运行吗?自省能做到这些吗?

    17 条回复    2015-05-22 08:53:18 +08:00
    Septembers
        1
    Septembers  
       2015-05-21 10:32:07 +08:00
    不能
    (理论可以通过动态分析bytecode完成(恩 我没测试过
    arbipher
        2
    arbipher  
       2015-05-21 10:34:55 +08:00   ❤️ 1
    被什么函数调用可以知道,参考
    https://docs.python.org/2/library/inspect.html
    http://stackoverflow.com/questions/900392/getting-the-caller-function-name-inside-another-function-in-python

    第几次被调用据我所知没有,等大神来回答吧。你加个count或者用闭包试试。
    vicalloy
        3
    vicalloy  
       2015-05-21 10:36:20 +08:00
    我觉得你还是给foo加个参数吧
    zerh925
        4
    zerh925  
    OP
       2015-05-21 10:36:39 +08:00
    刚dir了一下任意函数,发现一个func_name属性。通过传这个参数给foo()算是实现了。
    ```python
    def foo(outer):
    print "I was called by ", outer

    def bar():
    foo(bar.func_name)

    def run():
    foo(run.func_name)
    ```

    还有更好的办法吗?
    9hills
        5
    9hills  
       2015-05-21 10:37:51 +08:00   ❤️ 1
    https://gist.github.com/ninehills/9917858

    不仅能知道是谁调用的,还会打印出调用链。debug用
    zerh925
        6
    zerh925  
    OP
       2015-05-21 10:38:20 +08:00
    @arbipher 感谢!非常有用!刚在打自己的答案
    9hills
        7
    9hills  
       2015-05-21 10:38:42 +08:00   ❤️ 1
    效果如下:
    $ python test.py
    2014-04-02 00:40:44,273 [test.py:main() --> test.py:test('aaa')] hahha aaa
    muzuiget
        8
    muzuiget  
       2015-05-21 10:39:50 +08:00   ❤️ 1
    可以的,用这个模块 https://docs.python.org/2/library/traceback.html

    我最常用的

    import traceback; traceback.print_stack()

    打印当前的调用栈,其实就是相当于出现错误时的信息。
    songco
        9
    songco  
       2015-05-21 12:25:18 +08:00
    支持stacktrace的都可以把...
    recall704
        10
    recall704  
       2015-05-21 13:20:48 +08:00
    就二楼哪个方法吧,之前也是用的那个方式.
    alexapollo
        11
    alexapollo  
       2015-05-21 14:24:15 +08:00   ❤️ 2
    每个语言的月经贴。记住关键字:stacktrace/backtrace,加上语言python/c/java,google一搜就有。

    授人以渔!
    monkeylyf
        12
    monkeylyf  
       2015-05-21 15:10:46 +08:00
    >>> import inspect
    >>> inspect.stack()
    staticor
        13
    staticor  
       2015-05-21 15:52:01 +08:00   ❤️ 1
    我以前在leetcode还是codewars好像见过类似的统计函数被第几次调用的 提供一个可能有帮助的代码

    ![](http://7xivqr.com1.z0.glb.clouddn.com/15-5-21/88924102.jpg)
    staticor
        14
    staticor  
       2015-05-21 15:57:54 +08:00
    WKPlus
        15
    WKPlus  
       2015-05-21 18:17:53 +08:00   ❤️ 1
    查找caller上面很多人说过了,我用过一个方法来统计这个函数被调用多少次:

    def foo(called=[0]):
    called[0] += 1 # called[0]记录了foo被调用了多少次
    #your code here


    总算发现了python函数default值这个坑的第二个用法了:)

    当然也可以用函数属性来完成这个工作,不过要在foo函数定义之外再初始化一次这个属性,感觉没上面的代码好玩~
    zerh925
        16
    zerh925  
    OP
       2015-05-22 06:29:03 +08:00
    @WKPlus nice trick!
    jedihy
        17
    jedihy  
       2015-05-22 08:53:18 +08:00
    几乎所有语言都能打调用栈啊
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   945 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 20:24 · PVG 04:24 · LAX 12:24 · JFK 15:24
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.