0

just started learning python I noticed some strange behavior when instantiating classes :

impl A

class Gifters:
    def __init__(self, repository):
        self.repo = repository

    def __init__(self):
        self.repo = GiftersInfo()

impl B

class Gifters:
    def __init__(self, repository=GiftersInfo()):
        self.repo = repository

both calling:

class GiftersInfo:
    def __init__(self):
        self.list = []

in impl A, the list of GiftersInfo is empty (as expected)

in impl B, the list is only created once and later calls to Gifters' constructor reuse the same GiftersInfo.list somehow...

I noticed this when running these tests (in order):

def test_register_single_gifter(self):
    gifters = Gifters()
    gifters.register(Gifter("Jos"))

    self.assertEqual(1, len(gifters.list()))

=> A: OK

=> B: OK

def test_without_gifters(self):
    gifters = Gifters()
    self.assertEqual(0, len(gifters.list()))

=> A: OK

=> B: FAIL : expected 0 but was 1 (still containing "Jos" from prev test)

But I don't want to use impl A as this gives me the warning : redeclared INIT (and I don't like warnings ;)

can someone explain ?
and maybe even suggest the pythonist way to do this ?

EDIT: in the documentation I found this as a suggestion:

class Gifters:
    def __init__(self, repository=None):
        if repository is None:
            self.repo = GiftersInfo()
        else:
            self.repo = repository

is that the way ? seems so ugly (don't like else either :)

  • in the documentation I found this as a suggestion: class Gifters: def __init__(self, repository=None): if repository is None: self.repo = GiftersInfo() else: self.repo = repository – Olivier Costa Dec 07 '19 at 14:22
  • I don't get what you do with `Impl A`. Defining `__init__` a second time replaces the first definition, so the first one is useless and ignored (the warning you get comes from your IDE, not from Python) – Thierry Lathuille Dec 07 '19 at 15:17
  • ah that explains it ! – Olivier Costa Dec 09 '19 at 15:49
  • Your Impl. B is using a mutable default argument, which is reused by every call. It's important to remember that default arguments are treated as values and not expressions, and are only evaluated once. https://stackoverflow.com/questions/1132941/least-astonishment-and-the-mutable-default-argument – Patrick Haugh Dec 09 '19 at 15:54
  • and now I get it completely ! thx @Patrick – Olivier Costa Dec 11 '19 at 06:18

1 Answers1

0

class Gifters:

def __init__(self, repository=None):

    if repository is None:

        self.repo = GiftersInfo()

    else:

        self.repo = repository

is indeed the way to go