Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to return None if constructor arguments invalid

Tags:

python

oop

class

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?

like image 792
comte Avatar asked Aug 08 '14 09:08

comte


People also ask

Can you return in __ init __?

__init__ is required to return None. You cannot (or at least shouldn't) return something else. Try making whatever you want to return an instance variable (or function).

Does constructor return any value in Python?

In Python, the constructor does not return any value. Therefore, while declaring a constructor, we don't have anything like return type. Instead, a constructor is implicitly called at the time of object instantiation. Thus, it has the sole purpose of initializing the instance variables.

What is __ new __?

__new__ method will be called when an object is created and __init__ method will be called to initialize the object. In the base class object , the __new__ method is defined as a static method which requires to pass a parameter cls .


3 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
like image 136
Martijn Pieters Avatar answered Oct 05 '22 22:10

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)  
like image 32
Ivan Avatar answered Oct 05 '22 21:10

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
like image 45
Julien Avatar answered Oct 05 '22 23:10

Julien