【问题标题】:Access private variables in injected method - python在注入方法中访问私有变量 - python
【发布时间】:2017-06-12 14:23:13
【问题描述】:

问题在最后

我想做的是:

  1. 将属性注入创建的对象并设置它而不是变量(成功)
  2. 向创建的对象注入方法(我们称之为METHOD),对象之前没有这种方法(成功)
  3. 使用 self 从属性调用 public 另一个方法(成功)
  4. 使用 self 从属性调用 METHOD(成功)
  5. 使用 self 从 METHOD 获取私有类变量(失败

现在,这里有一些代码:

from types import MethodType
def add_property(instance, name, method):
    cls = type(instance)
    cls = type(cls.__name__, (cls,), {})
    cls.__perinstance = True
    instance.__class__ = cls
    setattr(cls, name, property(method))

def add_variable(instance, name, init_value = 0 ):
    setattr(type(instance), name, init_value)

class Simulation:
    def __init__(self):
        self.finished = False
        self.__hidden = -10

    def someloop(self):
        while not self.finished:
            self.__private_method()

    def __private_method(self):
        pass 

    def public_method(self):
        pass

def mocked_method(self):
    print(type(self))
    print(self.__dict__)
    print(self.__hidden)

def finished(self):

    print("Execute finished",type(self))
    self.public_method()
    self.mocked_update()
    return True


simulation = Simulation() 
add_property(simulation, "finished", finished)
add_variable(simulation, "count_finished", 0)
simulation.mocked_update = MethodType(mocked_method, simulation)
simulation.someloop() 

产生了什么代码(那些打印):

Execute finished '<class '__main__.Simulation'>
<class '__main__.Simulation'>
{'finished': False, '_Simulation__hidden': -10, 'mocked_update': <bound method mocked_method of <__main__.Simulation object at 0x030D2F10>>}
(...)
AttributeError: 'Simulation' object has no attribute '__hidden'

如您所见,self 就是它应该的样子(模拟类),它被正确注入,但它不起作用。 如果您想知道:

print(self._Simulation__hidden)

显然可以在 mocked_update 中工作。

因此我的问题是:我有机会使用 self 访问这个变量吗?

动机

由于cmets部分有问题:

这没有任何实际用途,只是一个实验。

【问题讨论】:

  • 我不明白。我们可以假设您拥有私有方法的名称吗?你到底想做什么,为什么self._Simulation_hidden 不适合你?
  • @juanpa.arrivillaga 只是一个实验,它没有真正的目的。我只是好奇这是否可以实现。
  • 抱歉,现在我明白你要做什么了。对不起,我很困惑。

标签: python python-3.x


【解决方案1】:

“私有”成员的名称修改严格在类定义中完成。为了达到预期的目的,即将self.__hidden 转换为self._Simulation_hidden,您只需在适当命名的类中定义它

例如:

def make_mocked_method():
    class Simulation:
        # this is your code, but now its inside a class stanza so '__' will be mangled
        def mocked_method(self):
            print(type(self))
            print(self.__dict__)
            print(self.__hidden)

    return Simulation.mocked_method

现在mocked_method 将正确访问所需的属性:

simulation.mocked_update = MethodType(make_mocked_method(), simulation)
simulation.someloop() 

给予:

<class '__main__.Simulation'>
{'finished': False, 'mocked_update': <bound method make_mocked_method.<locals>.Simulation.mocked_method of <__main__.Simulation object at 0x101c00a58>>, '_Simulation__hidden': -10}
-10

扩展

这依赖于我们对要添加方法的类的名称进行硬编码 (Simulation)。为避免这种情况,我们可以改用 exec:

def make_mocked_method(cls):
    txt = """class {}:
        def mocked_method(self):
            print(type(self))
            print(self.__dict__)
            print(self.__hidden)
    """.format(cls.__name__)
    ns = {}
    exec(txt, ns)
    return ns[cls.__name__].mocked_method

不幸的是,这里我们要添加的函数必须定义为文本,它不能是一些已经定义的任意函数对象。 (这可能通过使用inspect 找到它的源代码,然后使用exec 在类节中重新编译该源代码来解决(并且明智地选择globals)。

【讨论】:

  • 这很聪明,但如果你必须知道类的名称来编写类定义,你还不如写self._Simulation__hidden,看来。我没有意识到当你这样做时名字不会被破坏:A = type('A', (object,), {'__hidden':42})
  • @juanpa.arrivillaga 当然不推荐……这只是在回答“能不能做”的问题!
  • 谢谢你的解释,我不认为一个人可以做到这一点!
猜你喜欢
  • 2020-12-11
  • 2012-09-24
  • 1970-01-01
  • 2011-07-04
  • 1970-01-01
  • 1970-01-01
  • 2012-06-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多