【问题标题】:How can I create a class method with multiple dots?如何创建具有多个点的类方法?
【发布时间】:2013-03-15 10:34:20
【问题描述】:

在 python 中,我想创建一个带有多个点的(类)方法,以便对 xmlrpc 方法进行测试,该方法可以具有带有多个点的方法名称。当我尝试以下操作时:

class Foo(object):
    def method.with.many.dots(self):
        return 42

我的语法无效。我还尝试使用更复杂的想法,例如

class Foo(object):
    def __getattr__(self, attr):
        print attr

这对于带有点的方法名称也不能开箱即用。任何想法如何创建一个简单的模拟对象,我可以用它来做类似的事情

mock.some.test.with.many.dots()

以简单的方式在python代码中,无需启动xmlrpc服务器?

【问题讨论】:

  • Python 将其计算为mock 对象的test 属性的many 属性的dots 方法。
  • HYRY's solution 是您需要的,但它不适用于 with 或您的示例中的任何其他关键字。

标签: python python-2.7 mocking xml-rpc


【解决方案1】:

此解决方案可行

输入:

import mock
MO = mock.Mock()
MO.some.test.wyth.many.dots.return_value = 42
MO.some.test.wyth.many.dots()

输出:

42

注意,“with”是关键字。

每个带点的“后代”都是一个独立的(模拟)对象。

【讨论】:

    【解决方案2】:
    class Foo(object):
        def __init__(self):
            self._attr_path = []
    
        def __getattr__(self, attr):
            self._attr_path.append(attr)
            return self
    
        def __call__(self, *args, **kw):
            print ".".join(self._attr_path)
            print args, kw
            del self._attr_path[:]
    
    f = Foo()
    f.a.b.c(1,2,3)
    

    这个输出:

    a.b.c
    (1, 2, 3) {}
    

    解决@Daira Hopwood 的问题:

    class Bar(object):
        def __init__(self, foo, attr):
            self.foo = foo
            self._attr_path = [attr]
    
        def __getattr__(self, attr):
            self._attr_path.append(attr)
            return self
    
        def __call__(self, *args, **kw):
            print self
            print args, kw
    
        def __str__(self):
            return ".".join(self._attr_path)
    
    class Foo(object):
    
        def __getattr__(self, attr):
            return Bar(self, attr)
    
    f = Foo()
    f.a.b.c(1,2,3)
    

    再次解决@Daira Hopwood 的问题:

    class Foo(object):
    
        def __init__(self, parent=None, name=""):
            self.parent = parent
            self.name = name
    
        def __getattr__(self, attr):
            return Foo(parent=self, name=attr)
    
        def __call__(self, *args, **kw):
            print self
            print args, kw    
    
        def __str__(self):
            nodes = []
            node = self
            while node.parent:
                nodes.append(node)
                node = node.parent
            return ".".join(node.name for node in nodes[::-1])
    
    f = Foo()
    x = f.a.b
    y = f.a.c
    x()
    y()
    
    g = f.a
    f.b
    g.b.c() 
    

    【讨论】:

    • 如果一个属性链在没有中间调用的情况下被多次访问,此解决方案将失败。如果你想让它健壮地工作,你真的需要多个代表链元素的对象。
    • 例如:访问f.a时,将f的_attr_path属性设置为['a']。现在假设您访问 f.b (没有介入呼叫);那么 f._attr_path 将被设置为 ['a', 'b'],这是错误的。
    • 请注意,存在一些库,例如 PyPI 上的“模拟”库,它会自动为任意属性创建模拟对象链,从而避免了上述问题。 (user301527 的回答使用了这个库。)
    • @DairaHopwood,我修改了答案。
    • @DairaHopwood,我又修改了答案,这次我用tree,我觉得可以解决问题。
    猜你喜欢
    • 2019-10-22
    • 2013-09-09
    • 2014-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-06
    • 2020-06-23
    • 1970-01-01
    相关资源
    最近更新 更多