Python 绑定需要访问私有变量的外部方法:Feature还是Bug?

Python 绑定需要访问私有变量的外部方法:Feature还是Bug?,python,cpython,Python,Cpython,SHORT VERSION:绑定到实例的外部方法无法通过self直接访问私有变量。这是一个特性还是一个bug 扩展版(带说明和示例): 在中,Alex Martelli解释了将函数绑定到实例的简单方法 使用此方法,可以使用外部函数设置类中的实例方法(在\uuu init\uu中) 但是,当绑定到实例的函数需要访问私有变量时,就会出现这种情况。这是因为名称损坏发生在\u Py\u Mangle中的步骤中,因此该函数从未有机会调用\uuuuu getattribute\uuuuu(“\u class

SHORT VERSION:绑定到实例的外部方法无法通过
self直接访问私有变量。这是一个特性还是一个bug

扩展版(带说明和示例)

在中,Alex Martelli解释了将函数绑定到实例的简单方法

使用此方法,可以使用外部函数设置类中的实例方法(在
\uuu init\uu
中)

但是,当绑定到实例的函数需要访问私有变量时,就会出现这种情况。这是因为名称损坏发生在
\u Py\u Mangle
中的步骤中,因此该函数从未有机会调用
\uuuuu getattribute\uuuuu(“\u classname\uu privatevarname”)

例如,如果我们定义一个简单的外部加法函数来访问私有实例变量
\uuuuuobj\uval

def add_extern(self, value):
  return self.__obj_val + value
并将其绑定到
中的每个实例,同时在类定义中定义类似的实例方法
add\u intern

class TestClass(object):
  def __init__(self, object_value):
    self.__obj_val = object_value
    self.add_extern = add_extern.__get__(self, TestClass)

  def add_intern(self, value):
    return self.__obj_val + value
然后,内部方法将工作,但外部绑定方法将引发异常:

>>> t = TestClass(0)
>>> t.add_intern(1)
1
>>> t.add_extern(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in add_extern
AttributeError: 'TestClass' object has no attribute '__obj_val'
但是,这并没有将变量留给外部调用方,这是我们不希望的。

由于Python的原因,存储在
t
上的属性的实际名称是
\u TestClass\u obj\u val
(如您在
dir(t)
中所见)。没有在类上定义的外部函数只是查找
\uuuuuj\uval

损坏的名称存储在函数的代码对象(例如,
t.add\u extern.func\u code.co\u names
)中,并且是只读的,因此没有简单的更新方法


所以有理由不使用这种技术。。。至少是名字有问题。

我100%知道这一切。我很好奇这是一个特性还是一个bug。将函数绑定到实例的操作在某些方面是不完整的绑定,因此在我看来这是一个bug。不过这真的是个小案子,所以没什么大不了的。是的,看起来像个bug,但我不认为创建新的实例方法是有文档记录的。很明显,mangling stuff的名称在函数构造函数中,而不是它所属的方法构造函数中。
class TestClass(object):
  ...
  def __getattribute__(self, name):
    try:
      return super(TestClass, self).__getattribute__(name)
    except AttributeError:
      # mimic behavior of _Py_Mangle
      if not name.startswith('__'):  # only private attrs
        raise
      if name.endswith('__'):  # don't mangle dunder attrs
        raise
      if '.' in name:  # don't mangle for modules
        raise
      if not name.lstrip('_'):  # don't mangle if just underscores
        raise

      mangled_name = '_{cls_name}{attr_name}'.format(
          cls_name=self.__class__.__name__, attr_name=name)
      return super(TestClass, self).__getattribute__(mangled_name)