0

A minimal example to reproduce my problem:

from decimal import Decimal

class MyDecimal(Decimal):
    def __init__(self, value, dummy):
        super().__init__(value)
        print(dummy)

x = MyDecimal(5, 'test')

Throws:

TypeError: optional argument must be a context

A similar issue is described in this question, but the answer suggests that this is a bug which was fixed on Python 3.3, and I'm using Python 3.9.

Any idea what I'm doing wrong here, or how else I can inherit class Decimal while using a different constructor prototype in my class (i.e., additional input arguments before and after the input argument passed to the base class upon construction)?

1 Answers1

0

decimal.Decimal uses __new__ instead of __init__, because Decimal instances are immutable, and initializing in __init__ would be a mutative operation. You need to implement __new__ yourself:

import decimal

class MyDecimal(decimal.Decimal):
    def __new__(cls, value, dummy):
        print(dummy)
        return super().__new__(cls, value)
user2357112
  • 260,549
  • 28
  • 431
  • 505
  • 1. Thank you very much for your answer!. 2. How exactly are they immutable when I can do something like `x += 5` (or am I not interpreting 'immutable' correctly)? 3. Do I need to implement `__new__` in addition to `__init__` or instead of `__init__`? –  Aug 31 '22 at 08:35
  • @bbbbbbbbb: `x += 5` will create a new Decimal. It will not mutate the original. As for `__init__`, you do not need to implement it. Just `__new__`. Implementing both in the same class is usually a mistake, and will lead to weird initialization order issues in subclasses. – user2357112 Aug 31 '22 at 08:37
  • OK, something fundamental is missing in your answer, probably due to the very simple MVP that I posted. I don't really have a 'dummy' input argument that I print. I have an input argument which I store into `self`. How exactly can I achieve that when there IS no `self`? –  Aug 31 '22 at 08:39
  • @bbbbbbbbb: What do you mean by "store into `self`"? If you mean assigning it to an attribute, then just assign it to an attribute of the new object - the one created by `super().__new__`. That'll work fine. The parts of your object structure that are inherited from `decimal.Decimal` are immutable, but attributes you add in the subclass can be assigned normally. – user2357112 Aug 31 '22 at 08:42
  • I mean, instead of `print(dummy)`, I need to do `self.dummy = dummy`. –  Aug 31 '22 at 08:44
  • Then just set a `dummy` attribute on the new object. `retval = super().__new__(cls, value); retval.dummy = dummy; return retval`. – user2357112 Aug 31 '22 at 08:45