1

我有一门课,有(太多)方法。大多数方法都带有一个参数(总是同名) - 我需要将参数的类型更改为其他类型,但也希望接受参数的“旧”版本(和raisea DeprecationWarning)。

编辑我们可以假设参数总是作为关键字参数传递。

这样做最干燥的方法是什么?

我想到的第一个解决方案是:

def check_orc(orc):
    if isinstance(Snaga, orc):
        orc = convert_to_urukhai(orc)
        raise DeprecationWarning("You should not be sending snaga to combat")
    return orc

class Warrior():
    def slash_orc(sword, shield, opponent):
       opponent = check_orc(opponent)
       ...

    def hack_orc(warhammer, opponent):
       opponent = check_orc(opponent)
       ...
4

2 回答 2

4

avasal 的评论是正确的。但是,出于教育目的,这是您想要的装饰器实现:

from functools import wraps

def convert_orc(f):
    @wraps(f)
    def wrapper(self, opponent, *args, **kwargs):
        if isinstance(Snaga, orc):
            raise DeprecationWarning(...)
            return f(self, convert_to_urukhai(opponent), *args, **kwargs)
        else:
            return f(self, opponent, *args, **kwargs)
    return wrapper

class Warrior():
    @convert_orc
    def slash_orc(self, opponent, sword, shield):
       ...

    @convert_orc
    def hack_orc(self, opponent, warhammer):
       ...

注意:我移到opponent参数中的第一个位置

于 2012-08-08T08:55:10.523 回答
2

你能判断这是否总是最后一个参数吗?如果没有,您将不得不使用它的名称。

我的想法是这样做:

def check_orc(orc):
    if isinstance(orc, int):
        orc = str(orc)
        print DeprecationWarning("You should not be sending snaga to combat")
    return orc

def check_opp(meth):
    code = meth.func_code
    argnames = code.co_varnames[:code.co_argcount]
    if 'opponent' in argnames:
        from functools import wraps
        argidx = argnames.index('opponent')
        @wraps(meth)
        def replace(*a, **k):
            if 'opponent' in k:
                k['opponent'] = check_orc(k['opponent'])
            else:
                a = list(a)
                a[argidx] = check_orc(a[argidx])
                a = tuple(a)
            return meth(*a, **k)
        return replace
    else:
        return meth

class Warrior():
    @check_opp
    def slash_orc(self, sword, shield, opponent):
       print "slash", (sword, shield, opponent)

    @check_opp
    def hack_orc(self, warhammer, opponent):
       print "hack", (warhammer, opponent)

Warrior().slash_orc(1,3,4)
Warrior().hack_orc(6,5)
Warrior().slash_orc(1,3,opponent=4)
Warrior().hack_orc(6,opponent=5)
Warrior().slash_orc(1,3,"4")
Warrior().hack_orc(6,"5")
Warrior().slash_orc(1,3,opponent="4")
Warrior().hack_orc(6,opponent="5")

这是一个非常丑陋的 hack,但仍然可以工作,并且可以避免重新排序参数。

在这里,我使用一种检查来找到正确的参数并对其进行修改,无论它是作为关键字还是索引参数传递。

请注意,我稍微更改了测试以使其适合我(我“弃用”整数并需要 strs)。您只需要我的check_opp()功能并将其应用到您需要的任何地方。

于 2012-08-08T09:04:02.403 回答