Python中的下划线

Python中的下划线


018.11.25

前言

我发现公司里即便是工作经验一年的程序员依然对Python的私有属性有些迷糊——也就是下划线的问题——拿捏不准要怎么用。我想在此总结一下。

单下划线

前置

前置单下划线是一种约定,即:认为这个变量或方法是类私有,外界不要调用。在这里,对象认为是“外界”。

示例如下:

class Persion(object):
    def __init__(self, name, age, hobbies):
        # 不建议被外界使用
        self._name = name
        self._age = age
        self._hobbies = hobbies

    # 允许被外界调用
    @property
    def detail(self):
        return self._get_sentence()

    # 建议不要被外界调用,而是在类中使用
    def _get_sentence(self):
        return f"{self._name} is {self._age} and loves {self._hobbies}."


if __name__ == "__main__":
    lily = Persion("lily", 18, "listenning")
    print(lily.detail)

# 输出:
# lily is 18 and loves listenning.

但外界能不能调用带前置单下划线的成员变量和成员方法呢?事实上是可以的:

print(lily._name)  # 输出:lily
print(lily._get_sentence())  # 输出: lily is 18 and loves listening.

我实在记不清是《Python编程之美》还是《数据结构(Python描述)》,里面对此解释说:之所以Python对类私有只是一种约定,是认为使用Python开发的程序员应该是成熟的。


而另一方面,在一个模块中,前置单下划线的变量或是函数,不能通过from module import *方式导入。如:

# demo1.py

# 这是一个变量
_one = "ONE"

# 这是一个函数
def _two():
    print("TWO")
# demo2.py
from demo1 import *

print(_one)  # 错误使用
_two()  # 错误使用

对此解释器会抛出异常:NameError: name 'xxx' is not defined

但并非demo1中的前置单下划线变量/方法在demo2中就不可以使用,完全可以import module,然后通过module.xxx方式,demo2代码做如下调整:

# demo2.py
import demo1

print(demo1._one)  # 正确使用
demo1._two()  # 正确使用

后置

后置单下划线是一种编程风格建议,即:当你的变量/方法名与Python中的关键字冲突时,可以加上后置单下划线做区分。如:

list_ = ["lily", "bob", "green"]
dict_ = {
    "name": "lily",
    "age": 18
}

双下划线

前置

事实上,前置双下划线变量/方法,更像是类私有。将第一个示例代码改写如下(单下划线都改写为双下划线):

class Persion(object):
    def __init__(self, name, age, hobbies):
        # 不能被外界访问
        self.__name = name
        self.__age = age
        self.__hobbies = hobbies

    # 允许被外界调用
    @property
    def detail(self):
        return self.__get_sentence()
	
	# 不能被外界调用
    def __get_sentence(self):
        return f"{self.__name} is {self.__age} and loves {self.__hobbies}."


if __name__ == "__main__":
    lily = Persion("lily", 18, "listening")
    print(lily.detail)

# 输出:
# lily is 18 and loves listening.

可如果你想外界访问:

print(lily.__name)  # 错误示例
print(lily.__get_sentence())  # 错误示例

解释器会抛异常:AttributeError: 'Persion' object has no attribute '__name'

其实同前置单下划线一样,双下划线其实也可以被外界访问,只不过解释器对他们**“以类之姓,冠它之名”**。

print(lily._Persion__name)  # 输出:lily
lily._Persion__get_sentence()  # 输出:lily is 18 and loves listening.

也就是说,当类名为X,双下划线变量为__y时,外界对其访问应该形如:_X__y


完全与前置单下划线一样的是,模块中的前置双下划线变量/函数,不能通过from module import *导入,但可以import module后使用:

module.__one
module.__two()

前置双下划线存在的意义:为了避免该成员的名称与子类中的名称冲突

后置

开个玩笑。

后置双下划线既没有实际意义,也不是编程风格的建议。

前后置

稍微对Python熟悉的人就会知道,存在前置双下划线同时还有后置双下划线的变量以及方法。如常见的__name__以及__init__()。这些属于Python的魔法对象,是为了区别其他用户自定义的命名。官方表示:永远不要将这样的命名方式应用于自己的变量或函数

感谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值