3

I am trying to apply the timing decorator described here to a method within a class instead of a standalone method. How should this be done?

I am getting this error:

TypeError: unbound method wrapper() must be called with SomeClass instance as
first argument (got float instance instead)
J_H
  • 17,926
  • 4
  • 24
  • 44
Alex van Houten
  • 308
  • 3
  • 17
  • 3
    Did you try it? It's the same. A function and a method aren't different. – agf Jul 20 '11 at 15:39
  • 2
    @agf: Unfortunately, there *is* a difference, although it's not caused by the function/method itself but by the class refusing to turn non-functions into instancemethods (with descriptors and stuff). But it shouldn't apply here, as the actual wrappers are functions themselves. –  Jul 20 '11 at 15:42
  • @delnan I'm not sure I understand. You're saying if the decorator returned something other than a function, it wouldn't work? – agf Jul 20 '11 at 15:45
  • @agf: Yes. See e.g. http://stackoverflow.com/questions/1677747/python-decorators-on-class-members-fail-when-decorator-mechanism-is-a-class –  Jul 20 '11 at 15:47

1 Answers1

1

EDIT

Thanks to your comment, I think I know what the problem is. This doesn't work:

class A:

    @timings
    @classmethod
    def a(cls, x):
       print(x)

A.a(2)

for exactly the reason you said. TypeError: unbound method wrapper() must be called with A instance as first argument (got int instance instead)

But this does:

class A:

    @classmethod
    @timings
    def a(cls, x):
        print(x)

A.a(2)

So the order matters. I think what's going on here is that it's fooling the way python handles bound methods: When python looks at the member a, it has to make a decision:

  1. Make a bound method
  2. Make a class method
  3. Do nothing (leave it as it is)

If it gets a regular function, it will do (1), and @timings produces a regular function.

Does this solve the problem?

Owen
  • 38,836
  • 14
  • 95
  • 125
  • The method I am trying to time is a classmethod. – Alex van Houten Jul 21 '11 at 06:51
  • Oh! In that case I think I know what it might be. I edited my answer: any better? – Owen Jul 22 '11 at 20:56
  • If I change the order, with the classmethod decorator at the line above the timings decorator, I get "TypeError: Class-level classmethod() can only be called on a method_descriptor or instance method." – Alex van Houten Aug 08 '11 at 11:41
  • @Alex van Houten: In that case I am stumped. I know you might not care about this problem any more but I am terribly curious what the problem is, so if you post some code maybe it will become apparent. – Owen Aug 08 '11 at 11:57
  • I guess you solved it. Suppose utilities.py has the Timing class, then this script, which I call Timing_classmethod.py, works: "import time from utilities import Timing timings=Timing() class sleep: enough_sleep=1.0 at classmethod at timings #(at=@) def sleepytime(cls,somestring): time.sleep(cls.enough_sleep) print somestring sleep.sleepytime('done') print timings" However, I was compiling the Cython version, Timing_classmethod.pyx and that gave the above error message. So it is a Cython thing which may or may not me solved in the latest release. – Alex van Houten Aug 09 '11 at 19:07
  • I guess this says it all: http://docs.cython.org/src/userguide/limitations.html#id2 – Alex van Houten Aug 09 '11 at 19:21