我正在实现一个链表,我有两个类,一个用于列表,另一个用于链接。链接对象具有私有的实例属性self.__next
。我只希望 LinkedList 对象能够修改此属性的值,它不应该直接使用 Link 对象进行更改。
如果可能的话,我猜它必须用抽象类和/或继承来实现。
class Link:
def __init__(self):
self.__next = True
def setter(self):
self.__next = False
class LinkedList():
def setter(self):
"""Changes the value of 'self.__next' in the link"""
pass
好的。在我们解决您手头的问题之前,让我们看看 python 是否真的有像private
这样的访问修饰符。
访问规范由约定完成:
变量名称前的单个下划线表示该变量用于类中的某些内部逻辑。
理想情况下,变量名称前的两个下划线表示该变量是私有的,但事实并非如此。
>>> class Foo:
... def __init__(self):
... self.x = 10 # public
... self._x = 20 # internal
... self.__x = 30 # private
...
>>> f = Foo()
>>> f.x
10
>>> f._x
20
>>> f.__x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__x'
您可能会认为__x
无法访问,因为它是私有的。但
>>> f._Foo__x
30
>>> dir(f)
['_Foo__x', '__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__', '_x', 'x']
dir(f)
的第一个值是_Foo__x
,这就是变量__x
。Python 只是重命名名称前有__
(2 个下划线(的变量。
但是,如果确实要防止类对象Link
修改实例成员link
则可以使用inspect
模块检查调用 setter 方法的位置。
import inspect
class Link:
def __init__(self, value=None, link=None):
self.value = value
self._link = link
@property
def link(self):
return self._link
@link.setter
def link(self, value):
caller = inspect.stack()[1].function
if hasattr(LinkedList, caller):
self._link = value
else:
raise AttributeError("Can't set value of link from class Link")
class LinkedList:
def __init__(self):
self.head = None
def append_link(self, value):
if not self.head:
self.head = Link(value)
else:
t = self.head
while t.link is not None:
t = t.link
t.link = Link(value)
def __repr__(self):
t = self.head
list_values = []
while t != None:
list_values.append(str(t.value))
t = t.link
return f'[{", ".join(list_values)}]'
ll = LinkedList()
print(ll)
ll.append_link(10)
ll.append_link(20)
ll.append_link(30)
ll.append_link(40)
print(ll)
l = Link()
l.link = 'value'
输出:
$ python LinkedList.py
[]
[10, 20, 30, 40]
Traceback (most recent call last):
File "LinkedList.py", line 55, in <module>
l.link = 'value'
File "LinkedList.py", line 20, in link
raise AttributeError("Can't set value of link from class Link")
AttributeError: Can't set value of link from class Link