Хорошо. Прежде чем мы решим вашу проблему, давайте выясним, есть ли у python модификаторы доступа, такие как private
.
Спецификация доступа определяется соглашениями:
A одиночное подчеркивание перед именем переменной будет означать, что переменная используется для некоторых внутренних логик c внутри класса.
Два подчеркивания перед именем переменной в идеале означают, что переменная должна быть закрытой, но это не так.
>>> 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
.
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