2

所以我想说的第一件事是:我一直在研究模块等,我只是不知道如何重写它以适应它。

项目:我拥有的是一个使用 Skype4Py 模块的 Skype Bot。我有大约 11 个命令,我注意到一个脚本变得有点大。

我正在尝试考虑如何将一个 main.py 文件链接到一个插件文件夹,该文件夹包含它自己受人尊敬的 Python 文件中的每个机器人函数。这听起来很简单,除了函数的调用方式。

这里只是对我的 Skype 机器人的基本介绍,缺少一些更大的功能。

import Skype4Py, random

class SkypeBot():

    def __init__(self):
        self.skype = Skype4Py.Skype()

        if self.skype.Client.IsRunning == False:
            self.skype.Client.Start()

        self.skype.Attach()

        self.results = ['Yes', 'No', 'Maybe', 'Never']

    def main(self):
        print '       Skype Bot currently running on user: %s' % self.skype.CurrentUserHandle

        print "\n\nCommands Called:\n"

        while True:
            self.skype.OnMessageStatus = self.RunFunction

    def RunFunction(self, Message, Status):
        if Status == 'SENT' or Status == 'RECEIVED':
            cmd = Message.Body.split(' ')[0]

            if cmd in self.functions.keys():
                self.context = Message
                self.caller = self.context.FromHandle
                self.functions[cmd](self)

    def ping(self):
        print "    %s : Ping" % self.caller
        self.context.Chat.SendMessage('Pong')

    def say(self):
        try:
            response = self.context.Body.split(' ', 1)

            if response[1] == "-info":
                print "    %s : say -info" % self.caller
                self.context.Chat.SendMessage("Resends the message entered. \n"
                                              "Usage: !say Hello. \n"
                                              "Example: Bot: Hello.")

            else:
                say = response[1]
                print "    %s : Say [%s]" % (self.caller, say)
                self.context.Chat.SendMessage(say)

        except:
            self.context.Chat.SendMessage("Please use -info to properly use the !say command")

    def eightball(self):
        try:
            question = self.context.Body.split(' ', 1)

            if question[1] == "-info":
                print "    %s : 8Ball -info" % self.caller
                self.context.Chat.SendMessage("Responds with an answer.\n"
                                              "Usage: !8ball 'Do I have swag?'\n"
                                              "Example: !8Ball Response: 'Yes'")

            else:
                random.shuffle(self.results)
                answer = self.results[3]
                print "    %s : 8Ball [%s]" % (self.caller, question[1])
                self.context.Chat.SendMessage("!8Ball Response: %s" % answer)

        except:
            self.context.Chat.SendMessage("Please use -info to properly use the !8ball command")

    #FUNCTIONS LIST
    #********************

    functions = {
    "!ping": ping,
    "!say": say,
    "!8ball": eightball,
    }


if __name__ == "__main__":
    snayer = SkypeBot()
    snayer.main()

所以基本上,我想知道的是,我该如何改变

self.skype.OnMessageStatus = self.RunFunction

以便它运行另一个文件中的函数?

4

1 回答 1

2

对于这种大小的程序,实际上没有必要将您的命令函数放入单独的文件中,但我想这是一个很好的组织。当您编写具有数千行代码的程序时,这是一种很好的做法。:)

一种方法是创建一个没有任何命令方法的基本 SkypeBot 类,然后从插件目录导入命令方法并将它们添加到类中。将新属性添加到现有类很容易,并且无论新属性是属性还是方法,添加它们的语法都是相同的。(稍微多做一点工作,甚至可以为实例添加新属性,因此您可以拥有多个实例,每个实例都有自己的一组命令。但我想这里没有必要,因为使用 SkypeBot 类的程序通常只会创建一个实例)。

因此,我们可以将您的问题分为两部分:

  1. 如何向现有类添加方法。
  2. 如何从其他源文件中导入这些方法。

正如我所说,1)很容易。2)也很容易,但我以前从未做过,所以我不得不做一些研究和测试,我不能保证我所做的就是最佳实践,但它确实有效。:)

我对Skype不太了解,也没有那个Skype4Py模块,而且正如你所说,上面的代码不是完整的程序,所以我写了一些相当简单的代码来说明添加插件方法的过程从单独的文件到现有的类。

主程序的名称是“plugin_demo.py”。为了保持整洁,它位于自己的目录“plugintest/”中,您应该在 Python 路径中的某个位置(例如,您通常保存 Python 程序的位置)创建该目录。此路径必须在您的 PYTHONPATH 环境变量中指定。

“plugintest/”具有以下结构:

plugintest/
    __init__.py
    plugin_demo.py
    plugins/
        __init__.py
        add.py
        multiply.py

__init__.pyPython 的机器使用这些文件import来让它知道一个目录包含一个 Python 包,见6.4。Python 文档中的包以获取更多详细信息。

以下是这些文件的内容。首先,进入“plugintest/”本身的文件:

__init__.py

__all__ = ['plugin_demo', 'plugins']
from plugintest import *

plugin_demo.py

#! /usr/bin/env python

#A simple class that will get methods added later from plugins directory
class Test(object):
    def __init__(self, data):
        self.data = data

def add_plugins(cls):
    import plugins

    print "Adding plugin methods to %s class" % cls.__name__
    for name in plugins.__all__:
        print name
        plug = getattr(plugins, name)
        print plug
        method = getattr(plug, name)
        print method
        setattr(cls, name, method)
        print
    print "Done\n"

add_plugins(Test)

def main():
    #Now test it!
    t = Test([1, 2, 3]); print t.data

    t.multiply(10); print t.data
    t.add(5); print t.data

if __name__ == '__main__':  
    main()

现在“plugintest/plugins/”目录的内容:

__init__.py

__all__ = ['add', 'multiply']
from plugintest.plugins import *

添加.py

#A method for the Test class of plugin_demo.py
def add(self, m):
    self.data = [m + i for i in self.data]

乘法.py

#A method for the Test class of plugin_demo.py
def multiply(self, m):
    self.data = [m * i for i in self.data]

如果你cd到包含“plugintest/”文件夹的目录,你应该能够运行它

python plugintest/plugin_demo.py

如果你cd要“plugintest/”本身

python plugin_demo.py

此外,在解释器(或另一个 Python 程序)中,您应该能够做到

import plugintest

然后运行main()“plugin_demo.py”的功能

plugintest.plugin_demo.main()

from ... import ...etc的其他常见变体也应该按预期工作。

“plugin_demo.py”中执行将导入的方法添加到Test类的魔术的函数是add_plugins(). 当它运行时,它会打印出每个方法名称、它的模块和它的功能。这在开发过程中可能很方便,但是一旦程序正常工作,您可能会注释掉其中一些打印语句。

我希望这会有所帮助,如果您有任何问题,请随时提出。

于 2014-10-29T05:46:32.237 回答