Python 中的 getter 和 setter 如何工作?

How do getters and setters work in Python?

我正在学习 getters 和 setters ,我的理解是它们的使用使得没有人可以直接改变对象的属性。在例子中

class Person:
    def __init__(self, name, age):
        self._name = name
        self._age = age

    def get_age(self):
        return self._age

    def set_age(self, new_age):
        if isinstance(new_age, int) & new_age>0 & new_age<120:
            self._age = new_age

    def get_name(self):
        return self._name
    
    def __str__(self):
        return 'Person[' + self._name + '] is ' + str(self._age)
    
p1 = Person("Sandeep", 49)

我创建了一个对象 p1,我将年龄设置为 49。因为我已经创建了一个 set_age 函数,所以我希望我们可以通过 [=13] 更改 p1 的年龄=] 只是,不是通过常规方式。但这并没有发生,我也可以通过 p1 更改 p1 的年龄,例如 p1._age = 35。那么,如果我仍然能够直接访问属性,那么使 set_age 函数有什么好处呢?

我想,我遗漏了一些东西,请帮忙。

what I understand is that they are used so that no one could change the object's attributes directly.

你的理解有误。没有神奇的规则告诉 python 解释器 oh, this class has a setter, so direct access to the fields aren't allowed any more.

换句话说:这仅仅是“按惯例工作”。当你看到一个有setter方法的pythonclass时,你知道不应直接访问字段,尽管您仍然可以这样做。

注意:python 对此类事情大多相当宽容。很多事情只是“按照惯例”。这只是 python 的“本质”:您可以做很多其他语言,尤其是像 Java 这样的静态类型语言不允许做的事情。

您需要告诉 python 如何将 getter 和 setter 与实际变量名称相关联。为此,您可以使用内置的 property 函数,如下所示:

class Person
    def __init__(self, name, age):
        self._name = name
        self._age = age

    def get_age(self):
        return self._age

    def set_age(self, new_age):
        if isinstance(new_age, int) & new_age>0 & new_age<120:
            self._age = new_age

    def get_name(self):
        return self._name
    name = property(get_name)
    age = property(get_age, set_age)

    def __str__(self):
        return 'Person[' + self.name + '] is ' + str(self.age)
    
p1 = Person("Sandeep", 49)

然后不要引用 _name_age 使用 nameage

现在我意识到我问了一个愚蠢的问题。使用 setters 的原因很明显,创建用于设置值的函数是对其应用约束的一种非常方便的方法。在上面的例子中,约束是人的年龄应该是正数并且小于 120。如果没有 setters.

是不可能实现这样的约束的

使用 getter 和 setter 的原因是,如果您想做一些比使用 foo.bar 设置和属性更复杂的事情。在你的例子中,set_age 有一个

isinstance(new_age, int) & new_age>0 & new_age<120

检查,这是不可能用原始属性做的。 (Side-note:你应该使用 and 而不是 &。)

是的,有人仍然可以做到 p1._age = -1,然后他们的代码将无法工作,但他们为什么会这样?这只会让他们的代码无法工作。

您的 get_name 功能不如 age 有用。它基本上使 name read-only,这可能有用也可能没用。

在Python中创建setter和getter时,通常使用@property装饰器。这意味着可以像调用属性一样调用函数,因此您可以只执行 p1.name 而不是 p1.get_name()。同样 p1.set_age(3) 变成 p1.age = 3.

您可能想在 __init__ 中使用年龄 setter,因为 Person 的年龄在创建时会被验证。

这是一个进行了这些更改的版本(以及其他一些可读性改进)。

class Person:
    def __init__(self, name, age):
        self._name = name
        self.age = age

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, new_age):
        if isinstance(new_age, int) and 0 < new_age < 120:
            self._age = new_age
    
    @property
    def name(self):
        return self._name

    def __str__(self):
        return f"Person[{self.name}] is {self.age}"
    
p1 = Person("Sandeep", 49)