我尝试让我的代码变得傻瓜,但我注意到输入内容需要花费大量时间,而且需要更多时间来阅读代码。
而不是:
class TextServer(object):
def __init__(self, text_values):
self.text_values = text_values
# <more code>
# <more methods>
我倾向于写这个:
class TextServer(object):
def __init__(self, text_values):
for text_value in text_values:
assert isinstance(text_value, basestring), u'All text_values should be str or unicode.'
assert 2 <= len(text_value), u'All text_values should be at least two characters long.'
self.__text_values = frozenset(text_values) # <They shouldn't change.>
# <more code>
@property
def text_values(self):
# <'text_values' shouldn't be replaced.>
return self.__text_values
# <more methods>
我的python编码风格是否偏执?或者有没有办法提高可读性,同时保持万无一失?
<
和>
之间添加了评论,仅供澄清。答案 0 :(得分:12)
以下是this page对Python习语的一些好建议:
捕获错误而不是避免它们以避免在特殊情况下使代码混乱。这个成语被称为EAFP(“更容易请求宽恕而不是许可”),而不是LBYL(“在你跳跃之前看”)。这通常使代码更具可读性。例如:
更糟:
#check whether int conversion will raise an error
if not isinstance(s, str) or not s.isdigit:
return None
elif len(s) > 10: #too many digits for int conversion
return None
else:
return int(str)
更好:
try:
return int(str)
except (TypeError, ValueError, OverflowError): #int conversion failed
return None
(请注意,在这种情况下,第二个版本要好得多,因为它正确处理前导+和 - ,并且值也在200到100亿之间(对于32位机器)。不要通过预期来混淆代码所有可能的失败:只需尝试并使用适当的异常处理。)
答案 1 :(得分:9)
“我的python编码风格是否过于偏执?还是有办法提高可读性,同时保持它的万无一失?”
你是傻瓜谁是保护自己的?
您?您是否担心自己不记得自己编写的API?
同行?您是否担心下一个小隔间中的某个人会积极努力通过API传递错误的内容?您可以与他们交谈以解决此问题。如果您提供文档,它会节省大量代码。
一个完整的反社会人员会下载您的代码,拒绝阅读API文档,然后使用不正确的参数调用所有方法?您可以为他们提供哪些帮助?
“傻瓜式”编码并不是非常有用,因为所有这些场景都更容易以另一种方式解决。
如果你是对自己的傻瓜,也许这不是真的明智。
如果你是一个同事或同伴的傻瓜,你应该 - 或许 - 与他们交谈并确保他们理解API文档。
如果你对一些想要破坏API的假想的反社会程序员进行万无一失,那么你无能为力。这是Python。他们有源头。当他们可以编辑源代码来破坏事物时,为什么他们会努力滥用API呢?
答案 2 :(得分:3)
在Python中使用私有实例属性,然后通过属性公开它是不常见的。只需使用self.text_values
。
答案 3 :(得分:3)
您的代码太偏执(特别是当您只想保护自己时)。
在Python圈子里,LBYL通常(但并不总是)不赞成。 但还有(经常没有说明)假设一个人有(好的)单元测试。
我个人?我认为可读性至关重要。我的意思是,如果你你自己认为它很难读,其他人会怎么想?而不太可读的代码也更容易捕获错误。更不用说让它更难/更耗时(你必须挖掘以找到所有LBYLing中实际所做的的代码)
答案 4 :(得分:2)
如果你试图使你的代码完全万无一失,那么有人会发明一个更好的傻瓜。说真的,一个好的经验法则是防止可能的错误,但不要弄乱你的代码,试着想一想调用者可能会打破你的每一种可能的方式。
答案 5 :(得分:2)
而不是花时间在assert
和私有变量,我更喜欢花时间在文档和测试用例中。我更喜欢阅读文档,当我必须阅读代码时,我更喜欢阅读测试。更多的代码成长更为真实。同时,测试为您提供了一个简单的代码和有用的用例。
答案 6 :(得分:2)
我需要对错误检查代码进行检查,以确定它所检查的错误的后果。如果垃圾数据进入我的系统,我发现它之前会有多长时间,确定问题是垃圾数据有多难,修复有多困难?对于像您发布的那样的案例,答案通常“不长”,“不难”,“并不困难”。
但数据会在某个地方持续存在,然后在六周内用作复杂算法的输入?我会检查出来的。
答案 7 :(得分:0)
我认为这不是特定于python的。我坚信合同设计:理想情况下,所有功能都应该有明确的前后条件;不幸的是,大多数语言(埃菲尔是规范的例外)并没有提供特别方便的方法来实现这一点,这有助于澄清和正确之间的明显冲突。
实际上,一种方法是编写'checkValues'方法,以避免混乱__init__
。您甚至可以将其压缩为:
def __init__(self, text_values):
self.text_values = checkValues( text_values )
def checkValues(text_values):
for text_value in text_values:
assert isinstance(text_value, basestring), u'All text_values should be str or unicode.'
assert 2 <= len(text_value), u'All text_values should be at least two characters long.'
return( frozenset( text_values ) )
另一种方法是使用折叠文本编辑器,可以借助一些评论惯例隐藏/显示前置条件;这对于自动生成文档也很有用。
答案 8 :(得分:0)
将你所有的精力放在参数检查中,并将其转换为编写清晰,简洁的文档字符串。
除非您正在为核反应堆编写代码;在这种情况下,我很感谢你两个都做。
答案 9 :(得分:0)
另一种思考方式是:您只需要捕获可以纠正的错误。如果你正在检查输入只是为了用AssertionError
中止,你最好只是允许代码稍后引发相应的异常,这样你就可以正确调试。
这条线特别糟糕,因为它会阻止鸭子输入:
assert isinstance(text_value, basestring), u'All text_values should be str or unicode.'