Python:可以使属性访问严格私有吗?

时间:2018-04-24 21:28:40

标签: python ironpython

如果我有一个包含字典的类,我需要在各种实例方法中重用,但我想使该字典只能从特定的实例方法中写入,那可能吗?

在此代码中:

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是唯一可以写入字典的方法,就像修改阻止从类外部写入字符一样?

我的用例是IronPython的托管版本,因此inspect.currentframe无效,如下面的几个答案所述。但是,这应该适用于未托管的IronPython或其他版本。

2 个答案:

答案 0 :(得分:1)

以下是如何使dict仅允许从正确的位置设置值:

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)

如果从dict中删除是一个问题,您还应该实现__delitem__

然后在GoodClassself.__dict = GoodDict()中使用它。

最后,您应该使用值元组而不是列表来确保不变性。

答案 1 :(得分:0)

虽然我不知道你为什么要这样做,但我认为这对你有用:

第一种方法:

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
  • 此方法不会为您提供全面保护,但需要手动覆盖。

它以抽象的方式(如果其他人有时会寻找这个)。