是否可以限制仅从不同的 class 使用 setter/modifier 方法?
Is it possible to restrict the use of a setter/modifier method from a different class only?
我正在实施一个 Linked List,我有两个 classes,一个用于列表,另一个用于 links。 link 对象有一个私有的实例属性 self.__next
。我只希望 LinkedList 对象能够修改此属性的值,不应直接使用 Link 对象进行更改。
如果可能的话,我猜它必须通过抽象 class and/or 继承来实现。
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 中的某些内部逻辑。
变量名前的两个下划线理想情况下表示该变量应该是私有的,但事实并非如此。
>>> 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
class对象能够修改link
实例成员,你可以检查setter方法在哪里使用 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
我正在实施一个 Linked List,我有两个 classes,一个用于列表,另一个用于 links。 link 对象有一个私有的实例属性 self.__next
。我只希望 LinkedList 对象能够修改此属性的值,不应直接使用 Link 对象进行更改。
如果可能的话,我猜它必须通过抽象 class and/or 继承来实现。
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 中的某些内部逻辑。
变量名前的两个下划线理想情况下表示该变量应该是私有的,但事实并非如此。
>>> 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
class对象能够修改link
实例成员,你可以检查setter方法在哪里使用 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