我如何将我的 Python 文件分离到多个插件? [英] How would I separate my Python File to multiple plugins?

查看:18
本文介绍了我如何将我的 Python 文件分离到多个插件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

So first thing I want to say: I have been looking into modules and such, I just don't quiet know how I would rewrite it to fit this in.

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

Project: What I have is a Skype Bot using the Skype4Py module. I have about 11 commands I noticed the one script is getting a little large.

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

I'm trying to think about how to link one main.py file to a Plugin Folder, which contains each and every bot function in it's own respectable Python file. It sounds simple an all, except when it comes to how the function is called.

这里只是对我的 Skype 机器人的基本了解,缺少一些较大的功能.

Here is just a basic look at my Skype bot, missing some of the larger functions.

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 "

Commands Called:
"

        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. 
"
                                              "Usage: !say Hello. 
"
                                              "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.
"
                                              "Usage: !8ball 'Do I have swag?'
"
                                              "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()

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

So basically, what I am wondering, how can I change

self.skype.OnMessageStatus = self.RunFunction

所以它会从另一个文件运行函数?

so that it'll run functions from another file?

推荐答案

对于这种规模的程序来说,将命令函数放入单独的文件中并不是必要,但我想是一个很好的组织.以及编写包含数千行代码的程序的良好实践.:)

For a program of this size it's not really necessary to put your command functions into separate files, but I guess it is good organization. And good practice for when you write a program that has thousands of lines of code. :)

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

One way to do this is to create a basic SkypeBot class without any command methods and then import the command methods from your plugins directory and add them to the class. It's easy enough to add new attributes to an existing class, and it doesn't matter if the new attributes are properties or methods, the syntax to add them is identical. (With a tiny bit more work it's even possible to add new attributes to an instance, so you can have multiple instances, each with their own individual set of commands. But I guess that's not necessary here, since a program that uses the SkypeBot class will normally only create a single instance).

所以我们可以将您的问题分为两部分:

So we can break your question into two parts:

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

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

As I said, 1) is easy. 2) is quite easy as well, but I've never done it before, so I had to do a little bit of research and testing, and I can't promise that what I've done is best practice, but it works. :)

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

I don't know much about Skype, and I don't have that Skype4Py module, and as you said, the code above is not the complete program, so I've written some fairly simple code to illustrate the process of adding plugin methods from separate files to an existing class.

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

The name of the main program is "plugin_demo.py". To keep things neat, it lives in its own directory, "plugintest/", which you should create somewhere in your Python path (eg where you normally keep your Python programs). This path must be specified in your PYTHONPATH environment variable.

plugintest/"具有以下结构:

"plugintest/" has the following structure:

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

__init__.py 文件由 Python 的 import 机制使用,以使其知道目录包含 Python 包,请参阅 6.4.Python 文档中的包以获取更多详细信息.

The __init__.py files are used by Python's import machinery to let it know that a directory contains a Python package, see 6.4. Packages in the Python docs for further details.

这是这些文件的内容.首先,进入plugintest/"本身的文件:

Here are the contents of those files. Firstly, the files that go into "plugintest/" itself:

__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
"

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/"目录的内容:

And now the contents of the "plugintest/plugins/" directory:

__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]

multiply.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/"文件夹的目录,你应该可以用

If you cd to the directory containing the "plugintest/" folder, you should be able to run it with

python plugintest/plugin_demo.py

如果你cd到plugintest/"本身

and if you cd to "plugintest/" itself

python plugin_demo.py

此外,在解释器(或其他 Python 程序)中,您应该可以做到

Also, in the interpreter (or another Python program), you should be able to do

导入插件测试

然后用

plugintest.plugin_demo.main()

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

The other usual variations of from ... import ... etc should also work as expected.

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

The function in "plugin_demo.py" that performs the magic of adding the imported methods to the Test class is add_plugins(). When it runs it prints out each method name, its module, and its function. This could be handy during development, but you'd probably comment out some of those print statements once the program's working properly.

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

I hope this helps, and if you have any questions please don't hesitate to ask.

这篇关于我如何将我的 Python 文件分离到多个插件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆