我的 Python 代码还有改进的空间吗?
我正在使用 Python(和 PyGTK)开发 Gedit 插件,但我确实没有太多使用 Python,所以我不知道我是否在编写 Python 代码。
我自己的所有代码都包含在 __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,但作为新手,我不确定。
还有改进的空间吗?如果是这样,怎么办?
(我试图回避该插件的实际功能,因为我更多地寻找编码风格审查而不是对数审查,但如果您需要查看外部库中的代码,整个插件位于 此处)
I'm working on a Gedit plugin using Python (and PyGTK) and I really havent' worked with Python much so I have no idea if I'm writing Pythonic code.
All of my own code is contained in __init__.py
. There are a few other files, but they're from an outside library that I'm hooking into. My __init__.py
is as follows:
#
# @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)
I'm just asking because the above doesn't seem very object oriented and it kind of strikes me as a bad idea to put this much logic in __init__.py
, but being new at this, I'm not sure.
Is there room for improvement? If so, how?
(I'm trying to shy away from what the plugin actually does because I'm looking more for a coding style review than a logarithm review, but if you need to see the code from the outside library, the whole plugin is at here)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我从来没有做过 GEdit 插件,所以我无法评论 __init__.py 问题,但一般注意事项:
Isn't Calling Parent's __init__ without new args extra--can't you just take out those 2 行?
你创建的局部变量比我多。我必须不断环顾四周,看看某个值从哪里来,或者它是否被再次使用。例如:
可能是:
这里有一点冗余:
比较:
除此之外,在我看来,它看起来是相当不错的 Python 代码。
I've never done a GEdit plugin, so i can't comment on the __init__.py issue, but general notes:
Isn't calling parent's __init__ with no new args redundant -- can't you just take out those 2 lines?
You create more local variables than I would have. I had to keep looking around to see where a value came from, or if it's used again. For example:
could be:
A little redundancy here:
compare:
Other than that, it looks like pretty decent Python code to my eye.
也许您想将其移动到名为
zen_plugin.py
的文件中,然后创建您的
__init__.py
Perhaps you want to move it into a file called
zen_plugin.py
Then make your
__init__.py
我会尝试从长的
expand_zencode()
中提取一些函数。例如,类似于expand_tabs()
。这在某种程度上是一个品味问题,但每当我看到带有注释的“游记”沿途指出“景点”时,这都是一个强烈的暗示,需要重构为每个带有文档注释的函数。 (不一定是一对一的;我没有精力/知识来获取有关此函数的详细建议。)此更改自动解决了 Ken 关于跟踪局部变量的抱怨。顺便说一句,您对制表符扩展有一个奇怪的定义:将每个制表符更改为制表符大小的空格。我想是有原因的
这是不需要的:
before
变量的代码似乎与其注释不匹配。 (.lstrip()
是多余的,不是吗?)有时参数之间有空格,有时则没有; IIRC Python 风格指南希望您始终如一地使用空格。 (
foo(x, y)
而不是foo(x,y)
。)您班级的注释是:“此文件添加...”。不应该是“这个插件添加了...”吗?
考虑在 http://refactormycode.com/ 上询问此类问题。
I would try to extract some functions from the long
expand_zencode()
. Like anexpand_tabs()
, for example. That's a matter of taste to some extent, but whenever I see a 'travelogue' with comments pointing out 'sights' along the way, it's a strong hint to refactor into functions each with a doc comment instead. (Not necessarily one-to-one; I don't have the energy/knowledge for detailed advice on this function.) This change automatically addresses Ken's complaint about keeping track of the local variables.BTW, you have an odd definition of tab-expansion: changing each tab character to tabsize spaces. I suppose there's a reason.
This is unneeded:
The code for the
before
variable doesn't seem to match its comment. (And the.lstrip()
is redundant, isn't it?)You sometimes have spaces between arguments and sometimes not; IIRC the Python style guide wants you to consistently use spaces. (
foo(x, y)
and notfoo(x,y)
.)Your class's comment says: "This file adds...". Shouldn't that be "This plugin adds..."?
Consider asking this sort of thing on http://refactormycode.com/ instead.
如果您只有一个文件,那么您的目录结构可能如下所示
在这种情况下,您可以将项目展平为
如果您稍后需要包中的其他模块,您可以转到
plugin.py
有此文件的位置其中的类和__init__.py
put这样,以前使用
from pluginname import ZenCodingPlugin
或import pluginname; 的任何内容都可以这样放置。 pluginname.ZenCodingPlugin
仍然可以工作。If you only have the one file then your directory structure probably looks like
In this case you can just flatten your project to
If you later need other modules in your package you could go to
where
plugin.py
has this class in it and in__init__.py
putThis way anything that was previously using
from pluginname import ZenCodingPlugin
orimport pluginname; pluginname.ZenCodingPlugin
would still work.它是 GUI 代码,而且总是很冗长,我最好的建议是:它有效吗?好的。下一个任务!
It's gui code and is always verbose, my best advice is: does it work? good. Next Task !