【问题标题】:How to determine file, function and line number?如何确定文件、函数和行号?
【发布时间】:2011-10-12 06:21:43
【问题描述】:

在 C++ 中,我可以像这样打印调试输出:

printf(
   "FILE: %s, FUNC: %s, LINE: %d, LOG: %s\n",
   __FILE__,
   __FUNCTION__,
   __LINE__,
   logmessage
);

如何在 Python 中做类似的事情?

【问题讨论】:

  • 你总是这样打印错误日志?这很了不起,因为 C++ 中没有 print 函数。
  • @Tomalak 错字,现在在 python 线程中。 :)
  • 一旦你使用 Python,你就再也回不去了(很多)。

标签: python


【解决方案1】:

有一个名为inspect 的模块提供这些信息。

示例用法:

import inspect

def PrintFrame():
  callerframerecord = inspect.stack()[1]    # 0 represents this line
                                            # 1 represents line at caller
  frame = callerframerecord[0]
  info = inspect.getframeinfo(frame)
  print(info.filename)                      # __FILE__     -> Test.py
  print(info.function)                      # __FUNCTION__ -> Main
  print(info.lineno)                        # __LINE__     -> 13

def Main():
  PrintFrame()                              # for this line

Main()

但是,请记住,有一种更简单的方法可以获取当前正在执行的文件的名称:

print(__file__)

【讨论】:

    【解决方案2】:

    例如

    import inspect
    frame = inspect.currentframe()
    # __FILE__
    fileName  =  frame.f_code.co_filename
    # __LINE__
    fileNo = frame.f_lineno
    

    这里还有更多http://docs.python.org/library/inspect.html

    【讨论】:

    • 还有一个简单的获取fileNo的方法:fileNo = frame.f_lineno
    【解决方案3】:

    基于 geowar 的回答:

    class __LINE__(object):
        import sys
    
        def __repr__(self):
            try:
                raise Exception
            except:
                return str(sys.exc_info()[2].tb_frame.f_back.f_lineno)
    
    __LINE__ = __LINE__()
    

    如果您通常想在例如使用__LINE__ print(或任何其他时间隐含的str()repr()),以上将允许您省略()s。

    (添加__call__ 的明显扩展名作为练习给读者。)

    【讨论】:

    • 为什么将return 语句打包在一个琐碎的(阅读:始终打开)try-raise-except 三元组中?
    • @Whaa,而不是什么?我刚刚提出的return 检查异常,作为获取堆栈的一种方法。大概这不是唯一的方法,但至少 Tugrul Ates 似乎(稍微)更复杂,并且需要使用较少的import
    • 明白。我错过了使用 Python 愚蠢的隐式异常信息机制。
    【解决方案4】:

    你可以参考我的回答: https://stackoverflow.com/a/45973480/1591700

    import sys
    print sys._getframe().f_lineno
    

    你也可以制作 lambda 函数

    【讨论】:

      【解决方案5】:

      哇,7岁的问题:)

      无论如何,采用 ​​Tugrul 的答案,并将其写为 debug 类型的方法,它可能看起来像:

      def debug(message):
          import sys
          import inspect
          callerframerecord = inspect.stack()[1]
          frame = callerframerecord[0]
          info = inspect.getframeinfo(frame)
          print(info.filename, 'func=%s' % info.function, 'line=%s:' % info.lineno, message)
      
      def somefunc():
          debug('inside some func')
      
      debug('this')
      debug('is a')
      debug('test message')
      somefunc()
      

      输出:

      /tmp/test2.py func=<module> line=12: this
      /tmp/test2.py func=<module> line=13: is a
      /tmp/test2.py func=<module> line=14: test message
      /tmp/test2.py func=somefunc line=10: inside some func
      

      【讨论】:

        【解决方案6】:

        我也对 python 中的 __LINE__ 命令感兴趣。 我的出发点是https://stackoverflow.com/a/6811020,我用元类对象对其进行了扩展。通过此修改,它具有与 C++ 中相同的行为。

        import inspect
        
        class Meta(type):
            def __repr__(self):
                # Inspiration: https://stackoverflow.com/a/6811020
                callerframerecord = inspect.stack()[1]  # 0 represents this line
                # 1 represents line at caller
                frame = callerframerecord[0]
                info = inspect.getframeinfo(frame)
                # print(info.filename)  # __FILE__     -> Test.py
                # print(info.function)  # __FUNCTION__ -> Main
                # print(info.lineno)  # __LINE__     -> 13
                return str(info.lineno)
        
        class __LINE__(metaclass=Meta):
            pass
        
        print(__LINE__)  # print for example 18
        

        【讨论】:

          【解决方案7】:
          import inspect
              .
              .
              .
          def __LINE__():
              try:
                  raise Exception
              except:
                  return sys.exc_info()[2].tb_frame.f_back.f_lineno
          
          def __FILE__():
              return inspect.currentframe().f_code.co_filename
              .
              .
              .
          print "file: '%s', line: %d" % (__FILE__(), __LINE__())
          

          【讨论】:

            【解决方案8】:

            在 Python 中获取行号而不导入整个 sys 模块...

            首先导入_getframe子模块:

            from sys import _getframe
            

            然后调用_getframe 函数并在您想知道行号时使用它的f_lineno 属性:

            print(_getframe().f_lineno)  # prints the line number
            

            来自解释器:

            >>> from sys import _getframe
            ... _getframe().f_lineno  # 2
            

            来自官方 Python 文档的警告:

            CPython 实现细节:此函数应仅用于内部和专用目的。不保证在 Python 的所有实现中都存在。

            换句话说:仅将此代码用于个人测试/调试原因。

            有关 sys 模块和 _getframe() 函数/子模块的更多信息,请参阅sys._getframe 上的官方 Python 文档。

            基于Mohammad Shahid's answer(上图)。

            【讨论】:

              【解决方案9】:

              这是一个tool 来回答这个古老而新的问题! 我推荐使用icecream

              您曾经使用 print() 或 log() 来调试您的代码吗?当然,你 做。 IceCream,或简称 ic,让打印调试变得更甜。

              ic() 类似于print(),但更好:

              1. 它会打印表达式/变量名称及其值。
              2. 打字速度提高了 40%。
              3. 数据结构印刷精美。
              4. 输出突出显示语法。
              5. 它可选地包括程序上下文:文件名、行号和父函数。

              例如,我创建了一个模块icecream_test.py,并将以下代码放入其中。

              from icecream import ic
              ic.configureOutput(includeContext=True)
              def foo(i):
                  return i + 333
              
              ic(foo(123))
              

              打印

              ic| icecream_test.py:6 in <module>- foo(123): 456
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2021-03-25
                • 2019-07-09
                • 1970-01-01
                • 2014-01-28
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多