2

我正在使用 Python(和 PyGTK)开发一个 Gedit 插件,我真的没有用 Python 工作过很多,所以我不知道我是否正在编写 Pythonic 代码。

我自己的所有代码都包含在__init__.py. 还有一些其他文件,但它们来自我正在连接的外部库。我__init__.py的如下:

#
# @file __init__.py
# Does the heavy lifting behind connecting Zen Coding to Gedit.
#

import gedit, gobject, string, gtk, re, zen_core

class ZenCodingPlugin(gedit.Plugin):
    """
    A Gedit plugin to implement Zen Coding's HTML and CSS shorthand expander.

    This file adds the menu items and keyboard shortcuts to the UI and connects
    those items with the good stuff (i.e., the code expansion).
    """

    def __init__(self):
        gedit.Plugin.__init__(self)

    def activate(self, window):
        "Gedit callback: install the expansion feature into the UI"

        ui_manager = window.get_ui_manager()
        action_group = gtk.ActionGroup("GeditZenCodingPluginActions")

        # Create the GTK action to be used to connect the key combo
        # to the Zen Coding expansion (i.e., the good stuff).
        complete_action = gtk.Action(name="ZenCodingAction",
                                     label="Expand Zen code...",
                                     tooltip="Expand Zen Code in document to raw HTML",
                                     stock_id=gtk.STOCK_GO_FORWARD)

        # Connect the newly created action with key combo
        complete_action.connect("activate",
                                lambda a: self.expand_zencode(window))
        action_group.add_action_with_accel(complete_action,
                                           "<Ctrl><Shift>E")

        ui_manager.insert_action_group(action_group, 0)

        # @TODO: Figure out what these lines do
        ui_merge_id = ui_manager.new_merge_id()
        ui_manager.add_ui(ui_merge_id,
                          "/MenuBar/EditMenu/EditOps_5",
                          "ZenCoding",
                          "ZenCodingAction",
                          gtk.UI_MANAGER_MENUITEM, False)
        ui_manager.__ui_data__ = (action_group, ui_merge_id)

    def deactivate(self, window):
        "Gedit callback: get rid of the expansion feature"

        ui_manager = window.get_ui_manager()
        (action_group, ui_merge_id) = ui_manager.__ui_data__

        # Remove the UI data, action group, and UI itself from Gedit
        del ui_manager.__ui_data__
        ui_manager.remove_action_group(action_group)
        ui_manager.remove_ui(ui_merge_id)


    def expand_zencode(self, window):
        "The action which handles the code expansion itself."

        view = window.get_active_view()
        buffer = view.get_buffer()

        # Grab the current cursor position.
        cursor_iter = buffer.get_iter_at_mark(buffer.get_insert())

        # Grab the first character in the line.
        line_iter = cursor_iter.copy()
        line_iter.set_line_offset(0)

        # Grab the text from the start of the line to the cursor.
        line = buffer.get_text(line_iter, cursor_iter)

        # Find the last space in the line and remove it, setting a variable
        # 'before' to the current line.
        words = line.split(" ")
        before = words[-1].lstrip()
        if not before:
            return

        # Get the language of the current document. Second line prevents an error
        # if first line returns None.
        lang = window.get_active_document().get_language()
        lang = lang and lang.get_name()

        # Using the 'before' variable, convert it from Zen Code
        # to expanded code. If there isn't anything, just return.
        if lang == 'CSS':
            after = zen_core.expand_abbreviation(before,'css','xhtml')
        else:
            after = zen_core.expand_abbreviation(before,'html','xhtml')
        if not after:
            return

        # Grab the line's indentation and store it.
        indent = re.match(r"\s*", line).group()

        # Automatically indent the string and replace \t (tab) with the
        # correct number of spaces.
        after = zen_core.pad_string(after,indent)
        if view.get_insert_spaces_instead_of_tabs():
            tabsize = view.get_tab_width()
            spaces = " " * tabsize
            after = after.replace("\t",spaces)

        # We are currently lame and do not know how to do placeholders.
        # So remove all | characters from after.
        after = after.replace("|", "")

        # Delete the last word in the line (i.e., the 'before' text, aka the
        # Zen un-expanded code), so that we can replace it.
        word_iter = cursor_iter.copy()
        position_in_line = cursor_iter.get_line_index() - len(before)
        word_iter.set_line_index(position_in_line)
        buffer.delete(word_iter, cursor_iter)

        # Insert the new expanded text.
        buffer.insert_at_cursor(after)

我只是在问,因为上面的内容似乎不是非常面向对象的,将这么多逻辑放入其中让我觉得是个坏主意__init__.py,但是在这方面是新手,我不确定。

有没有改进的余地?如果是这样,怎么做?

(我试图回避插件的实际作用,因为我更多的是寻找编码风格审查而不是对数审查,但如果您需要查看外部库中的代码,整个插件都在这里

4

5 回答 5

3

我从来没有做过 GEdit 插件,所以我无法评论 __init__.py 问题,但一般注意事项:

  • 在没有新参数的情况下调用父母的 __init__ 不是多余的——你不能把这两行去掉吗?

  • 您创建的局部变量比我创建的要多。我不得不继续四处寻找价值的来源,或者是否再次使用它。例如:

    tabsize = view.get_tab_width()
    spaces = " " * tabsize
    after = after.replace("\t",spaces)
    

    可能:

    after = after.replace("\t", " " * view.get_tab_width())
    
  • 这里有点冗余:

    if lang == 'CSS':
        after = zen_core.expand_abbreviation(before,'css','xhtml')
    else:
        after = zen_core.expand_abbreviation(before,'html','xhtml')
    

    相比:

    after = zen_core.expand_abbreviation(before, 'css' if lang == 'CSS' else 'html', 'xhtml')
    

除此之外,在我看来,它看起来像是相当不错的 Python 代码。

于 2010-02-17T22:29:00.953 回答
2

也许您想将其移动到一个名为zen_plugin.py

然后让你的__init__.py

from zen_plugin import ZenCodingPlugin
于 2010-02-17T22:21:33.677 回答
1

我会尝试从 long 中提取一些函数expand_zencode()。例如,像一个expand_tabs()。这在某种程度上是一个品味问题,但每当我看到一个“游记”,其中的注释指出了“景点”时,强烈建议将每个函数重构为带有文档注释的函数。(不一定是一对一的;我没有精力/知识来获得有关此功能的详细建议。)此更改自动解决了 Ken 关于跟踪局部变量的抱怨。

顺便说一句,您对制表符扩展有一个奇怪的定义:将每个制表符更改为制表符空格。我想是有原因的。

这是不需要的:

def __init__(self):
    gedit.Plugin.__init__(self)

before变量的代码似乎与它的注释不符。(而且.lstrip()是多余的,不是吗?)

有时参数之间有空格,有时没有;IIRC Python 风格指南希望您始终如一地使用空格。(foo(x, y)而不是foo(x,y)。)

你班的评论说:“这个文件增加了......”。那不应该是“这个插件添加...”吗?

考虑在http://refactormycode.com/上询问此类问题。

于 2010-02-17T22:33:27.803 回答
1

如果您只有一个文件,那么您的目录结构可能看起来像

pluginname
`- __init__.py

在这种情况下,您可以将项目展平为

pluginname.py

如果您以后需要包中的其他模块,您可以访问

pluginname
+- __init__.py
`- plugin.py

这门课plugin.py在哪里?__init__.py

from pluginname.plugin import ZenCodingPlugin

这样,以前使用from pluginname import ZenCodingPluginimport pluginname; pluginname.ZenCodingPlugin仍然可以使用的任何东西。

于 2010-02-17T23:16:28.967 回答
-3

它是 gui 代码,而且总是很冗长,我最好的建议是:它有效吗?好的。下一个任务!

于 2010-02-17T22:51:27.437 回答