我正在使用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
中将这么多逻辑放在一边是一个坏主意,但在这方面我是新的,我不是肯定的。
还有改进的余地吗?如果是这样,怎么样?
(我试图回避插件实际做的事情,因为我正在寻找编码风格评论而不是对数评论,但如果你需要查看外部库中的代码,整个插件是在here)
答案 0 :(得分:3)
我从来没有做过GEdit插件,所以我无法评论__init__.py问题,但一般说明:
没有调用父级的__init__而没有新的args冗余 - 你能不能只取出那两行?
您创建的局部变量比我想象的多。我不得不四处寻找价值来自哪里,或者是否再次使用它。例如:
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代码。
答案 1 :(得分:2)
也许您想将其移动到名为zen_plugin.py
然后制作__init__.py
from zen_plugin import ZenCodingPlugin
答案 2 :(得分:1)
我会尝试从长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/上询问此类事情。
答案 3 :(得分:1)
如果您只有一个文件,那么您的目录结构可能看起来像
pluginname
`- __init__.py
在这种情况下,您可以将项目展平为
pluginname.py
如果您以后需要包中的其他模块,可以转到
pluginname
+- __init__.py
`- plugin.py
其中plugin.py
包含此类,__init__.py
放置
from pluginname.plugin import ZenCodingPlugin
这样以前使用from pluginname import ZenCodingPlugin
或import pluginname; pluginname.ZenCodingPlugin
的任何内容都可以使用。
答案 4 :(得分:-3)
这是gui代码并且总是冗长,我最好的建议是:它有效吗?好。下一个任务!