关于功能:如何将我的Python文件分成多个插件?

How would I separate my Python File to multiple plugins?

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

项目:我有一个使用Skype4py模块的Skype bot。我有大约11个命令,我注意到一个脚本有点大。

我正在考虑如何将一个m a in.py文件链接到一个plugin文件夹,该文件夹包含它自己的可尊敬的python文件中的每个bot函数。这听起来很简单,除了如何调用函数。

这里只是简单介绍一下我的Skype bot,它缺少一些更大的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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()

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

1
self.skype.OnMessageStatus = self.RunFunction

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


对于这种大小的程序来说,不需要将命令函数放在单独的文件中,但我想这是一个很好的组织。以及编写具有数千行代码的程序时的良好实践。:)

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

所以我们可以把你的问题分成两部分:

  • 如何向现有类添加方法。
  • 如何导入这些方法来自其他源文件。
  • 如我所说,1)很容易。2)也很容易,但我以前从未做过,所以我不得不做一些研究和测试,我不能保证我所做的是最佳实践,但它是有效的。:)

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

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

    "pluginst/"具有以下结构:

    1
    2
    3
    4
    5
    6
    7
    plugintest/
        __init__.py
        plugin_demo.py
        plugins/
            __init__.py
            add.py
            multiply.py

    python的import机器使用__init__.py文件让它知道一个目录包含一个python包,见6.4。有关详细信息,请参阅python文档中的包。

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

    _初始版本

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

    插件_demo.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    #! /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()

    现在"pluginst/plugins/"目录的内容是:

    _初始版本

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

    Ad.Py

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

    乘法.py

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

    如果您将cx1〔2〕添加到包含"pluginst/"文件夹的目录中,您应该能够使用

    埃多克斯1〔3〕

    如果你把1〔2〕改为"pluginst/"。

    埃多克斯1〔5〕

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

    埃多克斯1〔6〕

    然后运行插件demo.py的main()功能

    埃多克斯1〔8〕

    其他常见的from ... import ...等变化也应如预期的那样起作用。

    "plugin-demo.py"中执行将导入方法添加到Test类的魔力的函数是add_plugins()。运行时,它会打印出每个方法名、模块及其函数。这在开发过程中可能很方便,但是一旦程序正常运行,您可能会对其中一些打印语句进行注释。

    我希望这有帮助,如果你有任何问题,请不要犹豫。