使用动态参数创建类似局部的对象

时间:2018-09-19 13:18:51

标签: python python-3.x

我正在尝试创建一个部分函数,​​但要使用动态参数将其存储为类属性并进行相应更改。类似于以下代码:

from functools import partial

def foo(*args, msg):
    print(msg)

class Bar:
    def __init__(self, msg):
        self.msg = msg
        self.functions = dict()
        self.functions['foo'] = partial(foo, msg=self.msg)

    def foo_method(self, *args):
        return self.functions['foo'](*args)

b =Bar('1')
b.foo_method()
b.msg = '2'
b.foo_method()

当然,只有两个语句都将打印“ 1”,因为部分对象固定了参数。我发现的唯一选择是将属性更改为属性,然后使用设置器手动更改部分属性:

class Bar:
    def __init__(self, msg):
        self._msg = None
        self.functions = dict()
        self.functions['foo'] = partial(foo)
        self.msg = msg

    def foo_method(self, *args):
        return self.functions['foo'](*args)

    @property
    def msg(self):
        return self._msg

    @msg.setter
    def msg(self, msg):
        self._msg = msg
        self.functions['foo'].keywords['msg'] = msg

我想知道是否还有一种更“ pythonic” /有效的方法来执行此操作,因为除此解决方法外,我真的不需要使用属性。

3 个答案:

答案 0 :(得分:2)

您可以使用lambda而不是partial进行参数的延迟(或通常称为“惰性”)评估,以便在调用函数之前不评估self.msg

class Bar:
    def __init__(self, msg):
        self.msg = msg
        self.functions = dict()
        self.functions['foo'] = lambda *args: foo(*args, msg=self.msg)

    def foo_method(self, *args):
        return self.functions['foo'](*args)

答案 1 :(得分:0)

仅存储对已传递函数的引用并立即构建调用有什么问题?即:

class Bar:

    def __init__(self, msg):
        self.msg = msg
        self.foo = foo  # a reference to foo, not needed here but used as an example

    def foo_method(self, *args):
        return self.foo(*args, msg=self.msg)  # or just: foo(*args, msg=self.msg)

答案 2 :(得分:0)

我想到的最简单的方法就是构造一个字典,然后将其加双星传递给函数以进行解压缩。

类似的东西:

def some_func(msg, some_arg=None):
    print("Hello world") # ignore the msg for now

call_args = {}
call_args['some_arg'] = 2 # single field
call_args.update({'msg': 1, 'stuff': [2,3,4]}) # multiple at once

some_func(**call_args)

现在,some_func将抛出TypeError,因为我们传递的args比函数需要的更多。您可以通过使函数在签名中接受** kwargs,减少您不希望使用的参数或其他方法来解决此问题。

现在,继续上一个会话:

call_args = {'msg': 'abc'} # let's get rid of those extra args
some_func(**call_args) # => prints 'Hello world'