Search code examples
pythonpython-3.xclassoopinstance

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?


Solution

  • 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