Variable de archivo Python – ¿Qué es?

Acabo de comenzar con Python, y como mi historial está en más lenguajes de bajo nivel (java, C ++), realmente no puedo obtener algunas cosas.

Entonces, en Python uno puede crear una variable de archivo, abriendo un archivo de texto, por ejemplo, y luego iterar a través de sus líneas como esta:

f = open(sys.argv[1]) for line in f: #do something 

Sin embargo, si bash f[0] el intérprete da un error. Entonces, ¿qué estructura tiene el objeto f y cómo lo sé en general, si puedo solicitar for ... in ... : bucle a un objeto?

f es un objeto de archivo . La documentación enumera su estructura, por lo que solo explicaré el comportamiento de indexación / iteración.

Un objeto es indexable solo si implementa __getitem__ , que puede verificar llamando a hasattr(f, '__getitem__') o simplemente llamando a f[0] y viendo si arroja un error. De hecho, eso es exactamente lo que su mensaje de error le dice:

 TypeError: 'file' object has no attribute '__getitem__' 

Los objetos de archivo no son indexables. Puede llamar a f.readlines() y devolver una lista de líneas, que a su vez es indexable.

Los objetos que implementan __iter__ son iterables con la syntax for ... in ... Ahora hay dos tipos de objetos iterables: objetos contenedores y objetos iteradores. Los objetos de iterador implementan dos métodos: __iter__ y __next__ . Los objetos de contenedor implementan solo __iter__ y devuelven un objeto iterador, que en realidad es sobre lo que se está iterando. Los objetos de archivo son sus propios iteradores, ya que implementan ambos métodos.

Si desea obtener el siguiente elemento en una iterable, puede utilizar la función next() :

 first_line = next(f) second_line = next(f) next_line_that_starts_with_0 = next(line for line in f if line.startswith('0')) 

Una palabra de advertencia: los iterables generalmente no son “rebobinados”, por lo que una vez que avanza a través de lo iterable, realmente no puede regresar. Para “rebobinar” un objeto de archivo, puede usar f.seek(0) , que establecerá la posición actual al principio del archivo.

1) f no es una lista. ¿Hay algún libro, tutorial o sitio web que indique que hay una lista? Si no, ¿por qué crees que puedes tratar f como una lista? Ciertamente, no puede tratar un archivo en C ++ o Java como una matriz, ¿verdad? Por qué no?

2) En python, un bucle for hace lo siguiente:

 a) The for loop calls __iter__() on the object to the right of 'in', egf__iter__(). b) The for loop repeatedly calls next() (or __next__() in python 3) on whatever f.__iter__() returns. 

Así que f.__iter__() puede devolver un objeto para que haga lo que quiera cuando se llama a next (). Da la casualidad de que Guido decidió que el objeto devuelto por un f.__iter__() debería proporcionar líneas desde el archivo cuando se llama a su método next ().

¿Cómo puedo saber en general, si puedo solicitar … en …: bucle a un objeto?

Si el objeto tiene un __iter__() , y el método __iter__() devuelve un objeto con un método next (), puede aplicarle un bucle for-in. O en otras palabras, aprendes de la experiencia qué objetos implementan el protocolo iterador .

Esto demuestra la diferencia entre un tipo de secuencia , que admite la indexación, la segmentación y la iteración limitada, y un tipo de iterador , que no admite la indexación o la segmentación, sino una iteración más avanzada, manteniendo el estado interno para hacerlo.

Un objeto de archivo es un ejemplo de este último. Puede extraer los contenidos como líneas y almacenarlos en un tipo de secuencia (específicamente, una lista) a través del método de líneas de readlines , como han señalado otros.

En Python, cada elemento de datos es un objeto de Python. Entonces, lo que sea devuelto por open() es un objeto; específicamente, es un objeto de file , que representa un identificador de archivo.

Ya sabes como hacer esto:

 handle = open("some_file.txt, "r") 

Esto es, conceptualmente, muy similar al equivalente en C:

 FILE *handle; handle = fopen("some_file.txt", "r"); 

En C, lo único útil que puedes hacer con esa variable de handle es pasarla a llamadas como fread() . En Python, el objeto tiene funciones de método asociadas a él. Entonces, aquí está C para leer 100 bytes de un archivo y luego cerrarlo:

 FILE *handle; handle = fopen("some_file.txt", "r"); result = fread(buffer, 1, 100 handle); // read 100 bytes into buffer fclose(handle); 

Y aquí es equivalente Python:

 handle = open("some_file.txt", "r"); handle.read(100) handle.close() 

Una buena forma de obtener más información sobre las funciones y los objetos de Python es usar el comando incorporado help() desde el indicador de Python. Pruebe help(open) y no le dice mucho, pero le dice que devuelve un objeto de archivo. Entonces, pruebe la help(file) y ahora obtendrá mucha información. Puede leer sobre el método .close() , .read() y otros, como .readlines() .

Pero el que te confundió fue iterar el objeto de manejar. Como un caso muy común es leer líneas de un archivo, Python hace que los manejadores de archivos funcionen como un iterador , y cuando se itera se obtiene una línea a la vez desde el archivo.

Los objetos de la lista en Python son indexables e iterables , por lo tanto, si tienes una lista con el nombre a , puedes hacer a[i] o for x in a: Buscando un artículo por posición, a[i] , está indexando. Los objetos de control de archivos no admiten la indexación, pero sí admiten la iteración.

En varias respuestas aquí verá la statement with . Esta es la mejor práctica en Python. Una statement with solo funciona con algunos tipos de objetos en Python; Los objetos tienen que soportar un par de funciones de métodos especiales. Todo lo que realmente necesita saber ahora mismo es que cuando pueda usarlo, se puede hacer un trabajo de inicialización y finalización necesario por usted. En el caso de abrir un archivo, la sentencia with se encargará de cerrar el archivo por usted. La gran parte es que la statement with garantiza que la finalización se realizará incluso si el código genera una excepción.

Aquí está Python idiomático para el ejemplo anterior:

 with open("some_file.txt") as handle: buffer = handle.read(100) 

Lo que estás buscando es readlines http://docs.python.org/2/library/stdtypes.html#file.readlines

 file_lines = f.readlines() for line in file_lines: print line print file_lines[0] # You can access an element by index 

La razón por la que puede hacer esto es porque file object es un iterable.

La variable de archivo es algo así como el manejador de archivos en C. Lo abre, lo opera (lee, escribe) y se cierra al final.

 handler.read() # read all file content at once handler.write(blob) # write there something handler.readlines() # read list with lines for line in handler: print line # iterate lines nicely 

El último ejemplo es mejor que for line in handler.readlines() , porque la primera leía las líneas cuando las necesita y la segunda consume todas las líneas a la vez (puede ser un problema con archivos grandes)

Siempre se puede usar dir (f) para ver la estructura de f, f es un objeto de archivo

  ['__class__', '__delattr__', '__doc__', '__enter__', '__exit__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'closed', 'encoding', 'errors', 'fileno', 'flush', 'isatty', 'mode', 'name', 'newlines', 'next', 'read', 'readinto', 'readline', 'readlines', 'seek', 'softspace', 'tell', 'truncate', 'write', 'writelines', 'xreadlines'] 

El intérprete da un error.

 TypeError: 'file' object has no attribute '__getitem__' 

lo que le indica que el file tipo no permite la indexación como f[0] y así sucesivamente. Si un tipo tiene el atributo, __getitem__ , permite la indexación, de lo contrario no lo tiene. En el caso de los archivos, es lo último.

Puedes saber más sobre los archivos haciendo.

 >>> fileTest = open('fileName') >>> type(fileTest)  >>> dir(fileTest) ['__class__', '__delattr__', '__doc__', '__enter__', '__exit__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'closed', 'encoding', 'errors', 'fileno', 'flush', 'isatty', 'mode', 'name', 'newlines', 'next', 'read', 'readinto', 'readline', 'readlines', 'seek', 'softspace', 'tell', 'truncate', 'write', 'writelines', 'xreadlines'] 

for lo general, los bucles se pueden aplicar a cualquier estructura que sea iterable.

Si quieres una lista de líneas, entonces puedes hacerlo.

 >>> with open('fileName') as f: lines = f.readlines() 

O haciendo,

 >>> with open('fileName') as f: lines = [line for line in f] 

Una vez que creas f, es un objeto de archivo. readlines es uno de los métodos del objeto de archivo. los

for line in f.readlines():

inicia un ciclo que permite que otro código que escriba para procesar la line del archivo a la vez. Puede usar el bucle for, porque el objeto devuelto desde readlines () es iterable.