Builder 
This pattern is useful when creating more complicated objects that would take a lot of initializer arguments. Instead, you call a number of methods for creating the object step by step. The idea is that the builder class should expose methods to add properties to the object its creating, with a final method build to return the object. These methods can be made fluent by returning self from the function, allowing you to chain these calls together. Builders can also be broken down into Facets, which are inherited builders exposed through the base builder class as properties to handle related elements of the object you are creating. This technically violates the open closed principle because you need to add properties to the base builder, however the alternative is creating a chain of inheritance where you instantiate the most specific builder that has access to all the inherited methods which is somewhat clunky.
class Person:
    def __init__(self):
        print('Creating an instance of Person')
        # address
        self.street_address = None
        self.postcode = None
        self.city = None
        # employment info
        self.company_name = None
        self.position = None
        self.annual_income = None
    def __str__(self) -> str:
        return f'Address: {self.street_address}, {self.postcode}, {self.city}\n' +\
            f'Employed at {self.company_name} as a {self.postcode} earning {self.annual_income}'
    
    @staticmethod
    def new():
        return PersonBuilder()
class PersonBuilder:  # facade
    # Good practice to take person as an argument
    def __init__(self, person=Person()):
        self.person = person
    @property
    def lives(self):
        return PersonAddressBuilder(self.person)
    @property
    def works(self):
        return PersonJobBuilder(self.person)
    def build(self):
        return self.person
class PersonJobBuilder(PersonBuilder):
    def __init__(self, person):
        super().__init__(person)
    def at(self, company_name):
        self.person.company_name = company_name
        return self
    def as_a(self, position):
        self.person.position = position
        return self
    def earning(self, annual_income):
        self.person.annual_income = annual_income
        return self
class PersonAddressBuilder(PersonBuilder):
    def __init__(self, person):
        super().__init__(person)
    def at(self, street_address):
        self.person.street_address = street_address
        return self
    def with_postcode(self, postcode):
        self.person.postcode = postcode
        return self
    def in_city(self, city):
        self.person.city = city
        return self
if __name__ == '__main__':
    pb = PersonBuilder()
    p = pb\
        .lives\
            .at('123 London Road')\
            .in_city('London')\
            .with_postcode('SW12BC')\
        .works\
            .at('Fabrikam')\
            .as_a('Engineer')\
            .earning(123000)\
        .build()
    print(p)
    person2 = PersonBuilder().build()
    print(person2)