无法通过字符串调用函数

1 投票
4 回答
2294 浏览
提问于 2025-04-16 11:14

我想根据我传入的字符串来调用一个类里的函数。

我试着按照这个链接里的步骤操作:从字符串中调用模块的函数

这是我的代码:

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

4 个回答

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。顺便提一下,类的命名应该使用驼峰命名法,具体可以参考风格指南 PEP 8

2

这样就可以了。

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

methodToCall(num)

getattr这个东西可以让你拿到某个特定实例(比如listOfPlayerFleets[currentPlayer])的方法的引用,所以你只需要用参数去调用它就行了。

3

你的 methodToCall 变量是一个绑定的方法,这意味着你不需要在一个对象上去调用它——它已经知道自己会在哪个对象上被调用。比如说,fleet.addFighter 是一个未绑定的方法。打印 repr(methodToCall)repr(fleet.addFighter) 会让这个区别变得更清楚。

你应该使用这个:

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

methodToCall(num)

撰写回答