写在前面
进行面向对象编程时,有时我们需要防止代码在系统中的其他位置任意执行。为了解决这个问题,访问修饰符的概念被引入到早期的语言设计中。
像 C++、Java 或 C# 这样的语言中,我们可以使用保留关键字 public、protected 或 private 来标记类的成员。Python 也有这三个访问修饰符,但它不使用关键字来标记成员。在 Python 中我们使用下划线 _
来标记函数或变量作为受保护或私有。
然而,Python 实际上并不像其他语言那样强制执行这些访问修饰符。相反,它使用名称修饰(name mangling)来混淆函数或变量,并使其更难找到。换句话说,如果你真的想访问它,你是可以的。这也只是程序员对自己的一个强制约定。
受保护函数
在处理模块范围的函数时,有时我们不希望我们的函数对导入模块的任何人可用。一种实现方法是在函数名前面放置一个或两个下划线。
例如,如果我们定义一个模块文件random_module.py
:
def public_func():
print("This function can be seen")
def __hidden_func():
print("You can't see this during import")
然后我们可以在解释器中导入该模块并尝试使用它:
>>> import random_module
>>> random_module.public_func()
This function can be seen
>>> random_module.__hidden_func()
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: module 'random_module' has no attribute '__hidden_func'
如果我们使用from random_module import *
这样的方式导入,同样也适用。可以看出我们的私有函数(下划线开头)是不能被直接访问的
类的私有方法和变量
有时我们希望对类成员施加限制,使其无法在类外部或子类中访问。在这种情况下,我们可以使用双下划线__
将变量或方法声明为私有。
class Example:
def __init__(self):
self.__a = "This is a private variable"
def __can_not_run(self):
print("Can't be executed outside of this class")
如果我们实例化这个类并尝试访问变量或方法:
>>> ex = Example()
>>> print(ex.__a)
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'Example' object has no attribute '__a'
>>> ex.__can_not_run()
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'Example' object has no attribute '__can_not_run'
我们可以看到这两个属性都不可用。
那么,如果我们创建子类,我们能够访问它们吗?
class SubExample(Example):
def print_a(self):
print(self.__a)
现在我们导入这个类:
>>> sub = SubExample()
>>> sub.print_a()
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'SubExample' object has no attribute '_SubExample__a'
错误提示看起来有点不同,但仍然是错误!正如我之前提到的,Python 在内部使用名称修饰来隐藏属性。如果一个变量是受保护的,而不是私有的,它将被移动到一个名为_CLASS_VARIABLE
的引用中,以使其更不容易访问。但是如果你知道这个模式,你实际上可以从任何地方访问和使用任何受保护的变量。
要访问__a
变量可以使用以下代码:
exam = Example()
exam._Example__a
类的受保护方法和变量
我们在上个例子中看到,如果变量或方法只是受保护的,我们应该能够从子类中访问它们。那么,我们如何定义受保护的属性呢?答案是在名称前面使用单个下划线_
。
class ProtectedExample:
def __init__(self):
self._b = "可以从子类中访问的属性"
现在我们可以创建一个子类来验证一下!
class SubProtected(ProtectedExample):
def print_b(self):
print(self._b)
然后,如果我们将其加载到解释器中:
>>> pe = ProtectedExample()
>>> print(pe._b)
Traceback...
>>> sp = SubProtected()
>>> sp.print_b()
可以从子类中访问的属性
通过这样,你现在知道如何在 Python 中使用访问修饰符来封装和混淆你的函数和变量了。
原文始发于微信公众号(harvey的网络日志):python函数前面的下划线(_)代表什么
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/263038.html