【问题标题】:how to return None if constructor arguments invalid如果构造函数参数无效,如何返回 None
【发布时间】:2014-10-01 18:31:39
【问题描述】:

目前我有类似的东西

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

我想将其重构为:

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

我创建了一个User() 类:

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

但在这种情况下,即使 namepasswordNoneuser 仍会被实例化(为空但仍然存在,因此 if user: 测试为真)。

我如何根据特定参数实例化一个对象?

【问题讨论】:

  • 在提出这个问题 5 年后,我最终避免了这种模式,并在 init 中使用了经典的 self.exists = False。如果您的实例正常,则将其设置为 True。条件不再是 if user: 但是 if user.exists: 这仍然很容易理解,但是对象构造器模式要简单得多(没有 new 方法)

标签: python class oop


【解决方案1】:

您必须使用__new__ 方法;当__init__ 被调用时,一个新的实例已经被创建了。

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

但是,您违反了预期;当你调用一个类时,我希望总是得到一个新实例。要么引发异常,要么改用类方法。

引发异常:

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

或使用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

【讨论】:

  • @comte:用户创建;而是返回 None 单例。
  • @Martikn, true, 'user' 未创建,但变量 user 已创建。 (我的意思是分配了内存)。我还说,如果我只在初始代码中将 init 更改为 new,它就可以工作。您的“实例”添加是否具有真正的附加值,或者仅仅是因为它的代码更简洁?
  • @comte:不知道你的意思; __new__ 仍然需要创建新的实例对象(通过调用object.__new__),因为__new__ 是在类上调用的静态方法。
  • 旁注:我觉得我的第一个代码(在调用用户构造函数之前测试名称和密码)要简单得多。我对代码复杂性的 OOP 观点感到满意!!!
  • @MKesper:见Can you annotate return type when value is instance of cls?,在模块级别使用T = TypeVar('T', bound='User'),然后在classmethod上使用def create_valid_user(cls: Type[T], ...) -> Optional[T](当然可以使用适合namepassword的任何类型)。 Optional 显示 None 是可能的结果。
【解决方案2】:

这是错误的方式。你应该在你的用户类中添加一个名为 check() 的方法。或者(更好的方法),创建一个 static 方法 createUser(name, password)。它看起来像:

user = User.createUser(name, password)  

【讨论】:

  • 为什么这是错误的方式(这只是一个问题)?我不喜欢 OOP,因为我觉得它使代码复杂化了。我喜欢 Martijn 的回答是它很短。为什么在构造函数完成工作时添加一个新的“createUser”方法(或者我错过了什么)?
  • 来自 Martjin 更新我明白你的意思。谢谢你们俩。
【解决方案3】:

类似这样的:

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

然后在你的代码中做这样的事情,或者把它作为工厂模式放在一个类方法中并返回它。

try:
    user = User(name, password)
except (TypeError, ValueError):
    user = None

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多