6

我试图让我的代码万无一失,但我注意到输入内容需要很多时间,阅读代码需要更多时间。

代替:

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 编码风格是否过于偏执?或者有没有办法在提高可读性的同时保持它的万无一失?

  • 注 1:我在 和 之间添加了评论<>只是为了澄清。
  • 注意2:我试图防止滥用我的代码的主要傻瓜是我未来的自我
4

10 回答 10

12

以下是此页面中有关 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

(请注意,在这种情况下,第二个版本要好得多,因为它可以正确处理前导 + 和 - 以及 2 到 100 亿之间的值(对于 32 位机器)。不要通过预测所有可能的失败:试一试并使用适当的异常处理。)

于 2009-12-26T15:01:41.853 回答
9

“我的 python 编码风格是不是太偏执了?或者有没有办法在提高可读性的同时保持它的万无一失?”

你在保护自己免受谁的愚弄?

你?您是否担心不记得自己编写的 API?

一个梨?您是否担心隔壁隔间中的某个人会积极努力通过 API 传递错误的东西?您可以与他们交谈以解决此问题。如果您提供文档,它会节省大量代码。

一个彻头彻尾的反社会者,他会下载你的代码,拒绝阅读 API 文档,然后用不正确的参数调用所有方法?你能为他们提供什么可能的帮助?

“万无一失”的编码并不是很有帮助,因为所有这些情况都可以通过另一种方式更容易地解决。

如果你对自己采取了万无一失的做法,也许这并不明智。

如果您想为同事或同行做傻事,您应该 - 也许 - 与他们交谈并确保他们理解 API 文档。

如果您要对一些想颠覆 API 的假设性反社会程序员进行万无一失,那么您无能为力。是蟒蛇。他们有来源。当他们可以编辑源代码来破坏事物时,他们为什么还要努力滥用 API?

于 2009-12-26T15:08:03.683 回答
3

在 Python 中使用私有实例属性,然后像你一样通过属性公开它是不常见的。只需使用self.text_values.

于 2009-12-26T15:08:16.553 回答
3

您的代码太偏执了(尤其是当您只想保护自己时)。

在 Python 圈子中,LBYL 通常(但并非总是)不受欢迎。也有一个(通常未说明的)假设,即一个人有(好的)单元测试。

我个人?我认为可读性是最重要的。我的意思是,如果您自己认为它很难阅读,那么其他人会怎么想?而且可读性较差的代码也更有可能捕获错误。更不用说使工作更难/更耗时(您必须深入了解代码在所有 LBYLing 中的实际作用)

于 2009-12-26T15:29:01.067 回答
2

如果你试图让你的代码完全万无一失,那么有人会发明一个更好的傻瓜。说真的,一个好的经验法则是防止可能的错误,但不要弄乱你的代码,试图想出调用者可能破坏你的每一种可能的方式。

于 2009-12-26T15:35:57.387 回答
2

而不是花时间在assert私有变量上,我更喜欢花时间在文档和测试用例上。我更喜欢阅读文档,当我必须阅读代码时,我更喜欢阅读测试。越多的代码越多,这就越真实。同时测试给你一个万无一失的代码和有用的用例。

于 2009-12-26T16:30:21.920 回答
2

我将错误检查代码的需求建立在它正在检查的错误的后果上。如果垃圾数据进入我的系统,我需要多长时间才能发现它,确定问题是垃圾数据的难度如何,修复的难度有多大?对于您发布的案例,答案通常是“不长”、“不难”和“不难”。

但是数据会被保存在某个地方,然后在六周内用作复杂算法的输入吗?我会检查一下。

于 2009-12-26T18:55:54.517 回答
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 ) )

另一种方法是使用折叠文本编辑器,它可以借助一些注释约定隐藏/显示先决条件;这对于自动生成文档也很有用。

于 2011-06-06T15:46:24.537 回答
0

把你投入到论证检查中的所有精力投入到编写清晰、简洁的文档字符串中。

除非你正在为核反应堆编写代码;在这种情况下,我会很感激你两者都做。

于 2011-06-07T21:39:30.863 回答
0

另一种思考方式是:您只需要捕获可以纠正的错误。如果您检查输入只是为了用 中止AssertionError,您最好只允许代码稍后引发适当的异常,以便您可以正确调试。

这条线特别糟糕,因为它停止了鸭式打字:

        assert isinstance(text_value, basestring), u'All text_values should be str or unicode.'
于 2013-04-02T22:49:21.293 回答