python - 如何将我的 Python 文件分离到多个插件?

标签 python function class module skype4py

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

项目:我拥有的是一个使用 Skype4Py 模块的 Skype 机器人。我有大约 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

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

最佳答案

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

一种方法是创建一个不带任何命令方法的基本 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

Python 的 import 机制使用 __init__.py 文件来让它知道某个目录包含 Python 包,请参阅 6.4. Packages在 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 *

add.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/”文件夹的目录,您应该能够运行它

pythonplugintest/plugin_demo.py

如果您cd到“plugintest/”本身

pythonplugin_demo.py

此外,在解释器(或另一个Python程序)中,您应该能够执行以下操作

导入插件测试

然后使用

运行“plugin_demo.py”的 main() 函数

plugintest.plugin_demo.main()

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

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

希望这对您有所帮助,如果您有任何疑问,请随时询问。

关于python - 如何将我的 Python 文件分离到多个插件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26599820/

相关文章:

python - django 数据库更新值

javascript - 如何以对象表示法调用内部 javascript 函数

mysql - MySQL 中的generate_series

在 python 2.4 中模拟 itertools.product 的 Pythonic 方法

python - Python 函数中的列表赋值

javascript - 为什么这个函数没有被调用?

c++ - ',' 或 ';' 之前的预期类名

c++ - 无法弄清楚如何通过仅使用类的函数删除整个链表

c++ - 常量构造器

python - 使用 ProcessPoolExecutor 在执行器中运行 AsyncIO