0

Let's say I have a class with two methods, one will be decorated by a classmethod and the other one will not.

class MyClass():
    def __init__(self):
        self.my_string = 'Hello'
    def test1(self):
        return self.my_string 
    @classmethod
    def test2(cls):
        return cls().my_string 

What is the difference between these two calls:

MyClass().test1()
MyClass.test2()

I checked the elapsed time of them and they differ a lot, so it got to be different somehow, but I can't understand why. Is there a preferable way of doing it? Thank you in advance.

Elger
  • 136
  • 8
  • 3
    "I checked the elapsed time of them and they differ a lot"—Differ how much, in which direction, and how did you time them? – khelwood Aug 25 '21 at 23:49
  • I used time.time() to wrap those calls. In the order I mentioned, these are the results Hello 0.0009968280792236328 Hello 0.0005137920379638672 The classmethod seems to be always faster – Elger Aug 25 '21 at 23:51
  • 1
    What are you actually trying to accomplish? Doing `cls().my_string` just doesn't make any sense to me. Be wary of the [XY problem](https://meta.stackexchange.com/q/66377/343832). BTW, welcome to Stack Overflow! Check out the [tour] if you haven't already, and [ask] if you want tips. – wjandrea Aug 25 '21 at 23:52
  • That's a *tiny* difference in times; it might just be arbitrary variation. If you want to time them, use `timeit` and run each one thousands of times. – khelwood Aug 25 '21 at 23:55
  • I got wondering because sometimes I want to delete the instance immediately after getting a variable that is inside of it. Thank you for welcoming me ;) – Elger Aug 26 '21 at 00:01
  • Also, I'm not sure if this is important, but in this example, `test1` is a getter method, [which is not Pythonic](/a/36943813/4518341). Instead you would get `MyClass().my_string` directly. – wjandrea Aug 26 '21 at 00:02
  • With timeit they still have difference, thank you for the tip, pretty cool package – Elger Aug 26 '21 at 00:02
  • @Elger OK, I could see that making sense if the class takes some input data and processes it on initialization. This example though, doesn't really make sense. – wjandrea Aug 26 '21 at 00:05
  • Yes, that's exactly what I am doing, that's why I crossed with this "problem". The input data is processed by each session of the user. – Elger Aug 26 '21 at 00:09

1 Answers1

4

They are very different.

MyClass().test1() invokes the instance method test1 with the instance MyClass() as its implicit first argument (bound to the parameter self).

MyClass.test2() invokes the class method test2 with the class MyClass as its implicit first argument (bound to the parameter cls).

You didn't ask about the more interesting MyClass().test2(), which still invokes the class method test2 with the class MyClass (the type of the instance) as its implicit first argument.

You also didn't ask about MyClass.test1(), which would raise a TypeError because MyClass.test1 resolves to an ordinary function, and no argument would be implicitly bound to the required parameter self.


This particular class method is strange. A class method should either be independent of any particular instance of the class, or create and return an instance. Creating an instance only for use in the class method doesn't really make sense.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • the way you described the first and second case clarifies to me what's happening, but I can't understand why the classmethod is a bit faster yet. Thank you for the answer – Elger Aug 26 '21 at 00:14