为什么不需要为Python对象添加 getter 和 setter

Getter 和 setter在java中被广泛使用。一个好的java编程准则为:将所有属性设置为私有的,同时为属性写getter和setter函数以供外部使用。 这样做的好处是属性的具体实现被隐藏,当未来需要修改时,只需要修改getter 和 setter即可,而不用修改代码中所有引用这个属性的地方。可能做的修改为:

  • 在获取或设置属性时打一条日志
  • 设置属性时,对值对进检查
  • 设置发生时, 修改设置的值
  • 获取属性时,动态地计算值

可谓是好处多多,getter和setter为变量访问提供了灵活的方式。

但python中情况却不同,因为对象属性访问的机制不同。java中需要为变量写getter和setter的原因为:当我们写这样的表达式 person.name 来获取一个 person 对象的 name 属性时,这个表达式的意义是固定的,它就是获取这个属性,而不可能触发一个函数的调用。但对于python, 这个表达式即可能是直接获取一个属性,也可能会调用一个函数。这取决 Person 类的实现方式。也就是说,python的对象属性访问的语法,天然就提供了getter和setter的功能。

由于这个区别,我们没有必要在python中为每个对象的属性写getter和setter。最开始时,我们总是将属性作为一个直接可访问的属性。当后续需要对这个属性的访问进行一些控制时,我们可以将其修改为函数触发式属性。在修改前后,调用这个对象属性的代码不用修改,因为还是使用相同的语法来访问这个属性。

可以使用@property 装饰器将一个直接访问的属性转变为函数触发式属性。如下所示,使用@property前的代码为

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

person = Person("Tom")
print(person.name)

代码的输出为:

Tom

此时为直接访问 name 这个属性。当我们需要确保 name 是一个字符串时,可以使用 @property 装饰器将属性转变为一个函数调用,如下所示。

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

    @property
    def name(self):
        print("get name called")
        return self._name

    @name.setter
    def name(self, name):
        print("set name called")
        if not isinstance(name, str):
            raise TypeError("Expected a string")
        self._name = name

person = Person("Tom")
print(person.name)

代码的输出为:

set name called
get name called
Tom

可以看出

  • 在创建Person对象时(代码的倒数第二行), 用于set name的函数被调用。这个函数会检查输入是否为一个字符串,如不是则raise一个TypeError
  • 在获取属性时(代码的最后一行),用于get name的函数被调用
  • 在修改前后,使用Person类的代码完全相同

总结

Python中对象访问的语法即可能是直接访问这个属性,也可能是调用一个函数,这取决于类的实现方式。我们可以在不修改调用者代码的前提下,轻松切换这两种方式。可见python原生就提供了添加额外getter和setter所带来的好处。因此没有必要一开始就为对象属性编写getter和setter函数,而是在需要时切换到函数调用式属性。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏玩转JavaEE

MongoDB固定集合

一般情况下我们创建的集合是没有大小的,可以一直往里边添加文档,这种集合可以动态增长,MongoDB中还有一种集合叫做固定集合,这种集合的大小是固定的,我可以在创...

3207
来自专栏互联网杂技

JavaScript 10分钟入门

简介 JavaScript是一门面向对象的动态语言,他一般用来处理以下任务: 1、修饰网页 生成HTML和CSS 生成动态HTML内容 生成一些特效 2、提供...

32510
来自专栏cs

python字符串

慕课网 首发了,放在垂直领域吧。 python字符串是一种元素为字符的序列类型。因为序列类型是元素被顺序放置的一种数据结构,因此可以通过索引来获取某一个字符,...

3009
来自专栏前端知识分享

javascript易混淆的split()、splice()、slice()方法详解

很多时候,一门语言总有那么些相似的方法,容易让人傻傻分不清楚,尤其在不经常用的时候。而本文主要简单总结了JavaScript中的关于字符串和数组中三个容易混淆的...

702
来自专栏ShaoYL

结构体

33113
来自专栏北京马哥教育

Python 变量类型

变量存储在内存中的值。这就意味着在创建变量时会在内存中开辟一个空间。 基于变量的数据类型,解释器会分配指定内存,并决定什么数据可以被存储在内存中。 因此,变量...

3708
来自专栏林德熙的博客

dotnet 设计规范 · 抽象定义

严格来说,只有一个类被其他的类继承,那么这个类就是基类。在很多时候,基类的定义是提供足够的抽象和通用方法和属性、默认实现。在继承关系中,基类定义在上层抽象和底层...

602
来自专栏北京马哥教育

Python 变量类型详解

豌豆贴心提醒,本文阅读时间5分钟,文末有秘密! ? 文 | 豌豆 图 | 来源网络 变量存储在内存中的值。这就意味着在创建变量时会在内存中开辟一个空...

3714
来自专栏黄Java的地盘

eventEmitter3源码分析与学习

事件监听在前端的开发过程中是一个很常见的情况。DOM上的事件监听方式,让我们看到了通过事件的方式来进行具体的业务逻辑的处理的便捷。

441
来自专栏静默虚空的博客

[Java 基础]控制语句

选择语句 if语句 if语句会判断括号中的条件是否成立,如果成立则执行if语句中的代码块,否则跳过代码块继续执行。 语法 if(布尔表达式) { //如果布尔...

1916

扫码关注云+社区