1

为了发现 Python 作为一种语言的边界,我正在探索是否有可能比使用前导下划线表示“私有”实现细节的约定更进一步地隐藏信息。

我已经设法使用这样的代码从本地定义的类中复制“公共”内容,从而实现了字段和方法的一些额外级别的隐私:

from __future__ import print_function

class Dog(object):
    def __init__(self):
        class Guts(object):
            def __init__(self):
                self._dog_sound = "woof"
                self._repeat = 1

            def _make_sound(self):
                for _ in range(self._repeat):
                    print(self._dog_sound)

            def get_repeat(self):
                return self._repeat

            def set_repeat(self, value):
                self._repeat = value

            @property
            def repeat(self):
                return self._repeat

            @repeat.setter
            def repeat(self, value):
                self._repeat = value

            def speak(self):
                self._make_sound()

        guts = Guts()

        # Make public methods
        self.speak = guts.speak
        self.set_repeat = guts.set_repeat
        self.get_repeat = guts.get_repeat

dog = Dog()
print("Speak once:")
dog.speak()
print("Speak twice:")
dog.set_repeat(2)
dog.speak()

但是,我正在努力寻找一种方法来为属性设置器和获取器做同样的事情。

我希望能够编写这样的代码:

print("Speak thrice:")
dog.repeat = 3
dog.speak()

并让它实际打印 'woof' 三遍。

我已经尝试了以下所有方法Dog.__init__,但都没有爆炸,但它们似乎也没有任何效果:

Dog.repeat = guts.repeat
self.repeat = guts.repeat
Dog.repeat = Guts.repeat
self.repeat = Guts.repeat
self.repeat = property(Guts.repeat.getter, Guts.repeat.setter)
self.repeat = property(Guts.repeat.fget, Guts.repeat.fset)
4

3 回答 3

2

描述符仅在类上定义时才起作用,而不是在实例上。请参阅上一个问题这个问题以及abarnert 已经指出您的文档。关键声明是:

对于物体来说,机器在object.__getattribute__()其中转化b.xtype(b).__dict__['x'].__get__(b, type(b))

注意对 的引用type(b)。整个类只有一个属性对象,访问时传入实例信息。

这意味着您不能在单个Dog实例上拥有仅处理该特定狗的内脏的属性。您必须在 Dog上定义一个属性,并让它通过self. 除非你不能用你的设置来做到这一点,因为你没有在 上存储对狗内脏的引用self,因为你试图隐藏内脏。

底线是,如果不在“向外”对象上存储对该对象的引用,就无法有效地代理对底层“胆量”对象的属性访问。如果您存储这样的参考,人们可以使用它以“未经授权”的方式修改胆量。

另外,遗憾的是,即使您现有的示例也不能真正保护胆量。我可以做这个:

>>> d = Dog()
>>> d.speak.__self__._repeat = 3
>>> d.speak()
woof
woof
woof

即使您试图通过仅公开胆量的公共方法来隐藏胆量,这些公共方法本身包含对实际胆量对象的引用,允许任何人直接潜入并修改胆量,绕过您的信息隐藏方案。这就是为什么尝试在 Python 中强制执行信息隐藏是徒劳的:语言的核心部分(如方法)已经暴露了很多东西,而您只是无法堵住所有这些漏洞。

于 2013-05-21T19:29:36.460 回答
1

您可以设置一个带有描述符和元类的系统,其中Dog元类为类的所有公共属性创建描述符并构造一个SecretDog包含所有私有方法的类,然后让每个Dog实例都有一个影子SecretDog实例,由包含您的描述符的描述符跟踪私人的实施。然而,这将是一个非常长的路要走很长的路要以一种语言“保护”私有实现,这种语言本质上不能真正拥有任何私有的东西。您还将有一段地狱般的时间让继承可靠地工作。

最终,如果您想在 Python 中隐藏私有实现,您可能应该将其编写为 C 扩展(或者一开始就不尝试)。如果您的目标是更深入地了解该语言,那么着眼于编写 C 扩展并不是一个糟糕的起点。

于 2013-05-21T19:36:21.923 回答
-1

你需要这样的东西

>>> class hi:
...     def __setattr__(self, attr, value):
...             getattr(self, attr)(value)
...     def haha(self, val):
...             print val
...
>>> a = hi()
>>> a.haha = 10
10

小心这个

于 2013-05-21T19:52:26.293 回答