转自知乎:http://www.zhihu.com/question/20885435
为什么 Java 与 Python 在对待成员变量的访问控制方式截然相反?
Java提倡成员变量应该是private的对外不可见的,然后提供get/set方法进行操作,而Python恰好相反,python 鼓励成员变量应该尽可能是公开的,然后直接使用成员变量。 感觉Python这样做有点违背“封装”的特性,还有他们在面向对象的概念上差别也十分的大,说一下你的理解。
谢谢 @秦双彪 邀请。
接口设计,必然有对外和对内的区分,使用 Python 也不例外。只不过 Python 的风格是信任开发者,让开发者自我约束,而不用编译期检查之类的强制措施。一般在 Python 中对于类的私有成员,用一个下划线开头即表示私有,外部调用者原则上不应该去依赖这些接口,但某些特殊的场合(比如库本身的测试用例)是可以去破坏这个规则的,这也是 Python 社区反教条主义的一个体现。甚至有的时候,这种约束都不用在变量名上体现,仅仅在文档上体现就已经足够——有文档的就是 API,没有公开文档描述的就是私有接口。
至于 Java 选择编译期检查的强制约束,我也只能说这是 Java 的风格,对比 Python 的做法并无优劣之分。事实上在 Java 中 private 的约束也一样并非不可突破,使用反射就可以绕过这一限制,不少 ORM 工具就使用反射向 private 的属性注入值。
再说到用 getter 还是直接赋值的问题,在 C/C++ 中避免向结构体属性直接赋值有非常充足的理由——那样会导致额外的内存布局依赖,所以对于需要暴露的 API,我们只能选择书写 getter 函数和 setter 函数;而对于 Python 而言,直接存取属性并没有面向特定的内存布局,反而和调用方法一样,是需要经过特定内部方法访问的,即:
# 三者等效
print spam.egg
print getattr(spam, "egg")
print object.__getattribute__(spam, "egg")
而 Java 使用 getter/setter 也是一种约定,约定一个对象对外公开的 只有方法,没有属性 ,只是 Java 的实现非常恶心,即使是简单的赋值、取值的 getter/setter 也需要自己一个个书写。Ruby 采取的是和 Java 一样的概念,但 Ruby 可以用 attr_accessor 这样的语法糖。另一个运行于 JVM 的语言 Scala 则采取和 Ruby 类似的做法弥补了 Java 的教条带来的麻烦,在字节码中自动生成 getter/setter 方法。
总结:除了 getter/setter 需要全部手动书写的问题 Java 略有槽点之外,其他的纯粹是风格差异。