Logging method calls

از PyLearn.com، دانشنامهٔ آزاد.

پرش به: ناوبری, جستجو
این نوشته (Logging method calls) بخشی از نکته ها و ترفند ها می باشد .
کتاب پایتون ماژول ها و ابزار وابسته نمونه پروژه و برنامه پرسش و پاسخ


در مثال زیر با استفاده از مبحث meta class عملیات log کردن یک تابع یا توابع کلاس انجام می گیرد ! می توان با الهام از این کد و روش هایی شبیه به آن و با استفاده از مبحث meta class برنامه هایی را نوشت که قبل و بعد از اجرای تابع یا توابع کلاس خاص اجرا شده و دستورات و وظایف محوله را انجام دهند . در این مثال تابع method_ به همراه هر تابع در هنگام اجرا آن و نیز خاتمه آن اجرا می گردد و روند کار تابع را در فایل خارجی ثبت می کند ! این روش برای خطایابی و مشاهده نحوه کار توابع و مخصوصا توابه بازگشتی بسیار مفید می باشد .

import re

log = open('log','w')
indent = 0
indStr = '  '

def logmethod(methodname):
    def _method(self,*argl,**argd):
        global indent

        #parse the arguments and create a string representation
        args = []
        for item in argl:
            args.append('%s' % str(item))
        for key,item in argd.items():
            args.append('%s=%s' % (key,str(item)))
        argstr = ','.join(args)   
        print >> log,"%s%s.%s(%s) " % (indStr*indent,str(self),methodname,argstr)
        indent += 1
        # do the actual method call
        returnval = getattr(self,'_H_%s' % methodname)(*argl,**argd)
        indent -= 1
        print >> log,'%s:'% (indStr*indent), str(returnval)
        return returnval

    return _method


class LogTheMethods(type):
    def __new__(cls,classname,bases,classdict):
        logmatch = re.compile(classdict.get('logMatch','.*'))
        
        for attr,item in classdict.items():
            if callable(item) and logmatch.match(attr):
                classdict['_H_%s'%attr] = item    # rebind the method
                classdict[attr] = logmethod(attr) # replace method by wrapper

        return type.__new__(cls,classname,bases,classdict)

class Test(object):
    __metaclass__ = LogTheMethods
    logMatch = '.*'

    def __init__(self):
        self.a = 10

    def meth1(self):pass
    def add(self,a,b):return a+b
    def fac(self,val): # faculty calculation
        if val == 1:
            return 1
        else:
            return val * self.fac(val-1)

if __name__ == '__main__':
    l = Test()
    l.meth1()
    print l.add(1,2)
    print l.fac(10)

نمونه log فایل :

<__main__.Test object at 0xb7bb276c>.__init__() 
: None
<__main__.Test object at 0xb7bb276c>.meth1() 
: None
<__main__.Test object at 0xb7bb276c>.add(1,2) 
: 3
<__main__.Test object at 0xb7bb276c>.fac(10) 
  <__main__.Test object at 0xb7bb276c>.fac(9) 
    <__main__.Test object at 0xb7bb276c>.fac(8) 
      <__main__.Test object at 0xb7bb276c>.fac(7) 
        <__main__.Test object at 0xb7bb276c>.fac(6) 
          <__main__.Test object at 0xb7bb276c>.fac(5) 
            <__main__.Test object at 0xb7bb276c>.fac(4) 
              <__main__.Test object at 0xb7bb276c>.fac(3) 
                <__main__.Test object at 0xb7bb276c>.fac(2) 
                  <__main__.Test object at 0xb7bb276c>.fac(1) 
                  : 1
                : 2
              : 6
            : 24
          : 120
        : 720
      : 5040
    : 40320
  : 362880
: 3628800

در فایل log نام هر تابع ، مفدار ارسالی ، مقدار برگشتی ، آدرس حافظه و ... بصورت بسیار واضحی نمایش داده شده است