스크립트 프로그래밍을 하다보면 간혹 콜러를 알기 위해 콜스택에 접근해야할 경우가 있습니다.
import sys
def func():
print sys._getframe().f_code.co_name
func()
python 에서는 위와 같이 콜스택의 현재 프레임에 접근해서 함수 이름을 얻어낼 수 있습니다.
콜러 함수 이름을 얻기 위해서는 sys._getframe().f_back 을 사용하거나
import sys
def func():
print sys._getframe().f_back.f_code.co_name
def func2():
func()
func2()
sys._getframe(1) 을 사용할 수 있습니다.
import sys
def func():
print sys._getframe(1).f_code.co_name
def func2():
func()
func2()
sys._getframe(n) 의 경우는 이미 눈치채셨겠지만
몇단계 전의 프레임을 얻어낼 때 사용합니다.
frame.f_code.co_name 는 무조건 함수 이름만을 얻어내기 때문에
클래스 인스턴스의 메소드 이름을 얻어내야 할 경우
메소드의 함수 이름은 알 수 있지만
어떤 클래스의 메소드인지는 알지 못합니다.
import sys
class Test:
def func(self):
print sys._getframe().f_back.f_code.co_name
def func2(self):
self.func()
t = Test()
t.func2()
결과
func2
파이썬 메소드 명칭을 정확히 얻어내기 위해서는
파이썬 메소드 호출 규약을 사용합니다.
파이썬에서는 0번째 인자로 self 를 넘겨주므로,
첫번째 인자로 어떤 클래스인지 알 수 있습니다.
frame = sys._getframe(n)
frameCode = frame.f_code
if frameCode.co_varnames:
firstVar = frame.f_locals.get(frameCode.co_varnames[0], None)
if firstVar:
firstVarClass = firstVar.__class__
해당 클래스내 frameCode.co_name 을 가진 메소드가 있는지 체크하고
만약 존재한다면 메소드가 가진 코드와 프레임 코드와 동일한가 체크하면
메소드 이름을 정확히 알아낼 수 있게 됩니다.
firstVarMethod = getattr(firstVarClass, frameCode.co_name)
if type(firstVarClass) is classobj:
if firstVarMethod and firstVarMethod.im_func.func_code== frameCode:
methodName = ".".join((str(firstVarClass), frameCode.co_name))
파이썬 콜스택 접근 기능을 이용하면 직접 로그 함수를 만들어 볼 수 있습니다.
more..
import sys
import os
import time
from new import classobj
INDENT = " "
POSITION_MAX = 15
FUNC_NAME_MAX = 20
FORMAT_TIME = "%y.%m.%d %H:%M:%S"
FORMAT_MSG = "%%s %%-%ds %%-%ds %%s %%s%%s\n" % (POSITION_MAX, FUNC_NAME_MAX)
LL_ERROR = 40
LL_WARNING = 30
LL_INFO = 20
LL_INFO2 = 19
LL_INFO3 = 18
LL_DEBUG = 10
logOut = sys.stdout
logErr = sys.stderr
logLevel = LL_DEBUG
logLevelNameDict = {
LL_ERROR : "E",
LL_WARNING : "W",
LL_INFO : "I",
LL_INFO2 : "I",
LL_INFO3 : "I",
LL_DEBUG : "D",
}
logLevelDisables = set()
def Log(lv, msg, depth=0):
if lv < logLevel:
return
if lv in logLevelDisables:
return
frame = sys._getframe(2)
frameCode = frame.f_code
lineNo = str(frame.f_lineno)
fileDir, fileName = os.path.split(frameCode.co_filename)
fileName = fileName[:POSITION_MAX-len(lineNo)]
position = ":".join((fileName, lineNo))
funcName = frameCode.co_name
if frameCode.co_varnames:
firstVar = frame.f_locals.get(frameCode.co_varnames[0], None)
if firstVar:
firstVarClass = firstVar.__class__
firstVarMethod = getattr(firstVarClass, frameCode.co_name)
if type(firstVarClass) is classobj:
if firstVarMethod and firstVarMethod.im_func.func_code== frameCode:
funcName = ".".join((str(firstVarClass), funcName))
funcName = funcName[-FUNC_NAME_MAX:]
try:
lvName = logLevelNameDict[lv]
except:
lvName = "LV%.3d" % (lvName)
logLevelNameDict[lv] = lvName
timeStamp = time.strftime(FORMAT_TIME)
outputMsg = FORMAT_MSG % (timeStamp, position, funcName, lvName, INDENT*depth, msg)
logOut.write(outputMsg)
if lv >= LL_ERROR:
logErr.write(m)
def ERROR(msg):
Log(LL_ERROR, msg)
def WARNING(msg):
Log(LL_WARN, msg)
def INFO3(msg):
Log(LL_INFO2, msg, 2)
def INFO2(msg):
Log(LL_INFO2, msg, 1)
def INFO(msg):
Log(LL_INFO, msg)
def DEBUG(msg):
Log(LL_DEBUG, msg)
def SetLevel(lv):
logLevel = lv
def Disable(lv):
logLevelDisables.add(lv)
헉헉-_-

(
0)

(
0)
http://imp17.com/tc/myevan/trackback/136