9.8. Clases de tipos integrados¶
Python integra varias clases de tipos en el modulo __builtin__
, a continuación se
describen algunas clases:
9.8.1. Clases generales¶
Las clases de uso general se describen a continuación:
9.8.1.1. buffer¶
El objeto de la clase buffer()
crea un nuevo objeto de búfer que haga referencia
al objeto dado. El búfer hará referencia a una porción del objeto de destino desde el
inicio del objeto (o en el desplazamiento especificado). La división se extenderá hasta
el final del objeto de destino (o con el tamaño especificado).
>>> cadena = "Hola mundo"
>>> cadena
'Hola mundo'
>>> cadena[5:10]
'mundo'
>>> type(cadena)
<type 'str'>
>>> cadena_buffer = buffer(cadena, 5, 5)
>>> type(cadena_buffer)
<type 'buffer'>
>>> cadena_buffer
<read-only buffer for 0x7f42121d3810, size 5, offset 5 at 0x7f42121d23b0>
>>> print(cadena_buffer)
mundo
El búfer en este caso anterior es una sub-cadena, inicia en la posición 5 con un
ancho de 5 caracteres y es no toma espacio de almacenamiento extra - eso referencia
a cortar
una cadena de caracteres.
Este ejemplo anterior no es muy útil para cadena de caracteres cortas como esta,
pero eso puede ser necesario cuando usa un gran numero de data. Este ejemplo puede
usar un tipo mutable bytearray()
:
>>> cadena = bytearray(1000000)
>>> type(cadena)
<type 'bytearray'>
>>> cadena_buffer = buffer(cadena, 1)
>>> cadena_buffer
<read-only buffer for 0x7f42121d3870, size -1, offset 1 at 0x7f42121d2270>
>>> type(cadena_buffer)
<type 'buffer'>
>>> cadena_buffer[0]
'\x00'
>>> cadena[1]
0
>>> cadena[1] = 5
>>> cadena[1]
5
>>> cadena_buffer[0]
'\x05'
Esto puede ser muy útil si usted quiere tener más que una vista en la data y no quiere (o puede) contener múltiples copias en memoria.
Note que el búfer ha sido remplazado por un mejor método llamado memoryview() en Python 3, aunque se puede usar en Python 2.7.
Note también que usted no puede implementar una interfaz búfer para sus propios objetos sin profundizando en la API de C, ej. usted no puede hacer eso con puramente con código Python.
En general un slice
tomará extra almacenamiento, entonces, si cadena[5:10]
será
una copia. Si usted define cadena_buffer = cadena[5:10]
y entonces del cadena
,
eso liberaría la memoria que fue tomada por cadena
, proveyendo que cadena_buffer
fue copiada. (Para usar esto usted necesita una gran cadena de caracteres, en este ejemplo
cadena
y rastrear el uso de la memoria de Python). Es sin embargo mucho más eficiente
que hacer la copia si no existe mucha data involucrada.
9.8.1.2. bytes¶
El objeto de la clase bytes
es agregada en Python 2.6 como un sinónimo para el tipo
str y este también soporta la notación b''
.
El uso principal de bytes en Python 2.6 será escribir pruebas de tipo de objeto como
isinstance(x, bytes)
. Esto ayudará al convertidor 2to3
, que no puede decir si
el código 2.x pretende que las cadenas contengan caracteres o bytes de 8 bits; ahora
puede usar bytes
o str
para representar exactamente su intención, y el código
resultante también será correcto en Python 3.0.
>>> arreglo = bytes("Python es interesante.")
>>> print(arreglo)
Python es interesante.
>>> type(arreglo)
<type 'str'>
9.8.1.3. quit¶
Es el método constructor de la clase Quitter
incluida en el módulo site
el
cual le permite salir de la consola interactiva Python:
>>> quit
Use quit() or Ctrl-D (i.e. EOF) to exit
>>> quit()
$
De esta forma puede salir de la consola interactiva Python y volviendo al interprete del Shell de comando.
9.8.1.4. slice¶
La clase slice
crea un objecto slice
, esto es usado por el extendido slicing
por ejemplo:
>>> a = range(20)
>>> a[0:10:2]
[0, 2, 4, 6, 8]
La sintaxis es la siguiente:
>>> slice(stop)
>>> slice(start, stop[, step])
9.8.1.5. staticmethod¶
Los métodos estáticos en Python son extremadamente similar a los métodos de nivel clase en python, la diferencia esta que un método estático es enlazado a una clase más bien que los objectos para esa clase.
Esto significa que un método estático puede ser llamado sin un objeto para esa clase. Esto también significa que los métodos estáticos no pueden modificar el estado de un objeto como ellos no pueden enlazarse a ese.
Los métodos estáticos Python puede crearse en dos formas, usando el aprovechamiento
staticmethod()
o el decorador @staticmethod
:
La clase staticmethod()
convierte una función a un método estático. Un método
estático no recibe un primer argumento implícito. La sintaxis es la siguiente:
>>> staticmethod(function) -> método
Para declarar un método estático, a continuación vea el siguiente ejemplo:
>>> class Calculador:
... def sumaNumeros(x, y):
... return x + y
... # crea un static method sumaNumeros
... sumaNumeros = staticmethod(sumaNumeros)
...
>>> print("Resultado:", Calculador.sumaNumeros(15, 110))
Resultado: 125
>>> print("Resultado:", Calculador().sumaNumeros(15, 110))
Resultado: 125
En el ejemplo anterior usted puede notar que se llamo al método sumaNumeros
sin
crear un objeto. Se puede llamar en la clase (por ejemplo, Clase.funcion()
) o
en una instancia (por ejemplo, Clase().funcion()
). La instancia se ignora a
excepción de su clase.
Los métodos estáticos son similares a los métodos estáticos Java
o C++
. Para
un concepto más avanzado, mire la clase classmethod
integrada en el interprete.
La clase staticmethod
introduce un cambio en la versión 2.4, agregando sintaxis de
decorador de función. La sintaxis es la siguiente:
class Clase:
@staticmethod
def funcion(argumento1, argumento2, ...):
...
Un ejemplo del uso de decoradores para staticmethod
a continuación:
>>> class Calculador:
... @staticmethod
... def sumaNumeros(x, y):
... return x + y
...
>>> print("Resultado:", Calculador.sumaNumeros(15, 110))
Resultado: 125
Este código fuente es enteramente idéntico al primer ejemplo (usando @staticmethod
),
solo que no usa la agradable sintaxis de decorador.
Finalmente, se usa el método staticmethod()
escasamente. Hay muchas situaciones donde los
métodos estáticos son necesarios en Python.
9.8.2. Clases de secuencias¶
Las clases de tipos secuencias se describen a continuación:
9.8.2.1. enumerate¶
La clase enumerate
devuelve un objeto enumerate. El iterable debe ser otro objeto
que soporte iteradores. El objeto enumerate produce pares que
contiene una cuenta (desde donde inicia, el cual el valor por defecto es cero) y un valor
producido por el argumento iterable.
Cuando la iteración de la secuencia llega al final se llama a la excepción
StopIteration y se causa el detener la iteración.
El objeto enumerate es muy útil para obtener una lista indexada como:
(0, seq[0]), (1, seq[1]), (2, seq[2]), ...
.
>>> enumerar = enumerate(range(3))
>>> next(enumerar)
(0, 0)
>>> next(enumerar)
(1, 1)
>>> next(enumerar)
(2, 2)
>>> next(enumerar)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
En el ejemplo anterior usa una secuencia numérica de 3 elementos generada por la función integrada range().
A continuación se le pasa el parámetro de inicio con el valor 1 de la secuencia
generada por la clase enumerate
:
>>> enumerar = enumerate(range(3), 1)
>>> next(enumerar)
(1, 0)
>>> next(enumerar)
(2, 1)
>>> next(enumerar)
(3, 2)
>>> next(enumerar)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
En el ejemplo anterior usa una secuencia numérica de 3 elementos generada con el valor inicial de 1 por la función integrada range().
9.8.2.2. reversed¶
La clase reversed
devolver un iterador inverso sobre los
valores de la secuencia, cuando la iteración de la secuencia llega al final se llama
a la excepción StopIteration y se causa el
detener la iteración.
>>> inversa = reversed(range(3))
>>> next(inversa)
2
>>> next(inversa)
1
>>> next(inversa)
0
>>> next(inversa)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
En el ejemplo anterior usa una secuencia numérica de 3 elementos generada por la función integrada range().
9.8.3. Clases de archivos¶
Las clases de tipos archivos se describen a continuación:
9.8.3.1. file()¶
El objeto file()
se implementan con el paquete del lenguaje C stdio
y se pueden
crear con la función interna open(). También son el resultado
de otras funciones y métodos internos, por ejemplo, os.popen()
y os.fdopen()
y
el método makefile()
de los objetos socket
.
Cuando falla una operación de archivos por una cuestión de E/S, se lanza la excepción
IOError. Esto incluye situaciones donde la operación
no esté definida por cualquier motivo, como usar seek()
en un dispositivo tty
o intentar escribir en un archivo abierto para lectura.
9.8.3.1.1. Métodos¶
El objeto file()
implementa los siguientes métodos integrados:
9.8.3.1.1.1. close()¶
El método close()
permite cerrar la manipulación del archivo. No es posible escribir
ni leer en un archivo cerrado. Cualquier operación que requiera que el archivo esté
abierto lanzará IOError si el archivo se ha cerrado.
Está permitido llamar a close()
más de una vez.
Una vez que se terminó de usar el archivo es necesario cerrarlo, para liberar los
recursos tomados por el manejo del archivo. Eso se hace con la sentencia archivo.close()
:
>>> archivo.close() # cierra el archivo datos.txt
Luego de lo cual no se puede acceder al archivo datos.txt
, si intenta una llamada a
la método archivo.read() devuelve una excepción
ValueError, porque el archivo está cerrado:
>>> archivo.close()
>>> archivo.read()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file
Truco
Para más detalles: https://docs.python.org/es/3.7/tutorial/inputoutput.html
9.8.3.1.1.2. flush()¶
El método flush()
permite descargar el bufér interno, como la función de lenguaje C
fflush()
de la librería stdio
. Puede no tener efecto en ciertos objetos similares
a los archivos.
Python automáticamente flushes los archivos cuando son cerrados. Pero usted podría to flush la data antes de cerrar cualquier archivo.
>>> archivo = open("datos.txt", "wb") # Abre un archivo
>>> print("Nombre del archivo: ", archivo.name)
Nombre del archivo: datos.txt
>>> archivo.flush()
... # Aquí eso no hace nada, pero usted puede
... # llamarlo con la operación read.
>>> archivo.close() # Cerrar archivo abierto
9.8.3.1.1.3. isatty()¶
El método isatty()
devuelve True
si el archivo está conectado a un dispositivo
tty
(un terminal interactivo de líneas de orden), en caso contrario, False
.
Nota
Si un objeto similar a los archivos no está asociado a un archivo real, no debe implementar este método.
>>> archivo = open("datos.txt", "r")
>>> archivo.isatty()
False
9.8.3.1.1.4. fileno()¶
El método fileno()
devuelve el «descriptor de archivo» utilizado por la
implementación subyacente para solicitar operaciones E/S del sistema operativo.
Puede ser útil para interfaces de bajo nivel que utilicen descriptores de archivos,
por ejemplo, el módulo fcntl
o os.read()
y similares.
Nota
Si un objeto similar a los archivos no tiene un descriptor de archivo, no debe implementar este método.
>>> archivo = open("datos.txt", mode="r")
>>> archivo.fileno()
6
9.8.3.1.1.5. next()¶
El método next()
permite usar un iterador para tratar cada linea del archivo como
el próximo valor, cuando la iteración del archivo llega al final se llama a la excepción
StopIteration y se causa el detener la
iteración.
>>> archivo = open("/etc/hostname")
>>> archivo
<open file '/etc/hostname', mode 'r' at 0x7fa44ba379c0>
>>> archivo.__iter__()
<open file '/etc/hostname', mode 'r' at 0x7fa44ba379c0>
>>> iter(archivo)
<open file '/etc/hostname', mode 'r' at 0x7fa44ba379c0>
>>> archivo is archivo.__iter__()
True
>>> linea = archivo.__iter__()
>>> next(linea)
'laptop\n'
>>> next(linea)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
9.8.3.1.1.6. read()¶
El método read()
permite leer el contenido del archivo. El argumento es opcional
y si no se especifica (o es -1) devuelve el contenido de todo el archivo. Una vez que
se leyó todo el archivo, una nueva llamada a la función devuelve una cadena vacía (“”).
>>> archivo = open("datos.txt", "r")
>>> archivo.read()
'Este es una prueba \ny otra prueba'
>>> archivo.read()
''
Si desea recibir una salida formateada por consola leyendo un archivo, a continuación un ejemplo:
>>> archivo = open("datos.txt", "r")
>>> contenido = archivo.read()
>>> print(contenido)
Este es una prueba
y otra prueba
9.8.3.1.1.7. readline()¶
El método readline()
permite leer una sola línea del archivo, devuelve al final de
la línea el carácter de nueva línea y solo se omite en la última línea del archivo (si
no termina con el carácter de nueva línea). Esto hace que el valor de retorno no sea
ambiguo. Si devuelve una cadena de caracteres vacía se alcanzó el fin del archivo,
mientras que una línea en blanco se representa con un carácter de nueva línea.
>>> archivo = open("datos.txt", "r")
>>> print(archivo.readline()) # lee la linea "Este es una prueba "
>>> print(archivo.readline()) # lee la linea "y otra prueba"
>>> print(archivo.readline())
>>>
9.8.3.1.1.8. readlines()¶
El método readlines()
devuelve una lista que contiene todas las líneas del archivo.
>>> archivo = open("datos.txt", "r")
>>> lineas = archivo.readlines()
>>> print(lineas)
['Este es una prueba \n', 'y otra prueba']
9.8.3.1.1.9. seek()¶
El método seek()
mueve la posición actual del cursos del archivo, como la función
del lenguaje C fseek()
de la librería stdio
. No devuelve ningún valor.
El método seek()
lleva la siguiente nomenclatura:
>>> seek(posicion_actual[, punto_referencia])
A continuación, un ejemplo que escribir y leer el archivo datos.txt
agregando una
lista de lineas al principio del archivo, como al final del archivo:
>>> archivo = open("datos.txt", "w")
>>> lista_de_lineas = [
... "Esta es la 1er linea",
... "Esta es la 2da linea",
... "Esta es la 3era linea",
... ]
>>> archivo.writelines("\n".join(lista_de_lineas))
>>> archivo.close()
>>> archivo = open("datos.txt", "r")
>>> next(archivo)
'Esta es la 1er linea\n'
>>> archivo.seek(8)
>>> next(archivo)
'la 1er linea\n'
>>> next(archivo)
'Esta es la 2da linea\n'
>>> next(archivo)
'Esta es la 3era linea'
>>> next(archivo)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> archivo.close()
En el ejemplo anterior, puede ver que se escriben tres lineas y se pasa como argumento
posicion_actual
el valor 8 el cual posiciona el curso de búsqueda en dicha posición
de la primera linea con archivo.seek(8)
y muestra una parte de la linea.
El argumento punto_referencia
es opcional, con un valor predeterminado de 0
(es
el principio del archivo); otros valores posibles son 1
(la posición actual del
archivo) y 2
(el final del archivo). No hay valor de retorno.
>>> archivo = open("datos.txt", "w")
>>> lista_de_lineas = [
... "Esta es la 1er linea",
... "Esta es la 2da linea",
... "Esta es la 3era linea",
... ]
>>> archivo.writelines("\n".join(lista_de_lineas))
>>> archivo.close()
>>> archivo = open("datos.txt", "r")
>>> next(archivo)
'Esta es la 1er linea\n'
>>> archivo.seek(8)
>>> next(archivo)
'la 1er linea\n'
>>> archivo.close()
>>> archivo = open("datos.txt", "rw+")
>>> nuevas_lineas = ["\nEsta es la 4ta linea", "Esta es la 5ta linea"]
>>> # Escribe la secuencia de la lineas al final del archivo.
... archivo.seek(0, 2)
>>> archivo.writelines("\n".join(nuevas_lineas))
>>> # Ahora lea completamente el archivo desde el inicio.
... archivo.seek(0, 0)
>>> for elemento in range(1, 6):
... linea = next(archivo)
... print("Linea No %d - %s" % (elemento, linea))
...
Linea No 1 - Esta es la 1er linea
Linea No 2 - Esta es la 2da linea
Linea No 3 - Esta es la 3era linea
Linea No 4 - Esta es la 4ta linea
Linea No 5 - Esta es la 5ta linea
>>> # Cerrar archivo abierto
... archivo.close()
>>>
En el ejemplo anterior se pudo usar el método seek()
con el argumento
punto_referencia
al final del archivo para agregar nuevas lineas y luego se uso
de nuevo el argumento punto_referencia
para ubicarse al inicio del archivo para
mostrar todo el contenido del archivo.
9.8.3.1.1.10. tell()¶
El método tell()
devuelve la posición actual del archivo, como la función del
lenguaje C ftell()
de la librería stdio
.
>>> archivo = open("/etc/hostname")
>>> archivo.tell()
0
>>> linea = iter(archivo)
>>> next(linea)
'debacagua9\n'
>>> archivo.tell()
11
>>> len("debacagua9\n")
11
>>> next(linea)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> archivo.tell()
11
Cuando la iteración de la secuencia llega al final se llama a la excepción StopIteration y se causa el detener la iteración.
9.8.3.1.1.11. truncate()¶
>>> archivo = open("datos.txt", "w")
>>> archivo.write("Este es una prueba \ny otra prueba")
>>> archivo.truncate(20)
>>> archivo.close()
>>> archivo = open("datos.txt", "r")
>>> archivo.read()
'Este es una prueba \n'
El método truncate()
trunca el archivo. Si se proporciona el argumento opcional,
el archivo se trunca a (como mucho) ese tamaño. El tamaño depende de la posición
actual. La disponibilidad de esta función depende de la versión del sistema operativo
(por ejemplo, no todas las versiones de Unix dan soporte a esta operación).
9.8.3.1.1.12. write()¶
El método write()
permite escribir el contenido de la cadena de texto al archivo,
y devuelve la cantidad de caracteres escritos.
Para escribir algo que no sea una cadena de caracteres, antes se debe convertir a cadena de caracteres.
>>> archivo = open("datos.txt", "w")
>>> # escribe el archivo datos.txt
... archivo.write("Este es una prueba \ny otra prueba")
>>>
9.8.3.1.1.13. writelines()¶
El método writelines()
escribe una lista de cadenas al archivo. No se devuelve
ningún valor. El nombre es paralelo a readlines()
, writelines()
no añade
separadores de línea.
>>> archivo = open("datos.txt", "w")
>>> lista_de_lineas = [
... "Plone es el más poderoso, ",
... "escalable, seguro ",
... "y longevo CMS, ",
... "escrito en Python.",
... ]
>>> archivo.writelines("\n".join(lista_de_lineas))
>>> archivo.close()
9.8.3.1.2. Atributos¶
Los objetos archivo también ofrecen otros atributos interesantes. No son necesarios para los objetos de interfaz tipo archivo, pero deberían implementarse si tienen sentido en un objeto particular.
9.8.3.1.2.1. closed¶
El atributo closed
del objeto file de tipo
booleano indica el estado actual. Es un atributo de sólo lectura,
que se cambia mediante el método close(). Puede no estar
disponible en todos los objetos con interfaz tipo archivo.
>>> archivo = open("datos.txt", "w")
>>> archivo.closed
False
>>> archivo.close()
>>> archivo.closed
True
9.8.3.1.2.2. mode¶
El atributo mode
del objeto file, es el modo de E/S del
archivo. Si se creó el archivo con la función integrada open(),
será el valor del parámetro mode
. Es un atributo de sólo lectura y puede no estar
disponible en todos los objetos con interfaz tipo archivo.
>>> archivo = open("datos.txt", "w")
>>> archivo.mode
'w'
9.8.3.1.2.3. name¶
El atributo name
del objeto file, es el nombre del archivo
si se creó el objeto archivo mediante la función integrada open(),
el nombre del archivo. En caso contrario, alguna cadena que indique el origen del archivo,
de la forma «<…>». Es un atributo de sólo lectura y puede no estar disponible en todos
los objetos con interfaz tipo archivo.
>>> archivo = open("datos.txt", "w")
>>> archivo.name
'datos.txt'
9.8.3.1.2.4. encoding¶
El atributo encoding
del objeto file, es el encoding
del archivo.
>>> with open("datos.txt", mode="r") as archivo:
... print("Encoding por defecto:", archivo.encoding)
... archivo.close()
...
Encoding por defecto: None
9.8.3.1.2.5. softspace¶
El atributo softspace
del objeto file del tipo
booleano indica si se debe escribir un espacio antes de escribir
otro valor al usar la sentencia print. Las clases que intenten
simular un objeto archivo deberían tener un atributo escribible softspace
, que
debería inicializarse a cero.
Esto será automático en la mayoría de las clases implementadas en Python (se debe
tener cuidado en las clases que redefinan el acceso a los atributos). Los tipos
implementados en el lenguaje C tendrán que proporcionar un atributo softspace
escribible.
Nota: Este atributo no se usa para controlar la sentencia print
, sino para permitir
que la implementación de print
lleve la cuenta de su estado interno.
>>>
>>> archivo = open("datos.txt", "w")
>>> archivo.softspace
0
9.8.4. Clases de objetos¶
Las clases de objetos se describen a continuación:
9.8.4.1. classmethod¶
La clase classmethod
convierte una función para ser un método de clase. Un método
de clase recibe la clase como primer argumento implícito, al igual que un método de
instancia recibe la instancia. La sintaxis es la siguiente:
classmethod(function) -> método
Para declarar un método de clase, a continuación vea el siguiente ejemplo:
>>> def sumaNumeros(cls, x, y):
... return x + y
...
>>> type(sumaNumeros)
<type 'function'>
>>> class Calculador:
... # crea un static method sumaNumeros
... sumaNumeros = classmethod(sumaNumeros)
...
>>> Calculador.sumaNumeros(15, 110)
125
>>> Calculador().sumaNumeros(15, 110)
125
>>> type(Calculador.sumaNumeros)
<type 'instancemethod'>
La clase classmethod
introduce un cambio en la versión 2.4, agregando sintaxis de
decorador de función. La sintaxis es la siguiente:
class Clase:
@classmethod
def funcion(cls, argumento1, argumento2, ...):
...
Un ejemplo del uso de decoradores para classmethod
a continuación:
>>> class Clase:
... @classmethod
... def funcion(cls, argumento1, argumento2):
... return argumento1 + argumento2
...
>>> Clase.funcion(2, 3)
5
>>> Clase().funcion(2, 3)
5
Se puede llamar en la clase (por ejemplo, Clase.funcion()
) o en una instancia
(por ejemplo, Clase().funcion()
). La instancia se ignora a excepción de su clase.
Si se llama a un método de clase para una clase derivada, el objeto de clase derivada
se pasa como el primer argumento implícito.
Los métodos de clase son diferentes a los métodos estáticos C++
o Java
. Si
quieres eso, mira la clase staticmethod integrada
en el interprete.
9.8.4.2. memoryview¶
La clase memoryview
devuelve un objeto vista de memoria del argumento dado.
Antes de introducir a que son las vistas de memoria, necesita entender primero sobre del protocolo Búfer de Python.
¿Qué es protocolo Búfer?
Este protocolo provee una forma de acceder la data interna de un objeto. Esta data interna es un arreglo de memoria o un búfer. El protocolo Búfer le permite un objeto para exponer esa data interna (búfers) y el otro para acceder a esos búfers sin tener que copiar intermediamente.
Este protocolo es solamente accesible al usar el nivel API de C y no usando el normal código base. Por lo tanto, para exponer el mismo protocolo a la base de código Python normal, las vistas de memoria están presentes.
¿Qué es una vista de memoria?
La vista de memoria es una forma segura de exponer el protocolo búfer en Python. Eso le permite a usted acceder a los búfers internos de un objeto para creación de un objeto de vista de memoria.
¿Por que el protocolo búfer y las vistas de memoria son importantes?
Necesita recordar que cada vez que ejecuta alguna acción en un objeto (llamar a una función de un objeto, cortar un arreglo), Python necesita crear una copia del objeto.
Si usted tiene una gran data para trabajar con ella (ej. data binaria de una imagen), debería crear innecesariamente copias de enormes trozos de datos, que casi no sirve de nada.
Usando el protocolo búfer, puede dar otros accesos al objeto para usar/modificar data grande sin realizar copias de eso. Esto hace que el programa use menos memoria y incremente la velocidad de ejecución.
¿Como exponer el protocolo búfer usando las vistas de memoria?
Los objetos de vista de memoria son creados usando la sintaxis:
>>> memoryview(objecto)
El método constructor memoryview()
toma un simple parámetro:
objecto
- es el objeto dado como parámetro el cual su data interna es expuesta.
objecto
debe ser un tipo el cual soportar el protocolo búfer (bytes
,
bytearray
). Devuelve el valor de un objeto de vista de memoria del objeto dado
como parámetro desde el método memoryview()
.
A continuación, un ejemplo donde se crea una vista de memoria usando el tipo
bytearray
previamente creado:
>>> cadena = bytearray(1000000)
>>> memoryview(cadena)
<memory at 0x7f6202179cc8>
>>> memoryview(cadena).format
'B'
>>> memoryview(cadena).itemsize
1L
>>> memoryview(cadena).ndim
1L
>>> memoryview(cadena).readonly
False
>>> memoryview(cadena).shape
(1000000L,)
>>> memoryview(cadena).strides
(1L,)
>>> memoryview(cadena).suboffsets
En el ejemplo anterior se crea una vista de memoria de un tipo bytearray
mostrando los diversos atributos disponibles.
Continuando el ejemplo anterior, se crea una vista de memoria de un tipo
buffer usando el objeto cadena
previamente creado:
>>> cadena_buffer = buffer(cadena, 1)
>>> memoryview(cadena_buffer)
<memory at 0x7f6202179cc8>
>>> memoryview(cadena_buffer).format
'B'
>>> memoryview(cadena_buffer).itemsize
1L
>>> memoryview(cadena_buffer).ndim
1L
>>> memoryview(cadena_buffer).readonly
True
>>> memoryview(cadena_buffer).shape
(999999L,)
>>> memoryview(cadena_buffer).strides
(1L,)
>>> memoryview(cadena_buffer).suboffsets
En el ejemplo anterior se crea una vista de memoria de un tipo buffer mostrando los diversos atributos disponibles.
A continuación, otro ejemplo donde se crea una vista de memoria usando el objeto
bytearray
previamente creado:
>>> randomBA = bytearray("ABC", "utf-8")
>>> randomBA
bytearray(b'ABC')
>>> vm = memoryview(randomBA)
>>> vm
<memory at 0x7fafc7136c30>
>>> print(vm[0])
A
>>> print(vm[1])
B
>>> print(vm[2])
C
Continuando el ejemplo anterior, se puede crear una lista desde
una vista de memoria usando el objeto vm
previamente creado:
>>> list = []
>>> for item in range(3):
... list.append(vm[item])
...
>>> list
['A', 'B', 'C']
Continuando el ejemplo anterior, se puede crear cadena de caracteres
desde una vista de memoria usando el objeto vm
previamente creado:
>>> cad = ""
>>> for item in range(3):
... cad += vm[item]
...
>>> print(cad)
ABC
Aquí, es creada un objeto vista de memoria llamado vm
desde un objeto bytearray
llamado randomBA
.
Entonces, es accedido al índice 0 posición vm
“A” y el valor es impreso. Luego, es
accedido al índice 1 posición vm
“B” y el valor es impreso. También, es accedido al
índice 2 posición vm
“C” y el valor es impreso.
Finalmente, es accedido todos los índices del objeto vm
y convertidos a una lista.
A continuación, otro ejemplo donde se modifica la data interna usando vista de memoria:
>>> randomBA = bytearray("ABC", "utf-8")
>>> print("Antes de actualizar:", randomBA)
Antes de actualizar: ABC
>>> vm = memoryview(randomBA)
>>> chr(90)
'Z'
>>> vm[1] = chr(90)
>>> print("Después de actualizar:", randomBA)
Después de actualizar: AZC
Aquí, se actualiza el indice 1 de la vista de memoria a un valor ASCII - 90 (Z)
usando la función chr(). Desde, el objeto de vista de memoria
vm
referencia al mismo búfer/memoria, actualiza el índice en el vm
también actualiza
el randomBA
.
Desde adentro internamente el tipo bytearray
almacena valores ASCII
para el
alfabeto, es decir, cada posición de la lista se debe indicar con su equivalente
numérico en la tabla ASCII
.
>>> chr(65)
'A'
>>> chr(66)
'B'
>>> chr(67)
'C'
>>> chr(90)
'Z'
Entonces se usa la función chr() para indicar su equivalente en
la tabla de valores ASCII
.
9.8.4.3. object¶
El objeto de la clase object
es el tipo más básico de objeto, es integrado en
el módulo __builtin__
. Este objeto se usa como herencia
cuando se crea una nueva clase en Python.
Todo, incluyendo las clases y tipos de Python son instancias de object
. Para
corroborar si un objeto es instancia de una clase se utiliza la función
isinstance().
>>> object
<type 'object'>
9.8.4.4. property¶
La clase property
típicamente es usado para definir un atributo property.
La sintaxis es la siguiente:
>>> property(fget=None, fset=None, fdel=None, doc=None) # devuelve atributo property
El parámetro fget
es una función a ser usada para obtener un valor de un atributo,
y igualmente el parámetro fset
es una función para definir el valor de un atributo,
y el parámetro fdel
es una función para eliminar un atributo.
El método property()
devuelve un atributo property
donde es dado el método
getter
, setter
y deleter
.
Si no hay argumentos son dados, el método property()
devuelven un atributo base
property
que no contienen ningún getter
, setter
o deleter
. Si doc
no es proveído, método property()
toma el docstring
de la función getter
.
A continuación, un ejemplo sencillo:
>>> class Persona:
... def __init__(self, nombre):
... self._nombre = nombre
... def getNombre(self):
... print("Obteniendo nombre")
... return self._nombre
... def setNombre(self, valor):
... print("Definiendo nombre a " + valor)
... self._nombre = valor
... def delNombre(self):
... print("Eliminando nombre")
... del self._nombre
... # Define la property para usar los métodos getNombre,
... # setNombre y delNombre
... nombre = property(getNombre, setNombre, delNombre, "Atributo property nombre")
...
>>> persona1 = Persona("Leo")
>>> print(persona1.nombre)
Obteniendo nombre
Leo
>>> persona1.nombre = "Leonardo"
>>> print(persona1.nombre)
Leonardo
>>> dir(persona1)
['__doc__', '__init__', '__module__', '_nombre', 'delNombre',
'getNombre', 'nombre', 'setNombre']
>>> persona1.delNombre()
Eliminando nombre
>>> dir(persona1)
['__doc__', '__init__', '__module__', 'delNombre', 'getNombre',
'nombre', 'setNombre']
>>> print(persona1.nombre)
Leonardo
>>> del persona1.nombre
>>> print(persona1.nombre)
Obteniendo nombre
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in getNombre
AttributeError: Persona instance has no attribute '_nombre'
Cuando se elimina persona1.delNombre()
puede notar que _nombre
ya no esta
disponible y si se vuelve a imprimir el valor de nombre print(persona1.nombre)
aun muestra el valor inicializado con el método setNombre
, entonces al ejecutar
del persona1.nombre
se elimina por completo el valor en memoria, luego si intenta
mostrar el valor del atributo property nombre
lanza
AttributeError por no encontró _nombre
el cual es usado como la variable privado para almacenar el nombre de una Persona.
Se definió lo siguiente:
Un método
getter
getNombre() para obtener el nombre de la persona,Un método
setter
setNombre() para definir el nombre de la persona,Un método
deleter
delNombre() para eliminar el nombre de la persona.
Ahora tiene definido un atributo property nombre
llamando al método property()
.
Como se mostró en el código anterior, la referencia persona1.nombre
internamente
llama al método getName()
como getter, setName()
como setter y delName()
como deleter a través de las salidas impresas presente dentro de los métodos.
También se definió el docstring del atributo con el valor “Atributo property nombre”.
Otra alternativa son los decoradores facilitan la definición de nuevas propiedades o la modificación de las existentes:
A continuación se creará un atributo property con métodos getter
, setter
y
deleter
usando el decorador @property
en vez de usar el método property()
,
usted puede usar el decorador Python @property
para asignar el método getter
,
setter
y deleter
:
>>> class Persona:
... def __init__(self, nombre):
... self._nombre = nombre
... @property
... def nombre(self):
... print("Obteniendo nombre")
... return self._nombre
... @nombre.setter
... def nombre(self, valor):
... print("Definiendo nombre a " + valor)
... self._nombre = valor
... @nombre.deleter
... def nombre(self):
... print("Eliminando nombre")
... del self._nombre
...
>>> persona1 = Persona("Leo")
>>> print("El nombre es:", persona1.nombre)
El nombre es: Obteniendo nombre
Leo
>>> persona1.nombre = "Leonardo"
>>> print(persona1.nombre)
Leonardo
>>> dir(persona1)
['__doc__', '__init__', '__module__', '_nombre', 'nombre']
>>> del persona1.nombre
>>> dir(persona1)
['__doc__', '__init__', '__module__', '_nombre', 'nombre']
>>> print(persona1.nombre)
Obteniendo nombre
Leo
Aquí, en vez de usar el método property()
, es usado el
decorador @property.
Primero especifica que el método nombre()
es un atributo de la clase Persona
.
Esto es hecho usando la sintaxis @property
antes el método getter como se
muestra en el código anterior.
Seguidamente se usa el nombre del atributo nombre
para especificar los métodos
setter y deleter.
Esto es hecho usando la sintaxis @<nombre-de-atributo>.setter (@nombre.setter
) para
el método setter y @<nombre-de-atributo>.deleter (@nombre.deleter
) para el método
deleter.
Note, es usando el mismo método nombre()
con diferentes definiciones para definir
los métodos getter
, setter
y deleter
.
Ahora, cada vez que se usa persona1.nombre
, es internamente llama el apropiado método
para getter
, setter
y deleter
como lo muestra la salida impresa presente
dentro de cada método.
9.8.4.5. super¶
La clase super
típicamente es usada al llamar un método de superclase cooperativo.
Las sintaxis de como usarlo son las siguientes:
>>> super(type, obj)
El código anterior devuelve un súper objeto enlazado; requiere isinstance(obj, type)
.
>>> super(type)
El código anterior devuelve un súper objeto no unido.
>>> super(type, type2)
El código anterior devuelve un súper objeto enlazado; requiere issubclass(type2, type)
.
Para declarar un método de superclase cooperativo, use esta sintaxis:
class ClaseBase():
def metodo(self, argumento):
pass
class Clase(ClaseBase):
def metodo(self, argumento):
super(Clase, self).metodo(argumento)
Un ejemplo sencillo real se muestra a continuación:
>>> class Mamifero(object):
... def __init__(self, mamifero):
... print(mamifero, "es un animal de sangre caliente.")
...
>>> class Perro(Mamifero):
... def __init__(self):
... print("Perro tiene 4 piernas.")
... super(Perro, self).__init__("Perro")
...
>>> perrito = Perro()
Perro tiene 4 piernas.
Perro es un animal de sangre caliente.
>>> isinstance(perrito, Perro)
True
Aquí, se llama el método __init__
de la clase Mamifero
(desde la clase
Perro
) usando el código fuente super(Perro, self).__init__('Perro')
en
vez de del tradicional Mamifero.__init__(self, 'Perro')
.
Como no necesitamos especificar el nombre de la clase base si usamos super()
,
podemos cambiar fácilmente la clase base para el método Perro
(si es necesario).
A continuación un ejemplo de cambiar la clase base a la clase RazaCanina:
>>> class Mamifero(object):
... def __init__(self, mamifero):
... print(mamifero, "es un animal de sangre caliente.")
...
>>> class RazaCanina(Mamifero):
... def __init__(self, nombre, raza):
... print(raza, "es la raza del canino.")
... super(RazaCanina, self).__init__("Perro")
...
>>> class Perro(RazaCanina):
... def __init__(self, raza):
... print("Perro tiene 4 piernas.")
... super(Perro, self).__init__("Perro", raza)
...
>>> perrito = Perro("Pastor Alemán")
Perro tiene 4 piernas.
Pastor Alemán es la raza del canino.
Perro es un animal de sangre caliente.
El método integrado super()
regresa un objeto proxy, un objeto substituto que
tiene la habilidad de llamar al método de la clase base vía delegación. Esto es
llamado indirección (habilidad de referenciar objeto base con el método super()
).
Desde que la indirección es calculada en tiempo ejecución, usted puede usar para apuntar hacia una clase base diferente en tiempo diferente (si usted lo necesita).
A continuación un ejemplo del uso super()
con
herencia múltiple de la objetos:
>>> class Animal(object):
... def __init__(self, animal):
... print(
... animal,
... "es un animal.\n\n",
... )
...
>>> class Mamifero(Animal):
... def __init__(self, mamifero):
... print(mamifero, "es un animal de sangre caliente.")
... super(Mamifero, self).__init__(mamifero)
...
>>> class MamiferoNoVolador(Mamifero):
... def __init__(self, mamifero):
... print(mamifero, "no puede volar.")
... super(MamiferoNoVolador, self).__init__(mamifero)
...
>>> class MamiferoNoAcuatico(Mamifero):
... def __init__(self, mamifero):
... print(mamifero, "no puede nadar.")
... super(MamiferoNoAcuatico, self).__init__(mamifero)
...
>>> class Perro(MamiferoNoAcuatico, MamiferoNoVolador):
... def __init__(self):
... print(
... "Perro tiene 4 piernas.\n",
... )
... super(Perro, self).__init__("Perro")
...
>>> perro = Perro()
Perro tiene 4 piernas.
Perro no puede nadar.
Perro no puede volar.
Perro es un animal de sangre caliente.
Perro es un animal.
>>> Perro.__mro__
(<class '__main__.Perro'>,
<class '__main__.MamiferoNoAcuatico'>,
<class '__main__.MamiferoNoVolador'>,
<class '__main__.Mamifero'>,
<class '__main__.Animal'>,
<type 'object'>)
>>> murcielago = MamiferoNoAcuatico("Murcielago")
Murcielago no puede nadar.
Murcielago es un animal de sangre caliente.
Murcielago es un animal.
>>> MamiferoNoAcuatico.__mro__
(<class '__main__.MamiferoNoAcuatico'>,
<class '__main__.Mamifero'>,
<class '__main__.Animal'>,
<type 'object'>)
El orden en resolver la herencia múltiple esta basado en el principio Method Resolution Order (MRO).
El MRO es calculado en Python de la siguiente forma:
Un método en la llamada derivada es siempre llamada antes de método de la clase base.
En nuestro ejemplo, la clase Perro
es llamada antes de las clases MamiferoNoAcuatico
o MamiferoNoVolador
. Esas dos clases son llamada antes de la clase Mamifero
el cual es llamada antes de la clase Animal
y la clase Animal
es llamada antes
de la clase object
.
Si hay herencia múltiple como Perro(MamiferoNoAcuatico, MamiferoNoVolador)
, el
método de MamiferoNoAcuatico
es invocado primero por que ese aparece primero.
9.8.5. type¶
Los objetos tipo representan los diversos tipos de objeto.
El tipo de un objeto es accesible mediante la función integrada
type(). No hay operaciones especiales sobre los tipos. El
módulo estándar types
define nombres para todos los tipos internos estándar.
>>> type(type)
<type 'type'>
Ver también
Consulte la sección de lecturas suplementarias del entrenamiento para ampliar su conocimiento en esta temática.
¿Cómo puedo ayudar?
¡Mi soporte está aquí para ayudar!
Mi horario de oficina es de lunes a sábado, de 9 AM a 5 PM. GMT-4 - Caracas, Venezuela.
La hora aquí es actualmente 7:35 PM GMT-4.
Mi objetivo es responder a todos los mensajes dentro de un día hábil.
