用户类应该是不可变的吗?

2024-09-30 01:18:45 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在读一本关于OOP的书:Elegant Objects作者是@yegor256。它说:“总是使用不可变的对象”(代码将更易于维护)。在

因此,如果我有User类,并且我想更改地址,我是否应该返回一个新用户(change_address_option2)?。在这之前,我通常会做更改地址选项1。在

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

    def change_address_option1(self, new_address):
        self.address = new_address

    def change_address_option2(self, new_address):
        return User(self.name, new_address)

这真的是个好做法吗?。我在其他项目中没有看到这一点:

^{pr2}$

编辑:在阅读了@ShadowRanger的评论之后,我对问题进行了编辑,使其更加具体。谢谢。在


Tags: nameself编辑newobjectsaddress地址def
3条回答

你正在读的这本书似乎是在鼓励函数式编程风格。虽然函数式编程通常回避可变对象,但我不认为这是Python中在您这样的情况下通常使用或认可的策略。在

尤其是这种策略在函数式语言中相对便宜(Python支持函数式编程风格,但它是一种不需要函数式编码的多通道语言),在这种情况下,语言本身通常可以识别这样的模式,并在不改变观察到的行为的情况下将其实现为变异,从而将这样做的开销降到最低。Python为此提供了no支持,因此这样做的成本相当高。在

对于类似于由DB表支持的模型,只需使用可变对象。不可变对象有一些用例,但至少在惯用的Python中,它们通常仅限于根本不会进行更改的情况,或者如果进行了更改,它们将生成完全不相关的对象。在这种情况下,它总是相同的“John”,并且生成新对象而不是在适当的地方对它们进行变异,会有很大的数据不同步的风险,在某些地方存储旧对象,在另一些地方存储新对象,而没有明显的方法来确定哪个是新的。对于唯一用户的当前状态,有一个单一的可变的黄金标准值得使用可变对象的麻烦。在

这取决于用户在应用程序中的含义。也许用户可以更改地址。真正的用户(通常代表使用该应用程序的人)可以移动到另一个地址,对吗?在

但是尽管@ShadowRanger建议在数据库支持的情况下使用可变对象,我还是建议不要这样做。更好的方法是将用户地址更改封装在对象中。我是说

class User:
    def __init__(self, db, name, address):
        self.db = db
        self.name = name

    def change_address_option3(self, new_address):
        self.db.exec("update user set address = ? where name = ?", new_address, self.name)

因此,无论某些处理程序或UI命令中的用户地址需要更改,都可以通过调用

^{pr2}$

使用可变对象,应该是这样的

User user = new User(db, "John")
user.change_address("New York")
db.exec("update users set address = ? where name = ?", user.address, user.name)

因此,与用户相关的应用程序逻辑有点分散在整个应用程序中。而不是封装在对象内部。在

它看起来像一个可变的对象,因为有些东西是可以改变的。但由于逻辑的封装,它很容易理解和改变一些东西。因为在应用程序的其他地方,您只使用用户的类方法与用户一起工作(例如更改地址),所以很容易更改某些内容,因为其他应用程序的coe不依赖于用户实现细节(是否有数据库或文件或其他任何支持)。在

书中有一篇关于这种方法的文章。在

好吧,这是我的想法。若您需要更改用户地址,则可能需要访问旧地址,或者需要为用户创建空地址。这表明address-不是简单的字符串,它必须是一个对象,并且用户必须有一个地址集合。在

class User:
    def __init__(self, name: str):
        self.name = name
        self.addresses = Addresses()

    def addresses(self) -> Addresses:
        return self.addresses

class Addresses:
    def clean(self) -> None:
        ...

    def add(self, address: Address) -> None:
        ...

class Address:
    def __init__(self, address: str):
        self.address = address


# changing address:
user = User('nikialeksey')
user.addresses().clean()
user.addresses().add(Address('new address'))

相关问题 更多 >

    热门问题