重新访问Python私有实例数据

时间:2016-02-11 07:58:54

标签: javascript python perl closures private

我已经读过各种各样的" 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和& amp; amp; amp; Perl不会为Python工作。

谢谢。

2 个答案:

答案 0 :(得分:4)

如果你只是想访问原文,那就不那么难了,因为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()

答案 1 :(得分:3)

您通常不会这样做,但您可以使用模块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'

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

因此,如果你愿意付出一些努力,这并非不可能。为什么你会在我不知道的正常编程过程中这样做。