python-3.x 使用动态参数创建类似分部的对象

8oomwypt  于 2022-11-26  发布在  Python
关注(0)|答案(4)|浏览(165)

我试图创建一个partial函数,但是它的动态参数被存储为类属性,并相应地进行更改。类似于下面的代码:

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()

当然,这两个语句只会在partial对象修复参数时输出“1”。我找到的唯一替代方法是将属性更改为属性,然后用setter手动更改partial属性:

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

我想知道是否有一种更“Python”/更有效的方法来实现这一点,因为除了这种变通方法之外,我真的不需要使用属性。

bf1o4zei

bf1o4zei1#

您可以使用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)
x0fgdtte

x0fgdtte2#

只存储对所传递函数的引用并当场构造调用有什么问题吗?例如:

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)
jjhzyzn0

jjhzyzn03#

有一件事情看起来很有效,那就是定义函数来使用class属性。
然后,您可以使用partial定义函式,其中一个参数为类别。

class myContex:
    a = 5
    
def my_fun(context, b, c):
    print(context.a, b, c)
    
my_fun_partial = partial(my_fun, myContext)
my_fun_partial(4,7)

# Output: 5 4 7

myContext.a = 50
my_fun_partial = partial(my_fun, myContext)
my_fun_partial(4,7)

# Output: 50, 4, 7
8iwquhpp

8iwquhpp4#

我能想到的最简单的可能方法是构造一个dict,并将其以双星号形式传递给函数进行解包。
类似于:

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_unc会抛出一个TypeError,因为我们传递的参数比函数接受的要多。你可以通过让函数在签名中接受**kwargs,减少你不期望的参数或其他方法来解决这个问题。
现在,继续上一个会话:

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

相关问题