You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中Getter与Setter底层原理及代码实现疑问解析

关于CS50P中Student类代码的疑问

先看这段代码:

class Student:
    def __init__(self, name, house):
        self.name = name
        self.house = house

    def __str__(self):
        return f"{self.name} from {self.house}"

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        if not name:
            raise ValueError("Invalid name")
        self._name = name

    @property
    def house(self):
        return self._house

    @house.setter
    def house(self, house):
        if house not in ["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"]:
            raise ValueError("Invalid house")
        self._house = house


def main():
    student = get_student()
    print(student)


def get_student():
    name = input("Name: ")
    house = input("House: ")
    return Student(name, house)


if __name__ == "__main__":
    main()

1. __init__里self.name = name的执行逻辑

当你在__init__里写self.name = name时,并不是直接给实例的name属性赋值,而是会触发带@name.setter装饰器的name方法。这个setter方法会先校验输入的name是否为空:如果是空的就抛出ValueError,校验通过后才会把值存在self._name这个实例变量里。self.house = house的逻辑完全一样,触发对应的house setter方法做校验,然后存在self._house里。

2. 为什么用_name而不是直接用name

这是为了避免无限递归。如果setter方法里写self.name = name,那又会触发setter方法,形成无限循环,直到栈溢出。用下划线开头的_name是Python里的约定:表示这个变量是实例内部的私有变量,外部代码不应该直接访问,只能通过self.name这个属性(也就是getter和setter)来操作。这样既保证了数据校验,又避免了递归调用。

3. self.name的底层实现

self.name本质是一个属性(property),不是普通的实例变量。当你读取self.name时,Python会自动调用带@property装饰器的name方法(也就是getter),返回self._name的值;当你给self.name赋值时,Python会自动调用带@name.setter装饰器的name方法(也就是setter),执行校验和赋值逻辑。

4. getter和setter的底层细节

  • 为什么setter要引用实例变量?因为setter的作用就是把合法的值存起来,所以必须把值放到一个实际的实例变量(比如_name)里;而getter的作用是返回这个存好的值,所以它只需要返回self._name就行,不需要修改什么。
  • @property是Python内置的装饰器,用来把一个方法变成只读属性;而@name.setter是property对象提供的装饰器,用来给这个属性添加赋值逻辑——也就是说,先通过@property定义getter,才能用@xxx.setter定义对应的setter,名字name.setter里的name就是你之前用@property装饰的方法名。

5. @符号的语法含义

@是Python里的装饰器语法糖,它的作用是把后面的函数作为参数传给装饰器函数,然后把装饰器返回的结果替换原来的函数。比如@property就是把name方法传给property()函数,生成一个property对象,然后这个对象就会接管self.name的读取和赋值操作。

内容的提问来源于stack exchange,提问作者Matthew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 22:05:25