Skip to content
Advertisement

How do I create a class where instantiation only happens if certain conditions are met?

Let’s say I have this class:

class Person:
    def __init__(self, name):
        self.name = name

If I want to instantiate Person I can do:

me = Person("António")

But what if I only want to instantiate Person if name has type str?
I tried this:

class Person:
    def __init__(self, name):
        if type(name) == str:
            self.name = name

But then when I do:

me = Person("António")
print(me.name)

you = Person(1)
print(you.name)

I get this:

enter image description here

So all that’s happening is:

  • If name is str, the instance has a .name method
  • If name is not str, the instance has no .name method

But what I actually want, is to stop instantiation all together if name is not an str.
In other words, I want it to be impossible to create an object from the Person class with a non str name.

How can I do that?

Advertisement

Answer

You could use a factory that checks the parameters, and returns a Person object if everything is fine, or raises an error:

maybe something line this:

class PersonNameError(Exception):
    pass

class Person:
    def __init__(self):
        self.name = None

def person_from_name(name: str) -> Person:
    """Person factory that checks if the parameter name is valid
    returns a Person object if it is, or raises an error without 
    creating an instance of Person if not.
    """
    if isinstance(name, str):
        p = Person()
        p.name = name
        return p
    raise PersonNameError('a name must be a string')

p = person_from_name('Antonio') 

Whereas:

p = person_from_name(123)   # <-- parameter name is not a string

throws an exception:

PersonNameError                           Traceback (most recent call last)
<ipython-input-41-a23e22774881> in <module>
     14 
     15 p = person_from_name('Antonio')
---> 16 p = person_from_name(123)

<ipython-input-41-a23e22774881> in person_from_name(name)
     11         p.name = name
     12         return p
---> 13     raise PersonNameError('a name must be a string')
     14 
     15 p = person_from_name('Antonio')

PersonNameError: a name must be a string
Advertisement