how to return None if constructor arguments invalid

Question:

Currently I have something like

if name and password:
     user = User(name, password)
     ...do stuff

I’d like to refactor it to something:

user = User(name, password)
if user:
     ...do stuff

I create a User() class:

class User():
    def __init__(self, name, password):
        if name and password:
            self.name, self.password = name, password

but in this case even if name or password are None, user still gets instantiated (empty but still exists, so the if user: test is true).

How to would I not instantiate an object based on specific arguments?

Asked By: comte

||

Answers:

You’ll have to use a __new__ method; by the time __init__ is called a new instance has already been created.

class User(object):
     def __new__(cls, name, password):
         if name and password:
             instance = super(User, cls).__new__(cls)
             instance.name, instance.password = name, password
             return instance

However, you are violating expectations; when you call a class, I’d expect to always get a new instance. Either raise an exception, or use a classmethod instead.

Raising an exception:

class User(object):
    def __init__(self, name, password):
        if not (name and password):
            raise ValueError('Empty name or password not allowed')
        self.name, self.password = name, password

try:
    user = User(name, password)
except ValueError:
    # oops, no username or password
else:
    # ...do stuff

or using a classmethod:

class User(object):
    def __init__(self, name, password):
        self.name, self.password = name, password

    @classmethod
    def create_valid_user(cls, name, password):
        """Create a user, or return None if conditions are not met"""
        if not (name and password):
            return None
        return cls(name, password)

user = User.create_valid_user(name, password)
if user is not None:
    # ...do stuff
Answered By: Martijn Pieters

It’s wrong way. You shold add a method in your User class named check(). Or(better way), create a static method createUser(name, password). It looks like:

user = User.createUser(name, password)  
Answered By: Ivan

Something like this :

class User():
    def __init__(self, name, password):
        self._name = self._password = None
        self.name = name
        self.password = password

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name: str) -> None:
        if not name:
            raise TypeError("name is required")
        if len(name) < 5: # exemple
            raise ValueError("name must have 5 characters or more")
        self._name = name

    # Do the same for password

Then do something like this in your code, or put it in a class method as Factory pattern and return it.

try:
    user = User(name, password)
except (TypeError, ValueError):
    user = None
Answered By: Julien
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.