Python中的protected和private
2021年2月23日 - 由Bo 0 评论 1799 阅读
Python中并没有public、protected、private这三个关键词的定义,但python中仍存在public、protected、private的概念。
Python中通过下划线来区分这三类,并限制了相关的变量和方法的继承和使用。(但我们仍然有办法访问到)
简单来说,无下划线的则是public,有一个下划线开头的则是protected,有两个下划线开头的则是private,注意前后都有下划线的是内置的比如__init__. 其实加了下划线的就是一个约定,告诉别人不要随意调用。
public是对外开放的,protected是只有自己和子类能用的,private则是只有自己能用的。
我们先看看变量和方法。先创建一个文件protect_private.py:
public_value = "public_value"
_protect_value = "protect_value"
__private_value = "private_value"
def public_method():
return "public"
def _protect_method():
return "protect"
def __private_method():
return "private"
然后在命令行试试:
>>> from protect_private import *
>>> public_value
'public_value'
>>> _protect_value
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_protect_value' is not defined
>>> __private_value
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '__private_value' is not defined
>>> public_method()
'public'
>>> _protect_method()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_protect_method' is not defined
>>> __private_method()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '__private_method' is not defined
我们可以看到,在import后,public的可以调用,但是protect和private的无法被调用。这三个变量和三个方法只能在原文件中才能都被调用。
接下来我们再看看Class中和被import后的情况。修改文件内容为如下:
class Person:
def __init__(self):
self.name = "Bob"
self._gender = "male"
self.__age = "18"
def show_name(self):
return self.name
def _show_name_protect(self):
return self.name
def __show_name_private(self):
return self.name
@property
def info_name(self):
return self.name
@info_name.setter
def info_name(self, value):
self.name = value
@property
def info_gender(self):
return self._gender
@info_gender.setter
def info_gender(self, value):
self._gender = value
@property
def info_age(self):
return self.__age
@info_age.setter
def info_age(self, value):
self.__age = value
class Child(Person):
def show_parent_name(self):
return self.name
def show_parent_gender(self):
return self._gender
def show_parent_age(self):
return self.__age
def call_parent_public_method(self):
return self.show_name()
def call_parent_protect_method(self):
return self._show_name_protect()
def call_parent_private_method(self):
return self.__show_name_private()
先试试Person中的变量:
>>> from protect_private import *
>>> p = Person()
>>> p.name
'Bob'
>>> p._gender
'male'
>>> p.__age
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute '__age'
我们看到初始化Person后,public和protected都可以被访问,但private则不可被访问。其实这只是不允许直接用变量名访问,我们仍然可以用p._Person__age来获得,这个叫名称改写。我们可以用dir来看看Person这个类有什么属性。
>>> dir(p)
['_Person__age', '_Person__show_name_private', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_gender', '_show_name_protect', 'info_age', 'info_gender', 'info_name', 'name', 'show_name']
>>> p._Person__age
'18'
接着试试Person中的方法:
>>> p.show_name()
'Bob'
>>> p._show_name_protect()
'Bob'
>>> p.__show_name_private()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute '__show_name_private'
类中的方法也是一样,public和protected都可以被访问,但private则不可被访问。
private的方法也是一样有名称改写,可以通过p._Person__show_name_private()来访问。
>>> p._Person__show_name_private()
'Bob'
除此之外,我们可以自定义一个方法来返回protected和private的变量和方法,也可以用装饰器@property和@setter,这里就需要程序员自己决定哪些能被访问不要随意修改到重要的值。
>>> p.info_age
'18'
>>> p.info_age = 19
>>> p.info_age
19
接下来再看看子类:
>>> c = Child()
>>> c.show_parent_name()
'Bob'
>>> c.show_parent_gender()
'male'
>>> c.show_parent_age()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "./protect_private.py", line 67, in show_parent_age
return self.__age
AttributeError: 'Child' object has no attribute '_Child__age'
>>> c.call_parent_public_method()
'Bob'
>>> c.call_parent_protect_method()
'Bob'
>>> c.call_parent_private_method()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "./protect_private.py", line 76, in call_parent_private_method
return self.__show_name_private()
AttributeError: 'Child' object has no attribute '_Child__show_name_private'
由此也看到protected能被子类使用,但private则不能被子类使用。