2

I usually use isinstance for constructor overloading, but people also suggests @classmethod for the same. But to my knowledge @classmethod shares the variable.

Below is a simple class

class abc:
    def __init__(self, a=0):
        self.a = a    

    @classmethod
    def from_const(cls, b=30):
        cls.b = b
        return cls(10)

    def printme(self):
        print(self.a,self.b)

Now, lets make three objects

a1 = abc(a=100)
a2 = abc.from_const(b=31)
a3 = abc.from_const(b=41)
a4 = abc().from_const(b=51)
a5 = abc().from_const(b=61)


a1.printme()
a2.printme()
a3.printme()
a4.printme()
a5.printme()

The output:

100 61
10 61
10 61
10 61
10 61

Now I have two questions,

  • Is it possible to make @classmethod not share class variables ?
  • How to properly use @classmethod for constructor overloading ?
Abhishek
  • 3,337
  • 4
  • 32
  • 51
  • 4
    What is `b` even *for*, here? You're setting it on the class, `cls`, so it shouldn't be surprising that it's shared, but why are you setting it at all? Did you mean to do `return cls(b)` instead? Or set it on instances via `__init__`, and `return cls(10, b)` if it shouldn't be shared. – jonrsharpe Jul 26 '18 at 14:48
  • 2
    If you want to assign b attribute to each instance using `from_const`, maybe you want to init the instance, then assign b to it. Here's the idea : `@classmethod def from_const(cls, b=30): instance = cls(10) instance.b = b return instance` – madjaoue Jul 26 '18 at 14:53
  • 1
    Why do instances created by `from_const` have a `b` attribute, but instances created by `__init__` don't? That doesn't make any sense. – Aran-Fey Jul 26 '18 at 14:54
  • @jonrsharpe: The code above is not a complete example, but to only show my doubt. I should have put it more clearly, but all I wanted to set two variables from different constructors – Abhishek Jul 26 '18 at 15:13
  • 1
    @madjaoue: I guess, i made this silly mistake of directly assigning it to class, you code was helpful. Thank you so much man! – Abhishek Jul 26 '18 at 15:13
  • As @Aran-Fey points out, though, that means that you cannot assume that any given instance of `abc` has a `b` attribute, because it depends how it was created. This violates the Liskov substitution principle and will lead to bugs and/or complexity. – jonrsharpe Jul 26 '18 at 15:15
  • @all, I guess, it was silly of me to post it so fast here, madjaoue's answer is what fixed it – Abhishek Jul 26 '18 at 15:17

1 Answers1

2

Maybe you want to init the instance first, then assign b inside your class to it.

Here's the idea :

class abc:
    def __init__(self, a=0):
        self.a = a
        self.b = None

    @classmethod
    def from_const(cls, b=30):
        instance = cls(10)
        instance.b = b
        return instance

    def printme(self):
        print(self.a,self.b)

a1 = abc(a=100)
a2 = abc.from_const(b=31)
a3 = abc.from_const(b=41)
a4 = abc.from_const(b=51)
a5 = abc.from_const(b=61)

Output:

(100, None)
(10, 31)
(10, 41)
(10, 51)
(10, 61)
madjaoue
  • 5,104
  • 2
  • 19
  • 31