python 获取类名和函数名

本文主要介绍了python 动态获取当前运行的类名和函数名的方法,

分别介绍使用内置方法、sys模块、修饰器、inspect模块等方法。


一、使用内置方法和修饰器方法获取类名、函数名

python中获取函数名的情况分为内部、外部

1、从函数外部获取函数名

使用指向函数的对象,然后用__name__属性

defa():

    pass

a.__name__

除此之外还可以:

getattr(a,'__name__')

a.__getattribute__('__name__')

完整示例:

def a():

    print("hello, l love u")


print(a.__name__)

print(a.__getattribute__('__name__'))

print(getattr(a,'__name__'))

尽管有些脱裤子放屁,总之,从外部获取的方法是非常灵活的。


2、从函数内部获取函数名

需要用些技巧

1)使用sys模块的方法:(推荐)

defa():

printsys._getframe().f_code.co_name

f_code 和 co_name 可以参考python源码解析的pyc生成和命名空间章节。

2)使用修饰器的方法: (推荐)

使用修饰器就可以对函数指向一个变量,然后取变量对象的__name__方法。

deftimeit(func):

defrun(*argv):

   printfunc.__name__

   ifargv:

    ret =func(*argv)

   else:

    ret =func()

   returnret

returnrun


@timeit

deft(a):

printa 

t(1)


修饰器的改进版:

使用修饰器就可以对函数指向一个变量,然后取变量对象的__name__方法。

defget_name(func):

    defwarper(*args, **kwargs):

        print("the function name is {}".format(func.__name__))

        result =func(*args, **kwargs)       

        returnresult   

    returnwarper


@get_name

defmy_name():

    print("hello")

@get_name

defyour_name(name):

    print("hello {}".format(name))


my_name()

your_name("mimvp.com")

运行结果:

the function name is my_name

hello

the function name is your_name

hello mimvp.com


二、使用inspect模块动态获取当前运行的函数名

importinspect


defget_current_function_name():

    returninspect.stack()[1][3]

classMyClass:

    deffunction_one(self):

        print"%s.%s invoked"%(self.__class__.__name__, get_current_function_name())

if__name__ =="__main__":

    myclass =MyClass()

    myclass.function_one()

动态获取当前运行的函数名很方便,特别是对于一些debug系统来说


完整示例:

def timeit(func):

    def run(*argv):

        print("timeit: %s"% (func.__name__))   # timeit: func

        ifargv:

            ret = func(*argv)

        else:

            ret = func()

        returnret

    returnrun


# @timeit

def func():

    print("self name: %s"% (sys._getframe().f_code.co_name))   # self name: func


importinspect

def get_current_function_name():

    returninspect.stack()[1][3]

class MyClass:

    def function_one(self):

        print("%s.%s invoked"% (self.__class__.__name__, get_current_function_name()))     # MyClass.function_one invoked



if__name__ == '__main__':

    print("%s : __main___"% (__file__.split(MIMVP_PROJECT_NAME)[1]))       # /common/mimvptech.py : __main___


    print("func.name: %s , getattr(a,'__name__'): %s"% (func.__name__, getattr(func, '__name__')))     # func.name: func , getattr(a,'__name__'): func


    func()


    myclass = MyClass()

    myclass.function_one()

运行结果:

/common/mimvptech.py : __main___

func.name: func , getattr(a,'__name__'): func

self name: func

MyClass.function_one invoked



知识拓展与思考

Python中没办法直接取得当前的行号和函数名,不像C++和PHP中的 __FILE__,__LINE__,__FUNC__,__FUNCTION__

如果一个函数在不知道自己名字的情况下,怎么才能递归调用自己,获取类名、函数名。

从python的logging模块说起,logging中的format中是有如下选项的:

%(name)s            Name of the logger (logging channel)

%(levelno)s         Numeric logging level forthe message (DEBUG, INFO,

                    WARNING, ERROR, CRITICAL)

%(levelname)s       Text logging level forthe message ("DEBUG", "INFO",

                    "WARNING", "ERROR", "CRITICAL")

%(pathname)s        Full pathname of the source filewhere the logging

                    call was issued (ifavailable)

%(filename)s        Filename portion of pathname

%(module)s          Module (name portion of filename)

%(lineno)d          Source line number where the logging call was issued

                    (ifavailable)

%(funcName)s        Function name

%(created)f         Time when the LogRecord was created (time.time()

                    returnvalue)

%(asctime)s         Textual time when the LogRecord was created

%(msecs)d           Millisecond portion of the creation time

%(relativeCreated)d Time inmilliseconds when the LogRecord was created,

                    relative to the time the logging module was loaded

                    (typically at application startup time)

%(thread)d          Thread ID(ifavailable)

%(threadName)s      Thread name (ifavailable)

%(process)d         Process ID(ifavailable)

%(message)s         The result of record.getMessage(), computed just as

                    the record isemitted

也就是说,logging是能够获取到调用者的行号和函数名的,那会不会也可以获取到自己的行号和函数名呢?

我们来看一下源码,主要部分如下:

defcurrentframe():

    """Return the frame object for the caller's stack frame."""

    try:

        raiseException

    except:

        returnsys.exc_info()[2].tb_frame.f_back

deffindCaller(self):

    """

    Find the stack frame of the caller so that we can note the source

    file name, line number and function name.

    """

    f =currentframe()

    #On some versions of IronPython, currentframe() returns None if

    #IronPython isn't run with -X:Frames.

    iff isnotNone:

        f =f.f_back

    rv ="(unknown file)", 0, "(unknown function)"

    whilehasattr(f, "f_code"):

        co =f.f_code

        filename =os.path.normcase(co.co_filename)

        iffilename ==_srcfile:

            f =f.f_back

            continue

        rv =(co.co_filename, f.f_lineno, co.co_name)

        break

    returnrv

def_log(self, level, msg, args, exc_info=None, extra=None):

    """

    Low-level logging routine which creates a LogRecord and then calls

    all the handlers of this logger to handle the record.

    """

    if_srcfile:

        #IronPython doesn't track Python frames, so findCaller throws an

        #exception on some versions of IronPython. We trap it here so that

        #IronPython can use logging.

        try:

            fn, lno, func =self.findCaller()

        exceptValueError:

            fn, lno, func ="(unknown file)", 0, "(unknown function)"

    else:

        fn, lno, func ="(unknown file)", 0, "(unknown function)"

    ifexc_info:

        ifnotisinstance(exc_info, tuple):

            exc_info =sys.exc_info()

    record =self.makeRecord(self.name, level, fn, lno, msg, args, exc_info, func, extra)

    self.handle(record)

简单解释一下,实际上是通过在currentframe函数中抛出一个异常,然后通过向上查找的方式,找到调用的信息。其中

rv = (co.co_filename, f.f_lineno, co.co_name)

上面三个值分别为文件名,行号,函数名。

可以去sys— System-specific parameters and functions来看一下代码中几个系统函数的说明

OK,如果已经看懂了源码,那获取当前位置的行号和函数名相信也非常清楚了,代码如下:

#!/usr/bin/python

# -*- coding: utf-8 -*-

'''

#=============================================================================

#  Author:          dantezhu - https://www.vimer.cn

#  Email:           zny2008@gmail.com

#  FileName:        xf.py

#  Description:     获取当前位置的行号和函数名

#  Version:         1.0

#  LastChange:      2010-12-17 01:19:19

#  History:        

#=============================================================================

'''

importsys

defget_cur_info():

    """Return the frame object for the caller's stack frame."""

    try:

        raiseException

    except:

        f =sys.exc_info()[2].tb_frame.f_back

    return(f.f_code.co_name, f.f_lineno)


defcallfunc():

    printget_cur_info()



if__name__ =='__main__':

    callfunc()

输入结果是:

('callfunc', 24)

符合预期!哈哈,OK!

现在应该不用再抱怨取不到行号和函数名了吧


其实,Python获取函数名、行号,也可以有更简单的方法,如下:

importsys

defget_cur_info():

    printsys._getframe().f_code.co_name

    printsys._getframe().f_back.f_code.co_name

get_cur_info()

调用结果是:

get_cur_info


另外,利用python的 inspect 模块中的 getframeinfo 也可以得到.

inspect.getframeinfo(frame[,context])

Get information about a frame or traceback object. A 5-tuple is returned, the last five elements of the frame’s frame record.Changed in version 2.6: Returns anamed tupleTraceback(filename, lineno, function,code_context, index).


参考推荐:

Python 装饰器之简易教程

Python 之 decorator 装饰器

Tornado 实现web网页爬虫

Linux Shell 脚本获取当前目录和文件夹名

Shell 参数含义 $0、$1、$2、${n}、$#、$@、$*、$?、 $_、$!、$$

Java 反射调用(Reflect)方法

Python urllib2.URLError: urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590)


转载自:https://blog.mimvp.com/article/7218.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容