4

So I like to use attr but sometimes I need to do my own thing. can I override the __init__ method with my own?

import attr
@attr.s(auto_attribs=True)
class MyClass:
     i: int
     def __init__(self, i, special=None):
          if special:
               self.i = special
          else:
               self.i = i
>>> a = MyClass(i=1,special=2)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    a = MyClass(i=1,special=2)
TypeError: __init__() got an unexpected keyword argument 'special'

Another example:

@attr.s(auto_attribs=True)
class MyOtherClass:
     i: int
     def __init__(self, i, **kwargs):
         self.i = kwargs.get('magic',i)



>>> a = MyOtherClass(i=5,magic=12)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    a = MyOtherClass(i=5,magic=12)
TypeError: __init__() got an unexpected keyword argument 'magic'
polo
  • 1,352
  • 2
  • 16
  • 35

2 Answers2

7

If you pass @attr.s(auto_attribs=True, init=False), a attrs won't create an __init__ method (works the same for repr, eq, ...).


As of attrs 20.1.0, if you pass @attr.s(auto_attribs=True, auto_detect=True) or use the NG API @attr.define (no args necessary), it will automatically detect the presence of a custom __init__ (and every other __ method) on the current class and won’t overwrite it.

hynek
  • 3,647
  • 1
  • 18
  • 26
4

The "attrs by Examples" page says:

Sometimes, you want to have your class’s __init__ method do more than just the initialization, validation, etc. that gets done for you automatically when using @attr.s. To do this, just define a __attrs_post_init__ method in your class. It will get called at the end of the generated __init__ method.

>>> @attr.s
... class C(object):
...     x = attr.ib()
...     y = attr.ib()
...     z = attr.ib(init=False)
...
...     def __attrs_post_init__(self):
...         self.z = self.x + self.y
>>> obj = C(x=1, y=2)
>>> obj
C(x=1, y=2, z=3)
ababak
  • 1,685
  • 1
  • 11
  • 23
  • thanks @ababak but this is more of a workaround for my toy example than an answer to my question – polo Oct 03 '19 at 17:02
  • So the answer is no, you can't use your own init as it is generated automatically and will overwrite yours. But you can use another option specially designed for cases when you need your own init. – ababak Oct 04 '19 at 07:53