decorator question

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Schüle Daniel

    #1

    decorator question

    hello NG,

    consider this code
    [color=blue][color=green][color=darkred]
    >>> def timelogger(f):[/color][/color][/color]
    .... def wrapper(*a,**kw ):
    .... print "started at %s" % time.ctime()
    .... t0 = time.time()
    .... f(*a, **kw)
    .... t1 = time.time()
    .... print "ended at %s" % time.ctime()
    .... print "diff = ", t1-t0, "sec"
    .... return wrapper
    ....[color=blue][color=green][color=darkred]
    >>> import time
    >>> @timelogger[/color][/color][/color]
    .... def loops(a,b,c):
    .... sum = 0
    .... for i in range(a):
    .... for j in range(b):
    .... for k in range(c):
    .... sum += 1
    ....[color=blue][color=green][color=darkred]
    >>> loops[/color][/color][/color]
    <function wrapper at 0x402eec34>[color=blue][color=green][color=darkred]
    >>> loops(10,10,10)[/color][/color][/color]
    started at Sun Jan 8 23:19:19 2006
    ended at Sun Jan 8 23:19:19 2006
    diff = 0.0003671646118 16 sec

    the code above works fine
    but I am wondering wheather it's possible to
    write something like this
    [color=blue][color=green][color=darkred]
    >>> def timelogger(f, logfile=sys.std out):[/color][/color][/color]
    .... def wrapper(*a,**kw ):
    .... logfile.write(" started at %s" % time.ctime())
    .... t0 = time.time()
    .... f(*a, **kw)
    .... t1 = time.time()
    .... logfile.write(" ended at %s" % time.ctime())
    .... logfile.write(" diff = %f %s" % (t1-t0, "sec"))
    .... return wrapper
    [color=blue][color=green][color=darkred]
    >>> import time
    >>> @timelogger(fil e("hierher", "a")) ### <<<<<< (1)[/color][/color][/color]
    .... def loops(a,b,c):
    .... sum = 0
    .... for i in range(a):
    .... for j in range(b):
    .... for k in range(c):
    .... sum += 1
    ....

    (1) fails to compile
    is it possible to pass parameters to a decorator function?

    Regards, Daniel

  • Frank Niessink

    #2
    Re: decorator question

    Schüle Daniel wrote:[color=blue]
    >
    > (1) fails to compile
    > is it possible to pass parameters to a decorator function?[/color]

    Yes, I think this does what you want:

    import time, sys

    def timelogger(logf ile=sys.stdout) :
    def actual_timelogg er(function):
    def wrapper(*a,**kw ):
    logfile.write(" started at %s" % time.ctime())
    t0 = time.time()
    function(*a, **kw)
    t1 = time.time()
    logfile.write(" ended at %s" % time.ctime())
    logfile.write(" diff = %f %s" % (t1-t0, "sec"))
    return wrapper
    return actual_timelogg er

    @timelogger(log file=file("hier her", "a")) ### <<<<<< (1)
    def loops(a,b,c):
    sum = 0
    for i in range(a):
    for j in range(b):
    for k in range(c):
    sum += 1


    loops(100,100,1 00)


    Cheers, Frank

    Comment

    • Ralf Schmitt

      #3
      Re: decorator question

      Schüle Daniel schrieb:[color=blue]
      > hello NG,
      >
      > consider this code
      >[color=green][color=darkred]
      > >>> def timelogger(f):[/color][/color]
      > ... def wrapper(*a,**kw ):
      > ... print "started at %s" % time.ctime()
      > ... t0 = time.time()
      > ... f(*a, **kw)
      > ... t1 = time.time()
      > ... print "ended at %s" % time.ctime()
      > ... print "diff = ", t1-t0, "sec"
      > ... return wrapper
      > ...[color=green][color=darkred]
      > >>> import time
      > >>> @timelogger[/color][/color]
      > ... def loops(a,b,c):
      > ... sum = 0
      > ... for i in range(a):
      > ... for j in range(b):
      > ... for k in range(c):
      > ... sum += 1
      > ...[color=green][color=darkred]
      > >>> loops[/color][/color]
      > <function wrapper at 0x402eec34>[color=green][color=darkred]
      > >>> loops(10,10,10)[/color][/color]
      > started at Sun Jan 8 23:19:19 2006
      > ended at Sun Jan 8 23:19:19 2006
      > diff = 0.0003671646118 16 sec
      >
      > the code above works fine
      > but I am wondering wheather it's possible to
      > write something like this
      >[color=green][color=darkred]
      > >>> def timelogger(f, logfile=sys.std out):[/color][/color]
      > ... def wrapper(*a,**kw ):
      > ... logfile.write(" started at %s" % time.ctime())
      > ... t0 = time.time()
      > ... f(*a, **kw)
      > ... t1 = time.time()
      > ... logfile.write(" ended at %s" % time.ctime())
      > ... logfile.write(" diff = %f %s" % (t1-t0, "sec"))
      > ... return wrapper
      >[color=green][color=darkred]
      > >>> import time
      > >>> @timelogger(fil e("hierher", "a")) ### <<<<<< (1)[/color][/color]
      > ... def loops(a,b,c):
      > ... sum = 0
      > ... for i in range(a):
      > ... for j in range(b):
      > ... for k in range(c):
      > ... sum += 1
      > ...
      >
      > (1) fails to compile
      > is it possible to pass parameters to a decorator function?
      >[/color]

      It's possible. The call to timelogger must return a function which
      itself takes a function and returns one:

      def timelogger(logf ile=sys.stdout) :
      def deco(f):
      def wrapper(*a,**kw ):
      logfile.write(" started at %s" % time.ctime())
      t0 = time.time()
      f(*a, **kw)
      t1 = time.time()
      logfile.write(" ended at %s" % time.ctime())
      logfile.write(" diff = %f %s" % (t1-t0, "sec"))
      return wrapper
      return deco

      [color=blue]
      > Regards, Daniel
      >[/color]

      Comment

      • Bengt Richter

        #4
        Re: decorator question

        On Sun, 08 Jan 2006 23:26:28 +0100, =?ISO-8859-1?Q?Sch=FCle_Da niel?= <uval@rz.uni-karlsruhe.de> wrote:
        [...][color=blue]
        >
        >the code above works fine
        >but I am wondering wheather it's possible to
        >write something like this
        >[color=green][color=darkred]
        > >>> def timelogger(f, logfile=sys.std out):[/color][/color]
        >... def wrapper(*a,**kw ):
        >... logfile.write(" started at %s" % time.ctime())
        >... t0 = time.time()
        >... f(*a, **kw)
        >... t1 = time.time()
        >... logfile.write(" ended at %s" % time.ctime())
        >... logfile.write(" diff = %f %s" % (t1-t0, "sec"))
        >... return wrapper
        >[color=green][color=darkred]
        > >>> import time
        > >>> @timelogger(fil e("hierher", "a")) ### <<<<<< (1)[/color][/color]
        >... def loops(a,b,c):
        >... sum = 0
        >... for i in range(a):
        >... for j in range(b):
        >... for k in range(c):
        >... sum += 1
        >...
        >
        >(1) fails to compile
        >is it possible to pass parameters to a decorator function?
        >[/color]
        Yes, but then the function must return the same kind of thing
        a bare decorator-function name would have, which is a function
        able to take a single argument of a function and return a function.

        So your decorator won't take f as an argument, just the optional logfile,
        and it will return a function that does the wrapping like the original decorator.
        [color=blue][color=green][color=darkred]
        >>> import sys, time
        >>> def timelogger(logf ile=sys.stdout) :[/color][/color][/color]
        ... def deco(f):
        ... def wrapper(*a,**kw ):
        ... logfile.write(" started at %s\n" % time.ctime())
        ... t0 = time.time()
        ... f(*a, **kw)
        ... t1 = time.time()
        ... logfile.write(" ended at %s\n" % time.ctime())
        ... logfile.write(" diff = %f %s\n" % (t1-t0, "sec"))
        ... return wrapper
        ... return deco
        ...[color=blue][color=green][color=darkred]
        >>> @timelogger() # stdout[/color][/color][/color]
        ... def foo(): pass
        ...[color=blue][color=green][color=darkred]
        >>> foo()[/color][/color][/color]
        started at Sun Jan 08 14:13:55 2006
        ended at Sun Jan 08 14:13:55 2006
        diff = 0.000000 sec[color=blue][color=green][color=darkred]
        >>> foo()[/color][/color][/color]
        started at Sun Jan 08 14:14:02 2006
        ended at Sun Jan 08 14:14:02 2006
        diff = 0.000000 sec[color=blue][color=green][color=darkred]
        >>> @timelogger() # stdout[/color][/color][/color]
        ... def foo(dt): time.sleep(dt)
        ...[color=blue][color=green][color=darkred]
        >>> foo(5)[/color][/color][/color]
        started at Sun Jan 08 14:14:59 2006
        ended at Sun Jan 08 14:15:04 2006
        diff = 5.007000 sec[color=blue][color=green][color=darkred]
        >>> foo(.5)[/color][/color][/color]
        started at Sun Jan 08 14:15:16 2006
        ended at Sun Jan 08 14:15:17 2006
        diff = 0.501000 sec[color=blue][color=green][color=darkred]
        >>>[/color][/color][/color]

        Regards,
        Bengt Richter

        Comment

        • Schüle Daniel

          #5
          Re: decorator question

          thx to all

          now I understand how it works and why it should be done in this way
          so it's possible to write more than only one declarator
          [color=blue][color=green][color=darkred]
          >>> def foo(f):[/color][/color][/color]
          .... l = [1]
          .... def method(*a,**kw) :
          .... f(l, *a, **kw)
          .... return method
          ....[color=blue][color=green][color=darkred]
          >>> def bar(f):[/color][/color][/color]
          .... l = [2]
          .... def method(*a,**kw) :
          .... f(l, *a, **kw)
          .... return method
          ....[color=blue][color=green][color=darkred]
          >>> @foo[/color][/color][/color]
          .... @bar
          .... def foobar(x,y,z):
          .... print x
          .... print y
          .... print z
          ....[color=blue][color=green][color=darkred]
          >>> foobar(1)[/color][/color][/color]
          [2]
          [1]
          1

          x and y are already binded
          by the way .. to l's lists are considered to be in closure?
          Or what is the right denotation for them?
          Can someone give me some pointers to the metaprogramming in Python?
          links etc

          Regards, Daniel

          Comment

          • Duncan Booth

            #6
            Re: decorator question

            Bengt Richter wrote:
            [color=blue][color=green]
            >>is it possible to pass parameters to a decorator function?
            >>[/color]
            > Yes, but then the function must return the same kind of thing
            > a bare decorator-function name would have, which is a function
            > able to take a single argument of a function and return a function.
            >
            > So your decorator won't take f as an argument, just the optional
            > logfile, and it will return a function that does the wrapping like the
            > original decorator.[/color]

            This sounds to me like something that should be done using a decorator.
            e.g. (everything from 'def timelogger' onwards is unchanged from the OP's
            code):

            def decoratorwithar gs(f):
            def wrapper(*args,* *kw):
            def inner(target):
            return f(target, *args, **kw)
            return inner
            return wrapper

            @decoratorwitha rgs
            def timelogger(f, logfile=sys.std out):
            def wrapper(*a,**kw ):
            logfile.write(" started at %s" % time.ctime())
            t0 = time.time()
            f(*a, **kw)
            t1 = time.time()
            logfile.write(" ended at %s" % time.ctime())
            logfile.write(" diff = %f %s" % (t1-t0, "sec"))
            return wrapper

            @timelogger(fil e("hierher", "a")) ### <<<<<< (1)
            def loops(a,b,c):
            sum = 0
            for i in range(a):
            for j in range(b):
            for k in range(c):
            sum += 1

            (I think the logfile output could do with some newlines.)

            Comment

            • Michele Simionato

              #7
              Re: decorator question

              Schüle Daniel wrote:[color=blue]
              > Can someone give me some pointers to the metaprogramming in Python?
              > links etc[/color]

              Check the Python Wiki. For the decorators in particular I wrote a
              module that
              you may find useful. See




              Comment

              Working...