Python initialization pitfalls

There are at least two not obvious class initialization mechanisms in Python, especially if your background is in different programming languages 😉

Class field initialization

If you assign a class value outside __init__ method like here (see class_field):

import random, string

class ClassToBeUsed:
    def __init__(self):
        self.field = ''.join(random.choices(string.ascii_letters + string.digits, k=10))

class ClassInitialization:
    class_field = ClassToBeUsed()

    def __init__(self, field: str):
        self.field = field


if __name__ == '__main__':
    instance1 = ClassInitialization('Instance1')
    instance2 = ClassInitialization('Instance2')

    print("Are both class_field objects the same?",
          instance1.class_field is instance2.class_field)

You should get:

Are both class_field objects the same? True

So be careful – class fields initialized outside __init__ are initialized only once (when the file is imported).

Class __init__ default arguments initialization

If you define a default vaule for arguments in the __init__ method like here:

import random, string

class ClassToBeUsed:
    def __init__(self):
        self.field = ''.join(random.choices(string.ascii_letters + string.digits, k=10))

class DefaultArgumentsInitialization:

    def __init__(self, field: str, class_to_be_used: ClassToBeUsed = ClassToBeUsed()):
        self.field = field
        self.class_to_be_used = class_to_be_used


if __name__ == '__main__':
    instance1 = DefaultArgumentsInitialization('Instance1')
    instance2 = DefaultArgumentsInitialization('Instance2')

    print("Are both class_to_be_used objects the same?",
          instance1.class_to_be_used is instance2.class_to_be_used)

You should get:

Are both class_to_be_used objects the same? True

So be careful – the default arguments of __init__ methods are initialized only once (when the file is imported).

So how do I support default arguments then?

You need to assign None to the argument by default and then reassign it inside __init__ if it has not been changed, see:

import random, string

class ClassToBeUsed:
    def __init__(self):
        self.field = ''.join(random.choices(string.ascii_letters + string.digits, k=10))

class DefaultArgumentsInitialization:

    def __init__(self, field: str, class_to_be_used: ClassToBeUsed = None):
        if class_to_be_used is None:
            class_to_be_used = ClassToBeUsed()
        self.field = field
        self.class_to_be_used = class_to_be_used


if __name__ == '__main__':
    instance1 = DefaultArgumentsInitialization('Instance1')
    instance2 = DefaultArgumentsInitialization('Instance2')

    print("Are both class_to_be_used objects the same?",
          instance1.class_to_be_used is instance2.class_to_be_used)

You should get:

Are both class_to_be_used objects the same? False

Pozostaw komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *