Python函數func的信息可以通過func.func_*和func.func_code來獲取
一、先看看它們的應用吧:
1.獲取原函數名稱:
1 >>> def yes():pass 2 3 >>> a=yes 4 >>> a.func_name 5 'yes' 6 >>>
2.獲取函數的flags【后面有用,先說這個】
[python docs]:The following flag bits are defined for co_flags: bit 0x04 is set if the function uses the *arguments syntax to accept an arbitrary number of positional arguments; bit 0x08 is set if the function uses the **keywords syntax to accept arbitrary keyword arguments; bit 0x20 is set if the function is a generator.
由這段Python官方文檔可知,函數的flags與參數的定義方式有關,看看下面的試驗:
>>> def yes():pass >>> yes.func_code.co_flags 67 >>> def yes(a):pass >>> yes.func_code.co_flags 67 >>> def yes(a,b=3):pass >>> yes.func_code.co_flags 67 >>> def yes(*args):pass >>> yes.func_code.co_flags 71 >>> def yes(a,*args):pass >>> yes.func_code.co_flags 71 >>> def yes(a,b=32,*args):pass >>> yes.func_code.co_flags 71 >>> def yes(*args,**kw):pass >>> yes.func_code.co_flags 79 >>> def yes(a,*args,**kw):pass >>> yes.func_code.co_flags 79 >>> def yes(a,b=3,*args,**kw):pass >>> yes.func_code.co_flags 79 >>> def yes(**kw):pass >>> yes.func_code.co_flags 75 >>> def yes(a,**kw):pass >>> yes.func_code.co_flags 75 >>> def yes(a,b=1,**kw):pass >>> yes.func_code.co_flags 75 >>> >>> yes=(x for x in range(100)) >>> yes <generator object <genexpr> at 0x0000000002FF22D0> >>> [x for x in dir(yes) if not x.startswith('_')] ['close', 'gi_code', 'gi_frame', 'gi_running', 'next', 'send', 'throw'] >>> dir(yes) ['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'next', 'send', 'throw'] >>> dir(yes.gi_code) ['__class__', '__cmp__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames'] >>> [x for x in dir(yes.gi_code) if x.startswith('co_')] ['co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames'] >>> yes.gi_code.co_flags 99 >>> yes.next() 0 >>> yes.next() 1 >>> yes.gi_code.co_varnames ('.0', 'x') >>> for name in [x for x in dir(yes.gi_code) if x.startswith('co_')]: print 'yes.gi_code.%s = %r'%(name,eval('yes.gi_code.%s'%name)) yes.gi_code.co_argcount = 1 yes.gi_code.co_cellvars = () yes.gi_code.co_code = '|\x00\x00]\x0b\x00}\x01\x00|\x01\x00V\x01q\x03\x00d\x00\x00S' yes.gi_code.co_consts = (None,) yes.gi_code.co_filename = '<pyshell#46>' yes.gi_code.co_firstlineno = 1 yes.gi_code.co_flags = 99 yes.gi_code.co_freevars = () yes.gi_code.co_lnotab = '\x06\x00' yes.gi_code.co_name = '<genexpr>' yes.gi_code.co_names = () yes.gi_code.co_nlocals = 2 yes.gi_code.co_stacksize = 2 yes.gi_code.co_varnames = ('.0', 'x') >>>
【1】function沒有*args或**kw時,func.func_code.co_flags=67;
【2】function有*args沒有**kw時,func.func_code.co_flags=71;
【3】function沒有*args有**kw時,func.func_code.co_flags=75;
【4】function既有*args也有**kw時,func.func_code.co_flags=79;
【5】function是一個generator時,func.gi_code.co_flags=99.
3.獲取func函數的所有位置參數的個數:
func.func_code.co_argcount
4.獲取func函數簽名:
[1]callable(func),True=>function,False=>generator
[2]func的定義的所有位置參數變量名:pVars=func.func_code.co_varnames[:func.func_code.co_argcount]
[3]func的默認參數及默認值:func.func_defaults
[4]func的所有帶默認值的參數的參數名:dVars=pVars[-len(func.func_defaults):]【當然首先要判斷func.func_defaults=?=None】
[5]根據func.func_code.co_flags來判斷有無帶星號的參數,按照上面的判定規則:
a.如果func.func_code.co_flags==67,無帶星號的參數;
b.如果func.func_code.co_flags==71,只有帶一個星號的參數,它的參數名是func.func_code.co_varnames[func.func_code.co_argcount]
c.如果func.func_code.co_flags==75,只有帶兩個星號的參數,它的參數名是func.func_code.co_varnames[func.func_code.co_argcount]
d. 如果func.func_code.co_flags==79,有兩個帶星號的參數,它們的參數名是 func.func_code.co_varnames[func.func_code.co_argcount:func.func_code.co_argcount+2], 其中第一個是帶一個星號的,第二個是帶兩個星號的
因為:
1 >>> def yes(**kw,*args):pass 2 SyntaxError: invalid syntax 3 >>>
故如此。到此,func函數的函數簽名就可以被還原了。
二、func.func_*
1.func.func_closure:
2.func.func_code:詳見下面第三條
3.func.func_defaults:tuple=>func函數的參數中的所有默認值
4.func.func_dict
5.func.func_doc:str=>func函數的文檔字符串
6.func.func_globals:dict=>func函數的全局環境
7.func.func_name:str=>func函數的函數名
三、func.func_code【翻譯有不周之處請指正】
1.func.func_code.co_argcount:co_argcount is the number of positional arguments (including arguments with default values);
int=>func函數的位置參數的個數,實際上python函數定義時定義的前面不加星號的所有參數都是位置參數,我們所說的關鍵字參數只是調用時候的說法。
2.func.func_code.co_cellvars:co_cellvars is a tuple containing the names of local variables that are referenced by nested functions;
tuple=>func函數中所有被其嵌套函數引用了的func函數的局部變量
3.func.func_code.co_code:co_code is a string representing the sequence of bytecode instructions;
str=>func函數的編譯后的字節碼
4.func.func_code.co_consts:co_consts is a tuple containing the literals used by the bytecode;
tuple=>func函數中的所有常量,如0,True,'',None
5.func.func_code.co_filename:co_filename is the filename from which the code was compiled;
str=>func函數的定義所在的源文件路徑
6.func.func_code.co_firstlineno:co_firstlineno is the first line number of the function;
int=>func函數的定義在其源文件中的第一行的行號
7.func.func_code.co_flags:co_flags is an integer encoding a number of flags for the interpreter;
int=>func函數參數傳遞方式的編碼,比如*args,**kw等形式
8.func.func_code.co_freevars:co_freevars is a tuple containing the names of free variables;
tuple=>func函數中所有的自由變量的名稱
9.func.func_code.co_lnotab:co_lnotab is a string encoding the mapping from bytecode offsets to line numbers (for details see the source code of the interpreter);
10.func.func_code.co_name:co_name gives the function name;
str=>func函數的名稱
11.func.func_code.co_names:co_names is a tuple containing the names used by the bytecode;
tuple=>func函數中所有的被字節碼使用到的名稱,比如模塊名,方法名等
12.func.func_code.co_nlocals:co_nlocals is the number of local variables used by the function (including arguments);
int=>func函數用到的局部變量的數目(包括參數)
13.func.func_code.co_stacksize:co_stacksize is the required stack size (including local variables);
func函數所需的堆棧大小(包括所有局部變量)
14.func.func_code.co_varnames:co_varnames is a tuple containing the names of the local variables (starting with the argument names);
tuple=>func函數中所有使用到的local variables的名稱,參數按順序排在最前面,其它的按在代碼中出現的順序排列;
四、看下面的一個實驗:
1 #coding=utf-8 2 import os,sys 3 4 def decorator(printResult=False): 5 def _decorator(func): 6 name=func.func_name 7 print '%s() was post to _decorator()'%name 8 def __decorator(*args,**kw): 9 print 'Call the function %s() in __decorator().'%\ 10 func.func_name 11 if printResult: 12 print func(*args,**kw),'#print in __decorator().' 13 else: 14 return func(*args,**kw) 15 return __decorator 16 return _decorator 17 18 def GetRandName(length,isVar=False): 19 u'''Get random name with string.letters+'_'+string.digits 20 21 length=>The length of name. 22 isVar=>The name must be a varname. 23 ''' 24 varName,chars=[],string.letters+'_'+string.digits 25 if isVar: 26 varName.append(chars[:53][random.randint(0,52)]) 27 length-=1 28 for i in range(length): 29 varName.append(chars[random.randint(0,62)]) 30 varName=''.join(varName) 31 return varName 32 33 def func_info(func): 34 print '%s() information:'%func.func_name 35 for name in [x for x in dir(func) if x.startswith('func_')]: 36 print '%s.%s = %r'%(func.func_name,name, 37 eval('%s.%s'%(func.func_name,name))) 38 for name in [x for x in dir(func.func_code) if x.startswith('co_')]: 39 print '%s.func_code.%s = %r'%(func.func_name,name, 40 eval('%s.func_code.%s'%(func.func_name,name))) 41 #輸出GetRandName()函數的信息 42 func_info(GetRandName) 43 print '-'*80 44 #輸出decorator()函數的信息 45 func_info(decorator) 46 print '-'*80 47 #將GetRandName函數用裝飾器先裝飾一下 48 GetRandName=decorator(True)(GetRandName) 49 #裝飾后GetRandName變成__decorator()函數 50 print 'GetRandName=%r'%GetRandName 51 #輸出此時的GetRandName即__decorator()函數的信息 52 print '%s() information:'%GetRandName.func_name 53 for name in [x for x in dir(GetRandName) if x.startswith('func_')]: 54 print '%s.%s = %r'%(GetRandName.func_name,name, 55 eval('GetRandName.%s'%name)) 56 for name in [x for x in dir(GetRandName.func_code) if x.startswith('co_')]: 57 print '%s.func_code.%s = %r'%(GetRandName.func_name,name, 58 eval('GetRandName.func_code.%s'%name))
運行結果:
1 Python 2.7.8 (default, Jun 30 2014, 16:08:48) [MSC v.1500 64 bit (AMD64)] on win32 2 Type "copyright", "credits" or "license()" for more information. 3 >>> ================================ RESTART ================================ 4 >>> 5 GetRandName() information: 6 GetRandName.func_closure = None 7 GetRandName.func_code = <code object GetRandName at 0000000002107F30, file "E:\文檔\程序庫\Python程序\func_information.py", line 18> 8 GetRandName.func_defaults = (False,) 9 GetRandName.func_dict = {} 10 GetRandName.func_doc = u"Get random name with string.letters+'_'+string.digits\n\n length=>The length of name.\n isVar=>The name must be a varname.\n " 11 GetRandName.func_globals = {'__builtins__': <module '__builtin__' (built-in)>, '__file__': 'E:\\\xce\xc4\xb5\xb5\\\xb3\xcc\xd0\xf2\xbf\xe2\\Python\xb3\xcc\xd0\xf2\\func_information.py', 'func_info': <function func_info at 0x0000000002BDD3C8>, '__package__': None, 'sys': <module 'sys' (built-in)>, '__name__': '__main__', 'GetRandName': <function GetRandName at 0x0000000002BE0D68>, 'os': <module 'os' from 'D:\Python27\lib\os.pyc'>, '__doc__': None, 'decorator': <function decorator at 0x00000000021199E8>} 12 GetRandName.func_name = 'GetRandName' 13 GetRandName.func_code.co_argcount = 2 14 GetRandName.func_code.co_cellvars = () 15 GetRandName.func_code.co_code = 'g\x00\x00t\x00\x00j\x01\x00d\x01\x00\x17t\x00\x00j\x02\x00\x17\x02}\x02\x00}\x03\x00|\x01\x00rO\x00|\x02\x00j\x03\x00|\x03\x00d\x02\x00 t\x04\x00j\x05\x00d\x03\x00d\x04\x00\x83\x02\x00\x19\x83\x01\x00\x01|\x00\x00d\x05\x008}\x00\x00n\x00\x00x1\x00t\x06\x00|\x00\x00\x83\x01\x00D]#\x00}\x04\x00|\x02\x00j\x03\x00|\x03\x00t\x04\x00j\x05\x00d\x03\x00d\x06\x00\x83\x02\x00\x19\x83\x01\x00\x01q\\\x00Wd\x07\x00j\x07\x00|\x02\x00\x83\x01\x00}\x02\x00|\x02\x00S' 16 GetRandName.func_code.co_consts = (u"Get random name with string.letters+'_'+string.digits\n\n length=>The length of name.\n isVar=>The name must be a varname.\n ", '_', 53, 0, 52, 1, 62, '') 17 GetRandName.func_code.co_filename = 'E:\\\xce\xc4\xb5\xb5\\\xb3\xcc\xd0\xf2\xbf\xe2\\Python\xb3\xcc\xd0\xf2\\func_information.py' 18 GetRandName.func_code.co_firstlineno = 18 19 GetRandName.func_code.co_flags = 67 20 GetRandName.func_code.co_freevars = () 21 GetRandName.func_code.co_lnotab = '\x00\x06\x1b\x01\x06\x01!\x01\r\x01\x13\x01!\x01\x0f\x01' 22 GetRandName.func_code.co_name = 'GetRandName' 23 GetRandName.func_code.co_names = ('string', 'letters', 'digits', 'append', 'random', 'randint', 'range', 'join') 24 GetRandName.func_code.co_nlocals = 5 25 GetRandName.func_code.co_stacksize = 6 26 GetRandName.func_code.co_varnames = ('length', 'isVar', 'varName', 'chars', 'i') 27 -------------------------------------------------------------------------------- 28 decorator() information: 29 decorator.func_closure = None 30 decorator.func_code = <code object decorator at 0000000002107AB0, file "E:\文檔\程序庫\Python程序\func_information.py", line 4> 31 decorator.func_defaults = (False,) 32 decorator.func_dict = {} 33 decorator.func_doc = None 34 decorator.func_globals = {'__builtins__': <module '__builtin__' (built-in)>, '__file__': 'E:\\\xce\xc4\xb5\xb5\\\xb3\xcc\xd0\xf2\xbf\xe2\\Python\xb3\xcc\xd0\xf2\\func_information.py', 'func_info': <function func_info at 0x0000000002BDD3C8>, '__package__': None, 'sys': <module 'sys' (built-in)>, '__name__': '__main__', 'GetRandName': <function GetRandName at 0x0000000002BE0D68>, 'os': <module 'os' from 'D:\Python27\lib\os.pyc'>, '__doc__': None, 'decorator': <function decorator at 0x00000000021199E8>} 35 decorator.func_name = 'decorator' 36 decorator.func_code.co_argcount = 1 37 decorator.func_code.co_cellvars = ('printResult',) 38 decorator.func_code.co_code = '\x87\x00\x00f\x01\x00d\x01\x00\x86\x00\x00}\x01\x00|\x01\x00S' 39 decorator.func_code.co_consts = (None, <code object _decorator at 0000000002107830, file "E:\文檔\程序庫\Python程序\func_information.py", line 5>) 40 decorator.func_code.co_filename = 'E:\\\xce\xc4\xb5\xb5\\\xb3\xcc\xd0\xf2\xbf\xe2\\Python\xb3\xcc\xd0\xf2\\func_information.py' 41 decorator.func_code.co_firstlineno = 4 42 decorator.func_code.co_flags = 3 43 decorator.func_code.co_freevars = () 44 decorator.func_code.co_lnotab = '\x00\x01\x0f\x0b' 45 decorator.func_code.co_name = 'decorator' 46 decorator.func_code.co_names = () 47 decorator.func_code.co_nlocals = 2 48 decorator.func_code.co_stacksize = 2 49 decorator.func_code.co_varnames = ('printResult', '_decorator') 50 -------------------------------------------------------------------------------- 51 GetRandName() was post to _decorator() 52 GetRandName=<function __decorator at 0x0000000002BDD4A8> 53 __decorator() information: 54 __decorator.func_closure = (<cell at 0x0000000002BF18E8: function object at 0x0000000002BE0D68>, <cell at 0x0000000002BF1828: bool object at 0x000000001E284280>) 55 __decorator.func_code = <code object __decorator at 0000000002124030, file "E:\文檔\程序庫\Python程序\func_information.py", line 8> 56 __decorator.func_defaults = None 57 __decorator.func_dict = {} 58 __decorator.func_doc = None 59 __decorator.func_globals = {'name': 'func_globals', '__builtins__': <module '__builtin__' (built-in)>, '__file__': 'E:\\\xce\xc4\xb5\xb5\\\xb3\xcc\xd0\xf2\xbf\xe2\\Python\xb3\xcc\xd0\xf2\\func_information.py', 'func_info': <function func_info at 0x0000000002BDD3C8>, '__package__': None, 'sys': <module 'sys' (built-in)>, 'x': 'func_name', '__name__': '__main__', 'GetRandName': <function __decorator at 0x0000000002BDD4A8>, 'os': <module 'os' from 'D:\Python27\lib\os.pyc'>, '__doc__': None, 'decorator': <function decorator at 0x00000000021199E8>} 60 __decorator.func_name = '__decorator' 61 __decorator.func_code.co_argcount = 0 62 __decorator.func_code.co_cellvars = () 63 __decorator.func_code.co_code = "d\x01\x00\x88\x00\x00j\x00\x00\x16GH\x88\x01\x00r'\x00\x88\x00\x00|\x00\x00|\x01\x00\x8e\x00\x00Gd\x02\x00GHn\r\x00\x88\x00\x00|\x00\x00|\x01\x00\x8e\x00\x00Sd\x00\x00S" 64 __decorator.func_code.co_consts = (None, 'Call the function %s() in __decorator().', '#print in __decorator().') 65 __decorator.func_code.co_filename = 'E:\\\xce\xc4\xb5\xb5\\\xb3\xcc\xd0\xf2\xbf\xe2\\Python\xb3\xcc\xd0\xf2\\func_information.py' 66 __decorator.func_code.co_firstlineno = 8 67 __decorator.func_code.co_flags = 31 68 __decorator.func_code.co_freevars = ('func', 'printResult') 69 __decorator.func_code.co_lnotab = '\x00\x01\x03\x01\t\x01\x06\x01\x15\x02' 70 __decorator.func_code.co_name = '__decorator' 71 __decorator.func_code.co_names = ('func_name',) 72 __decorator.func_code.co_nlocals = 2 73 __decorator.func_code.co_stacksize = 3 74 __decorator.func_code.co_varnames = ('args', 'kw') 75 >>>