Python:可以将属性访问严格设为私有吗?
Python: Possible to make attribute access strictly private?
如果我有一个 class 包含我需要在各种实例方法中重用的字典,但我想让该字典只能从特定实例方法写入,这可能吗?
在此代码中:
class GoodClass:
def __init__(self):
# name mangling enabled!
self.__dict = {}
def __repr__(self):
return str(self.__dict)
def add_to_dict(self, key, item):
# this should be the only method that can write to self.__dict
try:
self.__dict[key] += [item]
except KeyError:
self.__dict[key] = [item]
def make_items(self, n_items=3, important_param=1):
# do the important stuff
for i in range(n_items):
item = "param: {}".format(important_param)
self.add_to_dict("important_items", item)
def this_is_bad(self):
# don't want this to be possible
self.__dict["this is bad"] = ["quite bad"]
c = GoodClass()
c.make_items()
c.this_is_bad()
# c.__dict["can't do this"] = ["thanks mangling!"]
print(c)
# {'important_items': ['param: 1', 'param: 1', 'param: 1'], 'this is bad': ['quite bad']}
有没有办法确保 add_to_dict
是唯一可以写入字典的方法,就像 mangling 阻止从 class 外部写入字典一样?
我的用例是在 IronPython 的托管版本中,因此 inspect.currentframe
无法像下面几个答案中提到的那样工作。不过,这应该适用于未托管的 IronPython 或其他版本。
虽然我不知道你为什么要这样做,但我认为这对你有用:
第一种方法:
class my_class:
def __init__(self):
pass
@property
def some_variable(self):
return self.__some_variable
@some_variable.setter
def some_variable(self, value):
current_frame = inspect.currentframe()
calling_function = inspect.getouterframes(current_frame, 2)[1][3]
if (calling_function != "allowed_func_name"):
raise Exception()
self.__some_variable = value
第二种方法:
class my_class:
def __init__(self):
self.some_variable_set_flag = False
pass
def some_func(self, value):
self.some_variable_set_flag = True
try :
self.some_variable = value
finally :
self.some_variable_set_flag = False
@property
def some_variable(self):
return self.__some_variable
@some_variable.setter
def some_variable(self, value):
if (not self.some_variable_set_flag):
raise Exception()
self.__some_variable = value
- 此方法不会为您提供完整的保护,但需要手动覆盖。
它是一种抽象的方式(如果其他人会在某个时间寻找它的话)。
以下是让字典只允许从正确位置设置值的方法:
import inspect
class GoodDict(dict):
__allowed_codes = {GoodClass.add_to_dict.__code__}
def __setitem__(self, key, value):
frame = inspect.currentframe()
while frame:
if frame.f_code in GoodDict.__allowed_codes:
break
frame = frame.f_back
else:
raise Exception('__setitem__ called from non-allowed function')
super().__setitem__(key, value)
如果从字典中删除是一个问题,您还应该实施 __delitem__
。
然后在GoodClass
中使用:self.__dict = GoodDict()
.
最后,您应该将值设为元组而不是列表,以确保不变性。
如果我有一个 class 包含我需要在各种实例方法中重用的字典,但我想让该字典只能从特定实例方法写入,这可能吗?
在此代码中:
class GoodClass:
def __init__(self):
# name mangling enabled!
self.__dict = {}
def __repr__(self):
return str(self.__dict)
def add_to_dict(self, key, item):
# this should be the only method that can write to self.__dict
try:
self.__dict[key] += [item]
except KeyError:
self.__dict[key] = [item]
def make_items(self, n_items=3, important_param=1):
# do the important stuff
for i in range(n_items):
item = "param: {}".format(important_param)
self.add_to_dict("important_items", item)
def this_is_bad(self):
# don't want this to be possible
self.__dict["this is bad"] = ["quite bad"]
c = GoodClass()
c.make_items()
c.this_is_bad()
# c.__dict["can't do this"] = ["thanks mangling!"]
print(c)
# {'important_items': ['param: 1', 'param: 1', 'param: 1'], 'this is bad': ['quite bad']}
有没有办法确保 add_to_dict
是唯一可以写入字典的方法,就像 mangling 阻止从 class 外部写入字典一样?
我的用例是在 IronPython 的托管版本中,因此 inspect.currentframe
无法像下面几个答案中提到的那样工作。不过,这应该适用于未托管的 IronPython 或其他版本。
虽然我不知道你为什么要这样做,但我认为这对你有用:
第一种方法:
class my_class:
def __init__(self):
pass
@property
def some_variable(self):
return self.__some_variable
@some_variable.setter
def some_variable(self, value):
current_frame = inspect.currentframe()
calling_function = inspect.getouterframes(current_frame, 2)[1][3]
if (calling_function != "allowed_func_name"):
raise Exception()
self.__some_variable = value
第二种方法:
class my_class:
def __init__(self):
self.some_variable_set_flag = False
pass
def some_func(self, value):
self.some_variable_set_flag = True
try :
self.some_variable = value
finally :
self.some_variable_set_flag = False
@property
def some_variable(self):
return self.__some_variable
@some_variable.setter
def some_variable(self, value):
if (not self.some_variable_set_flag):
raise Exception()
self.__some_variable = value
- 此方法不会为您提供完整的保护,但需要手动覆盖。
它是一种抽象的方式(如果其他人会在某个时间寻找它的话)。
以下是让字典只允许从正确位置设置值的方法:
import inspect
class GoodDict(dict):
__allowed_codes = {GoodClass.add_to_dict.__code__}
def __setitem__(self, key, value):
frame = inspect.currentframe()
while frame:
if frame.f_code in GoodDict.__allowed_codes:
break
frame = frame.f_back
else:
raise Exception('__setitem__ called from non-allowed function')
super().__setitem__(key, value)
如果从字典中删除是一个问题,您还应该实施 __delitem__
。
然后在GoodClass
中使用:self.__dict = GoodDict()
.
最后,您应该将值设为元组而不是列表,以确保不变性。