如何复制python类属性?

时间:2013-05-21 19:25:13

标签: python

为了发现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)

3 个答案:

答案 0 :(得分:2)

描述符仅在类上定义时才起作用,而不是实例。请参阅已经指向您的this previous questionthis one以及the documentation。关键声明是:

  

对于对象,机器位于object.__getattribute__(),将b.x转换为type(b).__dict__['x'].__get__(b, type(b))

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

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

最重要的是,如果不在“向外”对象上存储对该对象的引用,则无法有效地代理对基础“guts”对象的属性访问。如果您存储此类引用,人们可以使用它以“未经授权”的方式修改内容。

此外,伤心地说,即使是现有的例子并没有真正保护胆量。我可以这样做:

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

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

答案 1 :(得分:1)

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

最终,如果你想隐藏Python中的私有实现,你应该把它写成C扩展(或者首先不尝试)。如果您的目标是更深入地理解该语言,那么编写C扩展名并不是一个糟糕的起点。

答案 2 :(得分:-1)

你需要这样的东西

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

小心这个