Python3 - 澄清对同一 属性 的多重验证

Python3 - Clarification about multiple verifications on the same property

我想对 Python 中的同一个 属性 进行不同的验证,但我不确定正确的方法是什么。例如,在下面的代码中,我想验证我的对象的名字和姓氏(以大写字母开头,长度超过 2 个符号)。对于姓氏 属性,我将所有检查合并为一个 setter。在这种情况下,我的代码不会同时捕获这两个异常。如果我像在名字 setter 中那样拆分它们,我无法一直将其设为 运行。我的问题是什么是正确的实现方式?谢谢。

class Person:
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    @property
    def last_name(self):
        return self.__last_name

    @last_name.setter
    def last_name(self, value):
        if len(value) > 2:
            self.__last_name = value
        else:
            raise Exception("Last name: more than 2 symbs needed")
        for letter in value:
            if letter == letter.upper():
                self.__last_name = value
                break
            else:
                raise Exception('Last name: has to start with upper case')

    @property
    def first_name(self):
        return self.__first_name

    @first_name.setter
    def first_name(self, value):
        for letter in value:
            if letter == letter.upper():
                self.__first_name = value
                break
            else:
                raise Exception('First name: has to start with upper case')

    @first_name.setter
    def first_name(self,value):
        if len(value) > 2:
            self.__first_name = value
        else:
            raise Exception("First name: more than 2 symbs needed")




Jack = Person('Ja', 'sparrow')
print(Jack.first_name)
print(Jack.last_name)

您可以简单地做一个合乎逻辑的 and 来检查这两个条件。

这里有一个姓氏的例子

class Person:
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    @property
    def last_name(self):
        return self.__last_name

    @staticmethod
    def _first_letter_is_upper(val):
        return val[0].isupper()

    @last_name.setter
    def last_name(self, value):

        if len(value) > 2 and Person._first_letter_is_upper(value):
            self.__last_name = value
        else:
            raise Exception("Last name: more than 2 symbs needed")


我已经稍微清理了您的代码并进行了一些更改以使其正常工作。此外,我建议您使用 raise ValueError() 而不是 Exception,因为这实际上是 first_namelast_name.

的值错误

通过调整您的代码并相应地打印错误消息,可以在一个值中捕获这两个错误。但是,您不能期望在 first_namelast_name 中都捕获错误,因为一旦第一个异常发生,代码就会停止执行,因此无法捕获和显示下一个异常。这仅仅是因为 python 是一种解释型语言,它会在第一次出现错误时停止执行。

这是我的代码版本。

self.first_name赋值,实际上会调用first_name()方法@property.
self.last_name.

也是如此

这确保即使在 __init__()

中也验证值

@property.setter 方法将值设置为名为 _property 的变量; _first_name_last_name.

在变量前加下划线 (_) 表明该变量不应公开使用,而是类似于代码的内部变量。

_first_name_last_name 保存对象的实际值,而 @property 方法只是充当用户访问(获取和设置)这些对象的一种前端值。由于这些是方法,因此可以在此处轻松完成验证。

class Person:
    def __init__(self, first_name='John', last_name='Doe'):
        self.first_name = first_name
        self.last_name = last_name

    def __repr__(self):
        return f'{self.__class__.__name__}({self.first_name} {self.last_name})' 

    @property
    def last_name(self):
        return self._last_name

    @last_name.setter
    def last_name(self, value):
        msg = ''
        if len(value) <= 2:
            msg = 'Last name: more than 2 symbols needed'

        if not value[0].isupper():
            if not msg:
                msg = 'Last name: has to start with upper case'
            else:
                msg += ', has to start with upper case'

        if msg:
            raise ValueError(msg)
        else:
            self._last_name = value

    @property
    def first_name(self):
        return self._first_name

    @first_name.setter
    def first_name(self, value):
        msg = ''
        if len(value) <= 2:
            msg = 'First name: more than 2 symbols needed'

        if not value[0].isupper():
            if not msg:
                msg = 'First name: has to start with upper case'
            else:
                msg += ', has to start with upper case'

        if msg:
            raise ValueError(msg)
        else:
            self._first_name = value

这是一个有效 Person 对象的示例。

>>> p = Person('Jack', 'Sparrow')
>>> p
Person(Jack Sparrow)

这些是在尝试创建具有无效值的对象时导致的异常。

>>> p = Person('ja', 'Sparrow')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "per.py", line 3, in __init__
    self.first_name = first_name
  File "per.py", line 47, in first_name
    raise ValueError(msg)
ValueError: First name: more than 2 symbols needed, has to start with upper case
>>> p = Person('Jack', 'sparrow')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "per.py", line 4, in __init__
    self.last_name = last_name
  File "per.py", line 26, in last_name
    raise ValueError(msg)
ValueError: Last name: has to start with upper case

如果 first_namelast_name 均无效,则仅引发 first_nameException,因为这是代码中首先分配的值。一旦 Exception 出现,执行就会停止,因此不再捕获值为 last_name 的错误。

>>> p = Person('jack', 'Sp')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "per.py", line 3, in __init__
    self.first_name = first_name
  File "per.py", line 47, in first_name
    raise ValueError(msg)
ValueError: First name: has to start with upper case