Python 修改类中多个方法的调用参数

Python 修改类中多个方法的调用参数,python,methods,arguments,Python,Methods,Arguments,我有一个类,它有(太)多的方法。大多数方法都使用一个参数(总是相同的名称)-我需要将参数的类型更改为其他类型,但也希望接受参数的“旧”版本(以及raiseaDeprecationWarning) 编辑:我们可以假设参数始终作为关键字参数传递 最干燥的方法是什么 我想到的第一个解决方案是: def check_orc(orc): if isinstance(Snaga, orc): orc = convert_to_urukhai(orc) raise De

我有一个类,它有(太)多的方法。大多数方法都使用一个参数(总是相同的名称)-我需要将参数的类型更改为其他类型,但也希望接受参数的“旧”版本(以及
raise
a
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)
       ...

阿瓦萨尔的评论是正确的。但是,出于教育目的,以下是您想要的装饰器实现:

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):
       ...

注意:我将
对手
移动到参数中的第一个位置

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):
       ...

注意:我将
对手
移动到参数中的第一个位置

您能告诉我这是否始终是最后一个参数吗?如果没有,你就得用它的名字

我的想法是这样做:

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")
这是一个相当丑陋的黑客,但仍然应该工作,并保存您从重新排序您的参数

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


请注意,为了使测试适合我,我稍微更改了测试(我“不推荐”int并需要str)。您只需检查我的
check_opp()
函数,并将其应用于任何需要的地方。

您能告诉我这是否始终是最后一个参数吗?如果没有,你就得用它的名字

我的想法是这样做:

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")
这是一个相当丑陋的黑客,但仍然应该工作,并保存您从重新排序您的参数

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


请注意,为了使测试适合我,我稍微更改了测试(我“不推荐”int并需要str)。您只需使用我的
check_opp()
函数,并将其应用到您需要的任何地方。

将最常用的参数添加到self,这样您就可以避免所有方法都传递它。或者,您很难通过sed命令编辑源代码。这不是干巴巴的,而是更具可读性和可维护性。我不明白-当它是实例的外部实体时,如何将参数添加到
self
中?将最常用的参数添加到self中,这样可以避免通过所有方法传递它。或者,您很难通过sed命令编辑源代码。这不是干巴巴的,而是更具可读性和可维护性。我不明白-当它是实例的外部实体时,我如何才能将参数添加到
self
?+1,但我在brainf*ck:)中看到了更好看的代码,这真是太难看了@JoelCornett是的,它是:-)但是如果对手有时在这里,有时在那里,你几乎没有其他选择…对手总是一个关键字参数(或者如果不是,我可以这样做)+1,但我在brainf*ck:)中看到了更好看的代码,那真是太难看了@JoelCornett是的,它是:-)但是如果
对手时而在这里时而在那里,你几乎没有其他选择…对手总是一个关键字参数(如果不是,我可以这样做)