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

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

问题描述

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



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



我想想如何将一个main.py文件链接到一个插件文件夹,它包含了每个bot函数在其自己的可尊敬的Python文件。这听起来很简单,除非它涉及到如何调用函数。



这里只是一个基本的看看我的Skype bot,缺少一些较大的功能。

  import Skype4Py,random 

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目前正在用户上运行:%s'%self.skype.CurrentUserHandle

print\\\
\\\
Commands Called:\\\


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

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

如果在self.functions.keys()中的cmd:
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(重新发送输入的消息。 \\\

用法:!说你好。 \\\

例如:Bot:Hello。)

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

除了:
self.context.Chat.SendMessage(请使用 - 信息以正确使用!say命令)

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

if question [1] ==-info:
print%s:8Ball -info%self.caller
self.context.Chat.SendMessage with a answer.\\\

用法:!8ball'我有赃物吗?'\\\

示例:!8Ball Response:'Yes')

else:
random.shuffle(self.results)
answer = self.results [3]
print%s:8Ball [%s]%(self.caller,question [1])$ ​​b $ b self.context.Chat.SendMessage(!8Ball响应:%s%answer)

除了:
self.context.Chat.SendMessage请使用-info来正确使用!8ball命令)

#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

__ init __。py 文件被Python的 import 机制使用,让它知道一个目录包含一个Python包,参见 6.4。有关详细信息,请参阅Python文档中的软件包



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



__ init __。py

  __ all__ = ['plugin_demo','plugins'] 
来自plugintest import *

plugin_demo.py

 #! / usr / bin / env python 

#一个简单的类,将从后续插件目录中获取方法
class Test(object):
def __init __(self,data):
self.data = data

def add_plugins(cls):
import plugins

print将插件方法添加到%s类%cls。 __name__
用于插件中的名称.__ all__:
打印名称
plug = getattr(plugins,name)
打印插件
method = getattr(plug,name)
print method
setattr(cls,name,method)
print
printDone\\\


add_plugins(Test)

def main():
#Now测试一下!
t = Test([1,2,3]); print t.data

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

if __name__ =='__main__':
main()


b $ b

现在是plugintest / plugins /目录的内容:



__ init __。py

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

add.py

  #A方法用于plugin类的plugin_demo.py 
def add(self,m):
self.data = [m + i for i in self.data]



multiply.py

  #A plugin_demo.py的Test类的方法
def multiply(self,m):
self.data = [m * i for i in self.data]

如果您 cd plugintest /文件夹,您应该可以使用



python plugintest / plugin_demo.py p>

如果 cd 到plugintest /本身



python plugin_demo.py



另外,在解释器(或另一个Python程序) do



import plugintest



main()使用


的函数plugin_demo.py

plugintest.plugin_demo.main ()



的其他常见变体来自... import ...



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



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


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.

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.

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.

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 "\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()

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. :)

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. How to add methods to an existing class.
  2. How to import those methods from other source files.

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. :)

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.

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/" has the following structure:

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

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.

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\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()

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]

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

python plugintest/plugin_demo.py

and if you cd to "plugintest/" itself

python plugin_demo.py

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

import plugintest

and then run the main() function of "plugin_demo.py" with

plugintest.plugin_demo.main()

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

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天全站免登陆