Невозможно вызвать функцию с помощью строки

1

Я пытаюсь вызвать функцию в классе на основе строки, в которую я прошел.

Я попытался выполнить следующие шаги по этой ссылке: Вызов функции модуля из строки с именем функции в Python

Вот мой код:

methodNameString = "add" + typeOfShip
methodToCall = getattr(listOfPlayerFleets[currentPlayer], methodNameString)

listOfPlayerFleets[currentPlayer].methodToCall(num)

Я получаю сообщение об ошибке:

AttributeError:fleet instance has no attribute 'methodToCall'

Любые идеи относительно того, почему methodToCall не присваивается мое правильное имя метода?

Я также пробовал

methodToCall = getattr(fleet, methodToCall)

то я получаю сообщение:

AttributeError: 'module' object has no attribute 'addCruiser'

Как будто getattr не может найти мои методы в моем классе.

listOfPlayerFleets - это список объектов флота

Вот как выглядит объект флота, который вы видите, что методы действительно существуют.

class fleet:
    """ Stores Fleet Numbers, Represents a fleet """

    ships = {'fighters':0, 'cruisers':0, 'capitols':0}
    attacking = False
    defending = False

    def __init__(self):
        self.ships = {'fighters':0, 'cruisers':0, 'capitols':0}
        self.attacking = False
        self.defending = False

    #add a Fighter
    def addFighter(self, numOfFighters):
        self.ships['fighters'] = numOfFighters


    #add a Cruiser
    def addCruiser(self, numOfCruisers):
        self.ships['cruisers'] = numOfCruisers

    #add a Capitol Ship
    def addCapitol(self, numOfCapitols):
        self.ships['capitols'] = numOfCapitols
  • 1
    Просто чтобы вы знали, ваша функция addShip фактически заменяет количество кораблей, но не добавляет их. Вы можете переименовать его в setShip или что-то еще.
Теги:

4 ответа

3
Лучший ответ

Ваша переменная methodToCall является связанным методом, то есть вам не нужно вызывать ее на объекте - он знает объект, на который он будет вызываться. fleet.addFighter, например, является несвязанным методом. Печать repr(methodToCall) и repr(fleet.addFighter) должна быть понятной.

Вы должны использовать это:

methodNameString = "add" + typeOfShip
methodToCall = getattr(listOfPlayerFleets[currentPlayer], methodNameString)

methodToCall(num)
  • 0
    Эй, это сработало отлично! Спасибо! Намного лучше, чем это другое решение, которое я попробовал. eval ("listOfPlayerFleets [currentPlayer]." + methodNameString + "(" + str (num) + ")"), который сработал, но я слышал, что eval не ваш друг.
  • 0
    @ChickenFur: вызов методов (и получение атрибутов) по строкам "тоже не ваш друг", просто он не так широко проповедуется (возможно, потому, что многие другие языки не заботятся о предоставлении ему отдельных функций, но не оставляют выбора, кроме eval ).
2

Это должно сделать это.

methodNameString = "add" + typeOfShip
methodToCall = getattr(listOfPlayerFleets[currentPlayer], methodNameString)

methodToCall(num)

getattr дает ссылку на метод этого конкретного экземпляра (listOfPlayerFleets[currentPlayer]), поэтому просто вызывайте его с параметрами.

  • 1
    Вы должны проверить, вызывается ли он до: if callable (methodToCall): methodToCall (num)
  • 0
    Спасибо! Я ценю ответ
1

Во-первых, такого рода вещи редко совпадают с правильным решением, например. используя словарь, и даже реже превосходит их. Вы можете использовать метод addShip(kind, num), который просто делает self.ships[kind] += num. Гораздо чище, проще продлить, СУХОЙ (не повторяйте себя) и в качестве дополнительного бонуса также быстрее.

Что касается ошибок: listOfPlayerFleets[currentPlayer].methodToCall(num) пытается вызвать метод с именем methodToCall (который, очевидно, не существует. getattr(listOfPlayerFleets[currentPlayer], methodNameString) уже получил вам метод, который вы хотите, и это связанный метод, т.е. когда вы вызываете methodToCall(), передается правое self.

Другая ошибка ('method' object has no ...) заключается в том, что в ней содержится разница между модулями и вещами (например, классами). Я полагаю, что class fleet находится в модуле под названием fleet? Тогда вам нужно fleet.fleet. Кстати, классы следует называть в CamelCase - см. Руководство по стилю, PEP 8.

  • 0
    Спасибо, это хорошие моменты. Я очень ценю помощь.
0

Вы пробовали

func = getattr(obj, "method")
if callable(func):
  result = func(args)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню