Python 私有实例数据重访

Python private instance data revisited

我读过各种“Python 实例中没有真正私有数据”的帖子,但我们都知道在 Perl 和 JavaScript 中使用闭包来有效地实现私有数据。那么为什么不在 Python 中呢?

例如:

import codecs

class Secret:
    def __private():
        secret_data = None

        def __init__(self, string):
            nonlocal secret_data
            if secret_data is None:
                secret_data = string
        
        def getSecret(self):
            return codecs.encode(secret_data, 'rot_13')

        return __init__, getSecret

    __init__, getSecret = __private()

现在我们做:

>>> thing = Secret("gibberish")
>>> thing.getSecret()
'tvoorevfu'
>>> dir(thing)
['_Secret__private', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'getSecret']

您可以对实例 thing 做些什么来获得对原始字符串的读取权限(忽略我的弱加密)或写入权限?

这周我要教我的学生有关 Python 类 的知识,我试图理解为什么在给定闭包的情况下,JavaScript 和 Perl 的技术不起作用Python.

您通常不会这样做,但您可以使用模块 inspect 深入研究实例。

>>> thing = Secret("gibberish")
>>> thing.getSecret()
'tvoorevfu'
>>> import inspect
>>> inspect.getclosurevars(thing.getSecret).nonlocals['secret_data']
'gibberish'
>>> inspect.getclosurevars(thing.__init__).nonlocals['secret_data']
'gibberish'

给定闭包中的函数之一,您可以访问闭包的变量。我还没有找到修改变量的方法。

所以只要你肯努力,也不是没有可能。为什么你会在正常的编程过程中这样做我不知道。

如果您只想访问 原件,这并不难,因为Python 函数实现了相当彻底的检查api。您可以通过以下方式访问原始机密:

thing = Secret("gibberish")
# __init__ doesn't need to be used here; anything defined within the closure will do
thing.__init__.__func__.__closure__[0].cell_contents

而且,嘿!我们得到了原始值。

修改该值比较困难---但并非不可能---(参见here)。为此设置修改:

import ctypes
...

thing = Secret("gibberish")
cell = ctypes.py_object(thing.__init__.__func__.__closure__[0])
new_value = ctypes.py_object('whatever')
ctypes.pythonapi.PyCell_Set(cell, new_value)

thing.getSecret()