2017-03-24 11 views
1

考慮:readlines()保證從當前位置讀取,而不是從文件的開頭讀取(在所有的Python實現中)?

with open('test.txt', 'w') as f: 
    for i in range(5): 
     f.write("Line {}\n".format(i)) 

with open('test.txt', 'r') as f: 
    f.readline() 
    for line in f.readlines(): 
     print(line.strip()) 

此輸出

Line 1 
Line 2 
Line 3 
Line 4 

即,f具有內部迭代和f.readline()消耗第一線和f.readlines()讀取所有其它線路,直到文件的末尾。 從語言的角度來看,這是預期的還是保證的?

我發現的唯一信息是從docs.python.org

如果你想閱讀列表的文件的所有行,你也可以使用list(f)f.readlines()

我覺得是模棱兩可的。

回答

1

兩個理由相信readlines()從當前位置,而不是從文件的開頭讀是「保證」:

  1. %的文檔,open返回file object其中每個詞彙意思的東西,執行io模塊中定義的合同。 io模塊文檔告訴我們.readlines()將會

    讀取並返回流的列表。

    還請注意,術語「流位置」在整個io文檔中經常使用。我想我必須承認,文檔不會100%明確地明確地說readlines()將從當前流位置開始讀取,而不是從文件開頭(或中間或隨機位置或位置取決於一週中的某一天)。然而,我認爲可以公平地說 - 鑑於它在io文檔中建立的流有位置 - 除了讀取當前流位置之外的任何解釋都是不正確的,即使我們沒有任何實際的實現看着。

  2. 這就是CPython所做的事情,CPython被廣泛理解爲Python的官方參考解釋器(正如文檔中指出的,例如https://docs.python.org/devguide/#other-interpreter-implementations)。

也許這樣的說法是不是很正式的或嚴格爲等效的說法可能是看的,比如說,C,C++,或ECMAScript的規格。如果這會讓你感到煩惱,那麼太糟糕了,因爲你不會在Python世界中找到那種形式化的程度。 Python的文檔是它的規範,但它們是也是文檔意味着用於該語言的普通開發人員,因此不像其他語言的正式標準那樣定義行爲。如有疑問,請以最自然的方式解釋文檔,並假定Python將遵循principle of least astonishment,如果不能提供足夠的確定性,請相信CPython參考解釋器。

2

當他們在文檔中提到這個技巧時,他們不會指望你先撥動迭代器。

是的,這是預期的(當你想跳過一個標題行,然後閱讀其餘的行)。

如果你想一定要閱讀所有的行只是文件倒帶調用readlines之前:

f.seek(0) 
lines = f.readlines() 

的文檔是有點稀少約readlines不倒帶文件。我做了很多谷歌搜索,這似乎暗示&自然。如果你不仍然相信,你必須要(在Python 3.6.1源bytesio.c)看看源代碼:

static PyObject * 
_io_BytesIO_readlines_impl(bytesio *self, PyObject *arg) 
/*[clinic end generated code: output=09b8e34c880808ff input=691aa1314f2c2a87]*/ 
{ 
    Py_ssize_t maxsize, size, n; 
    PyObject *result, *line; 
    char *output; 

    CHECK_CLOSED(self); 

    if (PyLong_Check(arg)) { 
     maxsize = PyLong_AsSsize_t(arg); 
     if (maxsize == -1 && PyErr_Occurred()) 
      return NULL; 
    } 
    else if (arg == Py_None) { 
     /* No size limit, by default. */ 
     maxsize = -1; 
    } 
    else { 
     PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'", 
        Py_TYPE(arg)->tp_name); 
     return NULL; 
    } 

    size = 0; 
    result = PyList_New(0); 
    if (!result) 
     return NULL; 

    output = PyBytes_AS_STRING(self->buf) + self->pos; 
    while ((n = scan_eol(self, -1)) != 0) { 
     self->pos += n; 

我停下粘貼readline的循環開始之後。在上面的行中,我們看到代碼正在使用對象的當前值self->pos。它不會在代碼的開頭重置。

-2

這就是readlines()應該做的事情。

+0

您是否有資源備份您的聲明? – pingul