在注入的方法中访问私有变量 - python

时间:2017-01-26 23:34:32

标签: python python-3.x

问题在最后

我想做的是:

  1. 将属性注入已创建的对象并设置它而不是变量(成功)
  2. 注入方法(让它称之为METHOD)创建对象,对象之前没有这样的方法(成功)
  3. 使用self(成功)
  4. 从属性调用public另一个方法
  5. 使用self(成功)从属性调用METHOD
  6. 使用self(失败
  7. 从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'
    

    正如你所看到的那样,自我应该是什么样的(模拟课程),它被正确地注入了,但它并没有起作用。 万一你想知道:

    print(self._Simulation__hidden)
    

    显然可以在mocked_update中使用。

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

    动机

    由于评论部分有问题:

    这不是任何真正的目的,只是一个实验。

1 个答案:

答案 0 :(得分:3)

“私人”成员的名称严格在类定义中完成。要实现期望的目的,即将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)在类节中重新编译该源来解决。