【问题标题】:What's the Pythonic way to store a data block in a Python script?在 Python 脚本中存储数据块的 Pythonic 方式是什么?
【发布时间】:2011-08-04 14:04:32
【问题描述】:

Perl 允许我在脚本中使用__DATA__ 标记来标记数据块的开始。我可以使用 DATA 文件句柄读取数据。在脚本中存储数据块的 Pythonic 方式是什么?

【问题讨论】:

  • 把它放在一个单独的文件(模块)中并导入它。不要内联。
  • @agf - 我不同意。使用包含在 StringIO 中的三引号字符串内联类似文件的对象,可实现可移植且自包含的测试用例或演示脚本。
  • 字符串方法都需要在使用前在文件中定义字符串。 perl DATA 部分位于代码之后。对?请让我知道是否有解决方法。

标签: python perl filehandle


【解决方案1】:

这取决于您的数据,但 dict 文字和多行字符串都是非常好的方法。

state_abbr = {
    'MA': 'Massachusetts',
    'MI': 'Michigan',
    'MS': 'Mississippi',
    'MN': 'Minnesota',
    'MO': 'Missouri',
    }

gettysburg = """
Four score and seven years ago,
our fathers brought forth on this continent
a new nation, 
conceived in liberty
and dedicated to the proposition
that all men are created equal.
"""

【讨论】:

  • 如果它是二进制数据(即没有字节和文本),您也可以通过在字符串前面加上 b 来包含这些数据。即:b"\x00\x01\x16\x38"。例如,Qt 使用它来包含资源文件
  • @Voo:b 前缀不这样做。它在 Python 2 中被忽略,在 Python 3 中意味着创建字节文字而不是字符串(unicode)文字。二进制数据可以作为十六进制转义符包含在常规的无前缀字符串中。
  • 哦,对,是在 Python3 模式下。当然,因为 python 2 中的“字符串”不是以前缀开头的 unicode,所以没有多大意义。但是你真的允许在 python 3 字符串中包含非法的 unicode 代码点吗?这令人惊讶,特别是因为从字节(例如从套接字读取)到 unicode 的转换确实会检查它是否有意义。
  • 确实如此。 str = "\x80abc" 有效,尽管它包含非法的 utf-8 代码点,而 str = b"\x80abc".decode("utf-8") 可以预见地失败。多么奇怪的行为。似乎结果只是被忽略了(即好像您将解码的错误模式设置为“忽略”)
  • U+0080 被定义为 C1 控制字符。它的 UTF-8 编码是b'\xc2\x80'b"\x80abc" 的问题在于它是无效的 UTF-8 序列,完全不同。
【解决方案2】:

使用 StringIO 模块创建一个源内文件类对象:

from StringIO import StringIO

textdata = """\
Now is the winter of our discontent,
Made glorious summer by this sun of York.
"""

# in place of __DATA__ = open('richard3.txt')
__DATA__ = StringIO(textdata)
for d in __DATA__:
    print d

__DATA__.seek(0)
print __DATA__.readline()

打印:

Now is the winter of our discontent,

Made glorious summer by this sun of York.

Now is the winter of our discontent,

(我只是将其称为 __DATA__ 以符合您的原始问题。实际上,这不是好的 Python 命名风格 - 像 datafile 这样的名称更合适。)

【讨论】:

  • 除标准魔术方法外,切勿使用双下划线名称。
【解决方案3】:

IMO 它在很大程度上取决于数据的类型:如果您只有文本并且可以确定里面没有任何可能的 ''' 或 """,您可以使用此版本的存储文本. 但是,如果您想存储一些已知“''”或“””存在或可能存在的文本,该怎么办?然后建议

  • 要么存储以任何方式编码的数据,要么
  • 将其放在单独的文件中

例子:文字是

Python 库中有很多 ''' 和 """。

在这种情况下,可能很难通过三引号来实现。所以你可以做

__DATA__ = """There are many '''s and \"""s in Python libraries.""";
print __DATA__

但是在编辑或替换文本时您必须注意。 在这种情况下,这样做可能更有用

$ python -c 'import sys; print sys.stdin.read().encode("base64")'
There are many '''s and """s in Python libraries.<press Ctrl-D twice>

然后你得到

VGhlcmUgYXJlIG1hbnkgJycncyBhbmQgIiIicyBpbiBQeXRob24gbGlicmFyaWVzLg==

作为输出。把它放到你的脚本中,比如在

__DATA__ = 'VGhlcmUgYXJlIG1hbnkgJycncyBhbmQgIiIicyBpbiBQeXRob24gbGlicmFyaWVzLg=='.decode('base64')
print __DATA__

看看结果。

【讨论】:

    【解决方案4】:

    不熟悉 Perl 的 __DATA__ 变量 Google 告诉我它经常用于测试。假设您也在考虑测试您的代码,您可能需要考虑 doctest (http://docs.python.org/library/doctest.html)。例如,而不是

    import StringIO
    
    __DATA__ = StringIO.StringIO("""lines
    of data
    from a file
    """)
    

    假设您希望 DATA 成为您现在所拥有的文件对象,并且您可以像以后的大多数其他文件对象一样使用它。例如:

    if __name__=="__main__":
        # test myfunc with test data:
        lines = __DATA__.readlines()
        myfunc(lines)
    

    但如果 DATA 的唯一用途是用于测试,您最好创建一个 doctest 或在 PyUnit / Nose 中编写一个测试用例。

    例如:

    import StringIO
    
    def myfunc(lines):
        r"""Do something to each line
    
        Here's an example:
    
        >>> data = StringIO.StringIO("line 1\nline 2\n")
        >>> myfunc(data)
        ['1', '2']
        """
        return [line[-2] for line in lines]
    
    if __name__ == "__main__":
        import doctest
        doctest.testmod()
    

    像这样运行这些测试:

    $ python ~/doctest_example.py -v
    Trying:
        data = StringIO.StringIO("line 1\nline 2\n")
    Expecting nothing
    ok
    Trying:
        myfunc(data)
    Expecting:
        ['1', '2']
    ok
    1 items had no tests:
        __main__
    1 items passed all tests:
       2 tests in __main__.myfunc
    2 tests in 2 items.
    2 passed and 0 failed.
    Test passed.
    

    Doctest 做了很多不同的事情,包括在纯文本文件中查找 python 测试并运行它们。就个人而言,我不是一个狂热的粉丝,并且更喜欢更结构化的测试方法 (import unittest),但它无疑是一种测试代码的 Python 方法。

    【讨论】:

      猜你喜欢
      • 2011-05-04
      • 2010-09-12
      • 1970-01-01
      • 2011-09-16
      • 1970-01-01
      • 1970-01-01
      • 2021-10-22
      • 2017-05-21
      • 1970-01-01
      相关资源
      最近更新 更多