Q:

Calling methods as parameters

total newb when it comes to Python and first post here (although I've used the help pages immensely so far) -- so forgive me if I'm overlooking anything obvious.
I'm trying to use functions from a class as parameters in a function outside of the class and it's not working. Here's my code...
# These are the attributes I use to build my fighter class and their various attack moves.

combat_system.py

Class Attack:
    def __init__(self, name, ST, QU, FL):
        self.name = name       
        self.SP = SP
        self.ST = ST
        self.QU = QU
        self.FL = FL

    def punch(self):
        return int(self.ST + self.QU)

    def kick(self):
        return int(self.ST + self.FL)

# Class instances are built from a dict
Rex = {'name': Rex, 'ST': 5, 'QU': 8, 'FL': 7}
Mac = {'name': Mac, 'ST': 9, 'QU': 3, 'FL': 3}

#And class instances are established in the game.py file

game.py
attacker1 = Attack(Rex['name'], Rex['ST']...
attacker2 = Attack(Mac['name'], Mac['ST']...

I get the desired result when I do this...note this function lives outside of the Attack Class. (attacker1, attacker2, defender1, and defender2 are all Attack Class instances)
combat_system.py

def battle():
    attack1_result = attacker1.punch() - defender1.punch() 
    attack2_result = attacker2.kick() - defender2.kick()
    return attack1_result, attack2_result

But what I want to do is give the gamer the option to choose which move each attacker performs and pass that Attack Class function to the battle function
# gamer makes a choice for each attacker

game.py

    xy = battle(punch, kick)

And I write the code in the battle function as follows...
combat_system.py

    def battle(attack1_move, attack2_move):
        attack1_result = attacker1.attack1_move() - defender1.attack1_move() 
        attack2_result = attacker2.attack2_move() - defender2.attack2_move()
        return attack1_result, attack2_result

I get the following error:

NameError: name 'punch' is not defined

And when I try this-
game.py

    xy = battle(Attack.punch, Attack.kick)

combat_system.py

    def battle(attack1_move, attack2_move):
        attack1_result = attacker1.attack1_move() - defender1.attack1_move() 
        attack2_result = attacker2.attack2_move() - defender2.attack2_move()
        return attack1_result, attack2_result

I get the following error:

AttributeError: 'Attack' has no attribute 'attack1_move'

And lastly, when I try this-
game.py

    xy = battle(Attack.punch(), Attack.kick())

combat_system.py

    def battle(attack1_move, attack2_move):
        attack1_result = attacker1.attack1_move() - defender1.attack1_move() 
        attack2_result = attacker2.attack2_move() - defender2.attack2_move()
        return attack1_result, attack2_result

I get this error:

TypeError: unbound method punch() must be called with Attack instance as first argument (got nothing instead)

Any help on what I'm doing incorrectly would be greatly appreciated. Thanks in advance, and LMK if I've omitted any necessary info in order to provide help.

A:

This is your most promising attempt:
xy = battle(Attack.punch, Attack.kick)

To make that work, you want:
def battle(attack1_move, attack2_move):
    attack1_result = attack1_move(attacker1) - attack1_move(defender1) 
    attack2_result = attack2_move(attacker2) - attack2_move(defender2)
    return attack1_result, attack2_result

The key takeaway here is that typically, my_obj.method(...) is the same as MyClass.method(my_obj, ...)

It's also possible to use
xy = battle('punch', 'kick')

as:
def battle(attack1_move, attack2_move):
    attack1_result = getattr(attacker1, attack1_move)() - getattr(defender1, attack1_move)() 
    attack2_result = getattr(attacker2, attack2_move)() - getattr(defender2, attack2_move)()
    return attack1_result, attack2_result

