python2.7: 在实例方法中传递kwargs

0 投票
2 回答
619 浏览
提问于 2025-04-18 15:41

如果我想把一个函数里的参数列表直接传给另一个函数,我可以用 locals 函数。不过,如果我在一个实例方法里,这就不行了,因为 self 不能作为关键字参数传递。我可以先创建一个 locals 的字典,然后把 self 删除掉。但我在想,是否有更优雅的方法来做到这一点,因为我经常遇到这个问题。

class MyObj:
    def test(self, a=1, b=2, c=3, d=4):
        return [a,b,c,d]

class MyVerboseObj(MyObj):
    def test(self, a=1, b=2, c=3, d=4):
        print "RUNNING TEST a=%d"%a
        kwargs = locals()
        del kwargs["self"]
        return MyObj.test(self, **kwargs)

MyVerboseObj().test()

有没有更好的方法把 MyVerboseObj.test 的参数列表传给 MyObj.test?

** 更新 **

这是一个简化的例子,用来说明我的问题。一个更实际的例子可能是这样的:

class GenericShow:
    def __init__(self, path):
        self.path = path
    def getRenderPath(self, extn="jpg", colspace="rgb"):
        return "%s/render_%s.%s"%(self.path, colspace, extn)
    def hasGenericShowHandler(self):
        try:
            import GenericShowHandler
            return True
        except: pass

class UkShow(GenericShow):
     def getRenderPath(self, extn="jpg", colspace="rgb"):
         if self.hasGenericShowHandler():
             kwargs = locals()
             kwargs.pop("self")
             return GenericShow.getRenderPath(self, **kwargs)
         else:
            return "%s/blah/render_%s.%s"%(path, colspace, extn)

show = UkShow("/jobs/test")
show.hasGenericShowHandler()
print show.getRenderPath()

我有很多展示对象,它们的变量由不同的模块定义,并且命名方式也不一样——我想创建一些具有共同功能的展示对象。

2 个回答

0

使用 locals() 通常不是个好主意。这种做法容易让人困惑,而且对代码的修改很脆弱,因为如果你添加了任何局部变量,就会搞乱你的调用。

我建议使用更明确的方式:

class MyObj:
    def test(self, a=1, b=2, c=3, d=4):
        return [a,b,c,d]

class MyVerboseObj(MyObj):
    def test(self, a=1, b=2, c=3, d=4):
        print "RUNNING TEST a=%d"%a
        return MyObj.test(self, a, b, c, d)

MyVerboseObj().test()

我知道这样做比较麻烦,但可以避免一些问题。而且这样效率更高。

另外,如果你不介意失去函数的签名,可以直接接受 *args, **kwargs 作为你重写函数的参数:

class MyObj:
    def test(self, a=1, b=2, c=3, d=4):
        return [a,b,c,d]

class MyVerboseObj(MyObj):
    def test(self, *args, **kwargs):
        print "RUNNING TEST"   
        return MyObj.test(self, *args, **kwargs)

MyVerboseObj().test()

在这个版本中访问 a 会有点麻烦,但因为你在第二个例子中并不太关心这些参数,所以这可能是个更简单的解决方案。

顺便提一下:当你的继承结构变得更加复杂(比如多重继承)时,你可能想开始使用 super() 方法:

class MyObj:
    def test(self, a=1, b=2, c=3, d=4):
        return [a,b,c,d]

class MyVerboseObj(MyObj):
    def test(self, *args, **kwargs):
        print "RUNNING TEST"   
        super(MyObj, self).test(*args, **kwargs)

MyVerboseObj().test()
2

如果你不想覆盖父类的函数(因为你想使用它),那么只需要给它起个不同的名字,就可以避免覆盖了!

class MyObj:
    def base_test(self, a=1, b=2, c=3, d=4):
        return [a,b,c,d]

class MyVerboseObj(MyObj):
    def test(self, a=1, b=2, c=3, d=4):
        print "RUNNING TEST a=%d"%a
        kwargs = locals()
        del kwargs["self"]
        return self.base_test(**kwargs)

print MyVerboseObj().test()

撰写回答