如何减少Python属性中的拼写错误?

问题描述 投票:0回答:2

我读过很多有关 Python 属性的内容,并且了解它们的好处,并且它们通常比 getter/setter 更 Pythonic。但是,我没有发现任何提及它们的用法更容易出现拼写错误,从而导致用户出现意外行为,我想了解如何缓解这一潜在问题。

考虑以下示例:

import datetime
import dateutil
class Person:
    def __init__(self, date_of_birth):
       self.date_of_birth = date_of_birth

    @property
    def date_of_birth(self):
        return self._date_of_birth

    @date_of_birth.setter
    def date_of_birth(self, value):
        # <Some checks about value>
        self._date_of_birth = datetime.datetime.strptime(value, '%d-%m-%Y').date()

    def compute_age(self):
        # Some computations involving today's date and self._date_of_birth
        return dateutil.relativedelta.relativedelta(datetime.date.today(), self.date_of_birth).years

# Compute age of someone
person = Person("15-06-1985")
person.compute_age() # Returns 38

# Update date of birth
person.date_of_birth = "17-08-2001"
person.compute_age() # Returns 22

# Update wrong attribute
person.date_of_brith = "25-11-1999" # No error or warning raised
person.compute_age() # Still returns 22

最后一段代码仍然完全有效,但是

person
现在有一个无用的
date_of_brith
属性,
person.compute_age()
不使用该属性,而开发人员的意图是更新
person
的实际出生日期。由于它不会生成警告或错误,因此此类错误可能不会被发现,并会产生难以在更复杂的应用程序中调试的意外结果。使用 setter 方法
person.set_date_of_birth()
而不是
person.date_of_birth
属性可以防止此类拼写错误,因为方法名称中的拼写错误会在执行时产生异常。因此,我的问题是,这不是提倡使用 setter 方法而不是属性吗?否则,在使用属性时是否有一种干净的方法来减轻这种拼写错误?

python properties coding-style
2个回答
0
投票

可以向实例添加任意属性,这是 Python 的一个基本属性。 (也有例外,但我们不必在这里关心它们。)

为了防止此类意外创建,我们可以重写

__setattr__
来定义
person.XXX = ...
的含义。在此方法中,您可以检查分配给的属性是否有效。

class Person:
    def __init__(self, date_of_birth):
       self.date_of_birth = date_of_birth

    def __setattr__(self, name, value):
        if name not in ["_date_of_birth"]:
            raise AttributeError(f"Cannot create attribute named '{name}'")
        super().__setattr__(name, value)

    ...

注意,我们不需要将

date_of_birth
添加到白名单中,因为不存在名为date_of_birth
实例属性
。当尝试分配给
person.date_of_birth
时,默认行为是调用
Person.date_of_birth.__set__
(如果存在)而不是创建实例属性。

也就是说,我会考虑是否值得让你的代码进行这样的运行时检查,而不是让用户负责适当地测试他们的代码。


-1
投票

您可以使用

__slots__
类变量来预定义允许/期望的属性:

class Person:

    __slots__ = ('date_of_birth',)

...

尝试设置插槽中未定义的属性会引发 AttributeError。您是否想对所有课程执行此操作只是为了捕获拼写错误取决于您。

编辑:如果您还使用 @property 的 getter 和 setter,则此方法不起作用。

© www.soinside.com 2019 - 2024. All rights reserved.