У меня есть функция под названием атака:

def attack(name,minmultiplier,maxmultiplier,critchance,attacker,attackee):
    print(attacker[0],"used",name)
    multiplier=random.randint(minmultiplier,maxmultiplier)
    crit=random.randint(critchance,100)
    if crit==100 and ((attacker[2]*multiplier*2)-attackee[3]) > 0:
        attackee[1]=attackee[1]-((attacker[2]*multiplier*2)-attackee[3])
    elif ((attacker[2]*multiplier)-attackee[3]) > 0:
        attackee[1]=attackee[1]-((attacker[2]*multiplier)-attackee[3])
    else:
        print("You fail to hit",attackee[0])
    print(attackee[0],"'s health after",attacker[0],"'s attack is",attackee[1])

И я делаю несколько реальных атак для боссов и игроков здесь:

boss=["Greed",1000,10,10,1]
slashp=attack("slash",1,2,5,player,boss)
slashb=attack("slash",1,2,5,boss,player)
kick=attack("kick",1,1,1,player,boss)
aiattacklist=[slashb]
attacknamelist=["slash","kick"]
attackfunclist=[slashp,kick]

Несмотря на то, что я сохраняю только эти версии как переменные, они все еще называются:

template used slash
You fail to hit Greed
Greed 's health after template 's attack is 1000
Greed used slash
template 's health after Greed 's attack is 58
template used kick
You fail to hit Greed
Greed 's health after template 's attack is 1000

Это то, что Python всегда делает, или я делаю что-то не так, потому что я не хочу, чтобы они вызывались (извините, если я не использовал правильную терминологию, я новичок)

1
partben 17 Дек 2015 в 16:25

4 ответа

Лучший ответ

Вы вызываете функции здесь:

slashp=attack("slash",1,2,5,player,boss)
slashb=attack("slash",1,2,5,boss,player)
kick=attack("kick",1,1,1,player,boss)

Там вы храните возвращаемое значение, а не функцию.

Если вы хотите сохранить некоторые предопределенные аргументы, либо воспользуйтесь другой функцией для переноса вызова, либо используйте лямбду (что по сути является упрощенной формой создания функции), либо используйте functools.partial(), чтобы предопределить некоторые аргументы и сохранить для них новый вызываемый.

Использование лямбды будет выглядеть так:

shlashp = lambda player, boss: attack("slash", 1, 2, 5, player, boss)
shlashb = lambda player, boss: attack("slash", 1, 2, 5, boss, player)
kick = lambda player, boss: attack("kick", 1, 1, 1, player, boss)

Это предполагает, что вы все еще хотите указать игрока и босса позже при вызове этих функций. Например, вы бы позвонили kick(player, boss).

Использование functools.partial() здесь не совсем подходит, потому что вы меняете аргументы boss и player; вам нужно просто определить переменную slash и передать аргументы boss и player в правильном порядке:

from functools import partial

slash = partial(attack, 'slash', 1, 2, 5)
kick = partial(attack, 'kick', 1, 1, 1)

Вызов slash или kick добавит любые дополнительные аргументы, поэтому slash(player, boss) вызывает функцию с этими двумя аргументами, добавленными к тем, которые вы уже определили.

Все это предполагает, что вы хотите управлять несколькими игроками и боссами. Если ваши player и boss переменные являются глобальными (возможно, когда-либо будет один игрок и один босс, чтобы сражаться), тогда вы просто передайте их при определении lambda или partial, и вы не передадите дополнительные аргументы. Например:

slashp = partial(attack, 'slash', 1, 2, 5, player, boss)
slashb = partial(attack, 'slash', 1, 2, 5, boss, player)
kick = partial(attack, 'kick', 1, 1, 1, player, boss)

И чтобы игрок ударил босса, достаточно позвонить kick().

Разница между объектом partial и lambda заключается в том, что вы можете проанализировать объект partial; Вы можете легко увидеть, какие аргументы вы определили, чтобы всегда передавать:

>>> from functools import partial
>>> def attack(*args): return args
...
>>> demo = partial(attack, 'kick', 1, 2, 5)
>>> demo.args
('kick', 1, 2, 5)
>>> demo()
('kick', 1, 2, 5)
>>> demo('player1', 'boss2')
('kick', 1, 2, 5, 'player1', 'boss2')

Объект partial нельзя использовать в качестве метода для класса, объект функции может. Используйте functools.partialmethod() объект, если вам нужно использовать эта особенность в классе.

5
Martijn Pieters 17 Дек 2015 в 13:38

Оберните свою функцию в лямбду:

slashp=lambda : attack("slash",1,2,5,player,boss)

Или используйте частичный:

slashp=partial(attack, name="slash",minmultiplier=1,maxmultiplier=2,critchance=5,attacker=player,attackee=boss)
0
Netwave 17 Дек 2015 в 13:31

Именно для этого functools.partial.

Вернуть новый частичный объект, который при вызове будет вести себя как func, вызываемый с помощью аргументов позиционных аргументов и ключевых слов. Если для вызова передается больше аргументов, они добавляются к аргументам. Если предоставляются дополнительные аргументы ключевых слов, они расширяют и переопределяют ключевые слова.

https://docs.python.org/2/library/functools.html#functools.partial

Пример использования:

import functools
slashp = functools.partial("slash",1,2,5,player,boss)
slashp()  # actual call 
1
Łukasz Rogalski 17 Дек 2015 в 13:33

Классы, казалось бы, лучше подходят и обеспечивают большую гибкость в будущем

class AttackType(object):
    def __init__(name, minmult, maxmult, crit):
        self.name = name
        self.minmult = minmult
        self.maxmult = maxmult
        self.crit = crit
    def attack(self, attackee, attacker):
        // all your logic here

kick = AttackType("kick", 1, 1, 1)
##... later
kick(player, boss)
0
dwanderson 17 Дек 2015 в 13:34