-5

I want to create a class called Chain.
I want to be able to call __init__ method multiple times.
For example:

>> Chain(1)
1
>> Chain(1)(2)
3  

How can I do this in Python?

Mojtaba Arezoomand
  • 2,140
  • 8
  • 23
  • 2
    Implement `__call__` on your class. That's what will be executed if you use `()` on an instance of the class. – khelwood Jan 07 '22 at 13:15
  • does [this](https://stackoverflow.com/questions/682504/what-is-a-clean-pythonic-way-to-have-multiple-constructors-in-python) answer your question? – raiyan22 Jan 07 '22 at 13:17
  • 1
    You'll also need to override `__repr__` so that the first call produces `1`, rather than something like `<__main__.Chain object at 0x10c2a76d0>` – chepner Jan 07 '22 at 13:22
  • 1
    Implement `__call__` and `__eq__` – Ch3steR Jan 07 '22 at 17:12
  • 1
    And `__str__`/`__repr__` so it "looks like" the answer. – jonrsharpe Jan 07 '22 at 17:13
  • It can't return the first number and support chaining. You'll have to override `__eq__` to support comparing an instance of `Chain` to a different value. – chepner Jan 07 '22 at 17:13
  • Why implement your own `__eq__` and `__repr__` when `int` has perfectly good implementations of those already? ;) – Samwise Jan 07 '22 at 17:16

4 Answers4

7

You just need a callable int:

>>> class Chain(int):
...     def __call__(self, other: int) -> Chain:
...         return Chain(self + other)
...
>>> Chain(10) == 10
True
>>> Chain(1)(2)(3)
6
Samwise
  • 68,105
  • 3
  • 30
  • 44
6

To do exactly what you have shown (the usefulness of which I question), you need to override __repr__ and define __call__. For example,

class Chain:
    def __init__(self, x):
        self.x = x

    def __repr__(self):
        return repr(self.x)

    def __call__(self, x):
        return Chain(self.x + x)

Since __call__ returns a new instance of Chain, you can chain calls indefinitely.

>>> Chain(1)
1
>>> Chain(1)(2)
3
>>> Chain(1)(2)(3)
6

Chain itself will always return an instance of Chain (unless you define Chain using a metaclass other than the default of type). Chain.__call__ is what allows you to call an instance of Chain like a function, returning a function to allow the actual chain of calls to continue. __repr__ is used so that each attempt to "show" the instance produces the value of its attribute.

chepner
  • 497,756
  • 71
  • 530
  • 681
3

Does this answer your question?

class Chain:
    def __init__(self, value):
        self.value = value

    def __call__(self, value):
        return Chain(self.value + value)


one = Chain(1)
three = Chain(1)(2)
print(three.value)

Just to explain what __call__ does is:

call is method enables Python programmers to write classes where the instances behave like functions and can be called like a function.

pedro_bb7
  • 1,601
  • 3
  • 12
  • 28
S P Sharan
  • 1,101
  • 9
  • 18
3

As far as I know, you cannot implement multiple __inits__ since it's the function which initializes variables etc.

What you can do is implement the __call__ function, which is the one being called when you call an instance e.g


class MyClass:
    def __init__(self,a):
        self.a = a
        print("Init")
    def __call__(self,b):
        print("call")
        self.b=b

inst = MyClass(1) # "Init"
inst(2) #"call"
CutePoison
  • 4,679
  • 5
  • 28
  • 63