Categorías
Python

Clasificación texto práctica con Python y Keras

 

Tabla de Contenidos

  • Cómo aleatoria es al azar?
  • lo que es “criptográficamente seguro?”
  • Lo que va a cubrir aquí PRNG
  • en ModulePRNGs azar PythonThe para matrices: PRNG numpy.random
  • El módulo random
  • para matrices: CSPRNGs numpy.random
  • en Pythonos.urandom (): Sobre tan aleatorio como los secretos mejor guardados
  • os.urandom de GetsPython (): Casi tan aleatoria como se pone los secretos mejor guardados
  • Un último candidato de
  • Python: uuid
  • por qué no sólo “por defecto a” SystemRandom?
  • Odds and Ends: PRNGs Hashing
  • Crónica
  • Más vínculos
  • El módulo random
  • para matrices: numpy.random
  • os.urandom (): Sobre tan aleatorio como Obtiene
  • Python Mejor secretos guardados

Mira ahora Este tutorial tiene un vídeo relacionado curso creado por el equipo del real Python. Mira que junto con el tutorial escrito para profundizar su comprensión: Generación de datos aleatorios en Python

Cómo es aleatoria al azar? Esta es una pregunta extraña para preguntar, pero es uno de suma importancia en los casos en que se refiere a seguridad de la información. Siempre que se está generando datos aleatorios, cadenas o números en Python, que es una buena idea tener al menos una idea aproximada de cómo se generan los datos.

Aquí, va a cubrir un puñado de opciones diferentes para generar datos aleatorios en Python, y luego se acumule a una comparación de cada uno en función de su nivel de seguridad, versatilidad, el propósito y la velocidad.

Prometo que este tutorial no va a ser una lección de matemáticas o la criptografía, que no estaría bien equipado para conferencia sobre en el primer lugar. Usted obtendrá en matemáticas apenas tanto como sea necesario, y no más.

Cómo aleatoria es al azar?

En primer lugar, una advertencia prominente es necesario. La mayoría de los datos generados al azar con Python no es totalmente al azar en el sentido científico de la palabra. Más bien, es pseudoaleatorio : generado con un generador de números pseudoaleatorios (PRNG), que es esencialmente cualquier algoritmo para generar datos aparentemente al azar, pero todavía reproducibles.

“verdaderos” números aleatorios puede ser generada por, lo has adivinado, un verdadero generador de números aleatorios (TRNG). Un ejemplo es escoger repetidamente un troquel del suelo, echar en el aire, y dejar que la tierra cómo se puede.

Suponiendo que su lanzamiento es imparcial, usted tiene realmente ni idea de qué número de la matriz aterrizará en. Lanzar un dado es una forma cruda de uso de hardware para generar un número que no es en absoluto determinista. (O, puede hacer que los dados-O-Matic hacer esto para usted.) TRNGs están fuera del alcance de este artículo, pero vale la pena mencionar, sin embargo, para efectos de comparación.

PRNG, generalmente se realiza con el software en lugar de hardware, el trabajo de forma ligeramente diferente. Aquí hay una descripción concisa:

Comienzan con un número aleatorio, conocido como la semilla, y luego usar un algoritmo para generar una secuencia pseudo-aleatoria de bits basados ​​en él. (Fuente)

Es probable que hayan dicho de “leer los documentos!” en algún momento. Bueno, esas personas no están equivocados. He aquí un fragmento particularmente notable a partir de la documentación del módulo de azar que no se quiere perder:

Advertencia : Los generadores pseudo-aleatorios de este módulo no deben utilizarse por razones de seguridad. random.seed (Fuente)

Usted probablemente ha visto (999), random.seed (1234), o similar, en Python. Esta llamada de función está sembrando el generador de números aleatorios subyacente utilizado por el módulo de Python al azar. Es lo que hace que las llamadas posteriores para generar números aleatorios determinista: Entrada de A siempre produce una salida B. Esta bendición también puede ser una maldición si se usa maliciosamente.

Tal vez los términos “al azar” y “determinista” parece como que no pueden existir uno al lado del otro. Para hacer que más clara, aquí es una versión extremadamente reducida de azar () que iterativamente crea un número “aleatorio” mediante el uso de x = (* 3 x)% 19. x se define originalmente como un valor de inicialización y luego se transforma en una secuencia determinista de números en base a esa semilla:

class NotSoRandom(object):
def seed(self, a=3):
"""Seed the world's most mysterious random number generator."""
self.seedval = a
def random(self):
"""Look, random numbers!"""
self.seedval = (self.seedval * 3) % 19
return self.seedval

_inst = NotSoRandom()
seed = _inst.seed
random = _inst.random

no tome este ejemplo demasiado literalmente, ya que está pensado principalmente para ilustrar el concepto. Si utiliza el valor de inicialización 1234, la siguiente secuencia de llamadas a aleatorio () debe ser siempre idéntica:

>>> seed(1234)
>>> [random() for _ in range(10)]
[16, 10, 11, 14, 4, 12, 17, 13, 1, 3]

>>> seed(1234)
>>> [random() for _ in range(10)]
[16, 10, 11, 14, 4, 12, 17, 13, 1, 3]

Verás una más grave ejemplo de esto en breve.

lo que es “criptográficamente seguro?”

Si usted no ha tenido suficiente con las siglas “RNG”, vamos a lanzar una más en la mezcla: un CSPRNG o PRNG criptográficamente seguro. CSPRNGs son adecuados para la generación de datos sensibles, tales como contraseñas, autenticadores, y fichas. Dada una cadena aleatoria, no es realista hay forma de que Joe malicioso para determinar qué cadena llegó antes o después de esa cadena en una secuencia de cadenas aleatorias.

Otro término que se puede ver es entropía . En pocas palabras, esto se refiere a la cantidad de aleatoriedad introducida o deseado. Por ejemplo, un módulo de Python que define las cubiertas en esta DEFAULT_ENTROPY = 32, el número de bytes para devolver de forma predeterminada. Los desarrolladores consideran que esto es “suficiente” bytes a una cantidad suficiente de ruido.

Nota : A través de este tutorial, supongo que un byte se refiere a 8 bits, tal como lo ha hecho desde la década de 1960, en lugar de alguna otra unidad de almacenamiento de datos. Usted es libre de llamar a esto un octeto si así lo prefiere.

Un punto clave sobre CSPRNGs es que son todavía pseudoaleatoria. Están diseñados de alguna manera que es internamente determinista, sino que añadir alguna otra variable o tienen alguna propiedad que hace que sean “suficientemente aleatoria” para prohibir respaldo en lo hace cumplir la función determinismo.

Lo que va a cubrir aquí

En términos prácticos, esto significa que se deben utilizar PRNG lisos para el modelado estadístico, simulación, y para hacer reproducible datos aleatorios. También son significativamente más rápido que CSPRNGs, como se verá más adelante. Use CSPRNGs para aplicaciones criptográficas seguridad y donde la sensibilidad de datos es imprescindible.

Además de ampliar en los casos de uso más arriba, en este tutorial, profundizar en las herramientas de Python para el uso de ambos PRNG y CSPRNGs: opciones

  • PRNG incluyen el módulo de azar de la biblioteca estándar de Python y su contraparte NumPy basada en arreglos , numpy.random. os de
  • Python, secretos, y módulos UUID contienen funciones para la generación de objetos criptográficamente seguros.

Vas a tocar en todo lo anterior y terminará con una comparación de alto nivel. PRNGs

en Python

El azar Módulo

probablemente la herramienta más ampliamente conocida para la generación de datos aleatorios en Python es su módulo aleatorio, que utiliza el algoritmo Mersenne Twister PRNG como su núcleo generador.

Anteriormente, se refirió brevemente a random.seed (), y ahora es un buen tiempo para ver cómo funciona. En primer lugar, vamos a construir algunos datos aleatorios sin sembrar. La función random.random () devuelve un flotador aleatorio en el intervalo [0,0, 1,0). El resultado será siempre menor que el punto final de la derecha (1.0). Esto también se conoce como un rango semiabierto:

>>> # Don't call `random.seed()` yet
>>> import random
>>> random.random()
0.35553263284394376
>>> random.random()
0.6101992345575074

Si ejecuta este código usted mismo, apuesto a ahorros de mi vida que los números devueltos en su máquina serán diferentes. El valor por defecto cuando no la semilla del generador es utilizar su tiempo de sistema actual o una “fuente de aleatoriedad” de su sistema operativo, si está disponible.

Con random.seed (), puede hacer que los resultados reproducibles, y la cadena de llamadas después de random.seed () producirá el mismo camino de los datos:

>>> random.seed(444)
>>> random.random()
0.3088946587429545
>>> random.random()
0.01323751590501987

>>> random.seed(444) # Re-seed
>>> random.random()
0.3088946587429545
>>> random.random()
0.01323751590501987

Aviso la repetición de números “aleatorios”. La secuencia de números aleatorios se convierte determinista, o completamente determinado por el valor de la semilla, 444.

vamos a echar un vistazo a algunas funciones más básicas de azar. Por encima, se genera un flotador al azar. Se puede generar un entero aleatorio entre dos puntos finales en Python con la función random.randint (). Este texto se extiende la plena [x, y] de intervalo y pueden incluir ambos puntos finales:

>>> random.randint(0, 10)
7
>>> random.randint(500, 50000)
18601

Con random.randrange (), puede excluir el lado derecho del intervalo, es decir, el número generado siempre se encuentra dentro [x, y) y será siempre menor que el punto final derecho:

>>> random.randrange(1, 10)
5

Si necesita generar flotadores al azar que se encuentran dentro de un específico [x, y] intervalo, puede utilizar random.uniform (), que de vísceras de la distribución uniforme continua:

>>> random.uniform(20, 30)
27.42639687016509
>>> random.uniform(30, 40)
36.33865802745107

Para elegir un elemento aleatorio a partir de una secuencia no vacía (como una lista o una tupla), puede utilizar random.choice (). También hay random.choices () para elegir varios elementos de una secuencia con reemplazo (duplicados son posibles):

>>> items = ['one', 'two', 'three', 'four', 'five']
>>> random.choice(items)
'four'

>>> random.choices(items, k=2)
['three', 'three']
>>> random.choices(items, k=3)
['three', 'five', 'four']

Para el muestreo sin reemplazo mímica, el uso random.sample ():

>>> random.sample(items, 4)
['one', 'five', 'four', 'three']

Usted puede cambiar aleatoriamente una secuencia en el lugar usando random.shuffle (). Esto modificará el objeto secuencia y aleatoriamente el orden de los elementos:

>>> random.shuffle(items)
>>> items
['four', 'three', 'two', 'one', 'five']

Si prefiere no mutar la lista original, tendrá que hacer una copia primero y luego baraja la copia. Puede crear copias de las listas de Python con el módulo de copia, o simplemente x [:] o x.copy (), donde x es la lista.

Antes de pasar a la generación de datos aleatorios con NumPy, vamos a ver una aplicación más involucrados ligeramente: la generación de una secuencia de cadenas aleatorias únicas de longitud uniforme.

Puede ayudar a pensar en el diseño de la primera función. Es necesario para elegir un “pool” de caracteres tales como letras, números y / o puntuacion, éstos se combinan en una sola cadena, y luego comprobar que esta cadena ya no se ha generado. Un conjunto de Python funciona bien para este tipo de pruebas de la membresía:

import string

def unique_strings(k: int, ntokens: int,
pool: str=string.ascii_letters) -> set:
"""Generate a set of unique string tokens.

k: Length of each token
ntokens: Number of tokens
pool: Iterable of characters to choose from

For a highly optimized version:
https://stackoverflow.com/a/48421303/7954504
"""

seen = set()

# An optimization for tightly-bound loops:
# Bind these methods outside of a loop
join = ''.join
add = seen.add

while len(seen) < ntokens: token = join(random.choices(pool, k=k)) add(token) return seen

'' .join () se une a las cartas de random.choices () en una sola str de Python de longitud k. Este distintivo se añade al conjunto, que no puede contener duplicados, y al mismo tiempo que ejecuta un lazo hasta que el conjunto tiene el número de elementos que se especifique.

Recursos : módulo de cadenas de Python contiene una serie de constantes útiles: ascii_lowercase, ascii_uppercase, string.punctuation, ascii_whitespace, y un puñado de otros. try de

Let esta función a cabo:

>>> unique_strings(k=4, ntokens=5)
{'AsMk', 'Cvmi', 'GIxv', 'HGsZ', 'eurU'}

>>> unique_strings(5, 4, string.printable)
{"'O*1!", '9Ien%', 'W=m7<', 'mUD|z'}

Para una versión afinada de esta función, esta usos respuesta desbordamiento de pila generador funciones, la unión nombre, y algunos otros trucos avanzados para hacer una versión más rápida criptográficamente seguro de unique_strings () por encima .

PRNG para Arrays: numpy.random

Una cosa que usted puede haber notado es que la mayoría de las funciones de retorno al azar un valor escalar (un solo int, float, o cualquier otro objeto). Si quería generar una secuencia de números aleatorios, una forma de lograr eso sería con una lista por comprensión Python:

>>> [random.random() for _ in range(5)]
[0.021655420657909374,
0.4031628347066195,
0.6609991871223335,
0.5854998250783767,
0.42886606317322706]

Pero hay otra opción que está diseñado específicamente para esto. Se puede pensar en numpy.random propio paquete de NumPy como si fuera la norma de la biblioteca de azar, pero para las matrices NumPy. (También viene cargado con la capacidad de extraer de mucho más distribuciones estadísticas.)

tomar en cuenta que numpy.random utiliza su propio PRNG que está separado del viejo y simple al azar. No se producirá matrices NumPy forma determinista al azar con una llamada a la propia random.seed de Python ():

>>> import numpy as np
>>> np.random.seed(444)
>>> np.set_printoptions(precision=2) # Output decimal fmt.

Sin más preámbulos, aquí están algunos ejemplos para abrir el apetito:

>>> # Return samples from the standard normal distribution
>>> np.random.randn(5)
array([ 0.36, 0.38, 1.38, 1.18, -0.94])

>>> np.random.randn(3, 4)
array([[-1.14, -0.54, -0.55, 0.21],
[ 0.21, 1.27, -0.81, -3.3 ],
[-0.81, -0.36, -0.88, 0.15]])

>>> # `p` is the probability of choosing each element
>>> np.random.choice([0, 1], p=[0.6, 0.4], size=(5, 4))
array([[0, 0, 1, 0],
[0, 1, 1, 1],
[1, 1, 1, 0],
[0, 0, 0, 1],
[0, 1, 0, 1]])

En la sintaxis para randn (D0, D1 , ..., dn), los parámetros D0, D1, ..., dn son opcionales e indicar la forma del objeto final. Aquí, np.random.randn (3, 4) crea una matriz 2D con 3 filas y 4 columnas. Los datos se i.i.d., lo que significa que cada punto de datos se dibuja independiente de los demás.

Otra operación común es crear una secuencia de valores booleanas aleatorias, verdadero o falso. Una forma de hacerlo sería con np.random.choice ([Verdadero, Falso]). Sin embargo, en realidad es sobre 4 veces más rápido que elegir (0, 1) y luego ver fundido a estos números enteros a sus correspondientes valores booleanos:

>>> # NumPy's `randint` is [inclusive, exclusive), unlike `random.randint()`
>>> np.random.randint(0, 2, size=25, dtype=np.uint8).view(bool)
array([ True, False, True, True, False, True, False, False, False,
False, False, True, True, False, False, False, True, False,
True, False, True, True, True, False, True])

¿Qué pasa con la generación de datos correlacionados? Digamos que desea simular dos series de tiempo correlacionados. Una manera de ir sobre esto es con la función de NumPy multivariate_normal (), que tiene una matriz de covarianza en cuenta. En otras palabras, para extraer de una sola variable aleatoria distribuida normalmente, es necesario especificar su (desviación estándar o) media y la varianza.

Para muestra de la distribución normal multivariante, se especifica la matriz de medios y de covarianza, y se termina con múltiple, serie correlacionados de datos que son cada una de aproximadamente normalmente distribuidos.

Sin embargo, en lugar de covarianza, la correlación es una medida que es más familiar e intuitivo para la mayoría. Es la covarianza normalizado por el producto de las desviaciones estándar, y así también se puede definir de covarianza en términos de correlación y la desviación estándar:

S O, ¿podría extraer muestras al azar de una distribución normal multivariable especificando una matriz de correlación y las desviaciones estándar? Sí, pero necesitará para conseguir lo anterior en forma de matriz en primer lugar. Aquí, S es un vector de las desviaciones estándar, P es su matriz de correlación, y C es la resultante (cuadrado) matriz de covarianza:

Esto se puede expresar en NumPy de la siguiente manera:

def corr2cov(p: np.ndarray, s: np.ndarray) -> np.ndarray:
"""Covariance matrix from correlation & standard deviations"""
d = np.diag(s)
return d @ p @ d

Ahora, puede generar dos series de tiempo que están correlacionados pero aún azar:

>>> # Start with a correlation matrix and standard deviations.
>>> # -0.40 is the correlation between A and B, and the correlation
>>> # of a variable with itself is 1.0.
>>> corr = np.array([[1., -0.40],
... [-0.40, 1.]])

>>> # Standard deviations/means of A and B, respectively
>>> stdev = np.array([6., 1.])
>>> mean = np.array([2., 0.5])
>>> cov = corr2cov(corr, stdev)

>>> # `size` is the length of time series for 2d data
>>> # (500 months, days, and so on).
>>> data = np.random.multivariate_normal(mean=mean, cov=cov, size=500)
>>> data[:10]
array([[ 0.58, 1.87],
[-7.31, 0.74],
[-6.24, 0.33],
[-0.77, 1.19],
[ 1.71, 0.7 ],
[-3.33, 1.57],
[-1.13, 1.23],
[-6.58, 1.81],
[-0.82, -0.34],
[-2.32, 1.1 ]])
>>> data.shape
(500, 2)

se puede pensar en los datos como 500 pares de puntos de datos inversamente correlacionados. Aquí está una comprobación de validez que puede realizar copias en las entradas originales, que se aproximan corr, DESVEST y media desde arriba:

>>> np.corrcoef(data, rowvar=False)
array([[ 1. , -0.39],
[-0.39, 1. ]])

>>> data.std(axis=0)
array([5.96, 1.01])

>>> data.mean(axis=0)
array([2.13, 0.49])

Antes de pasar a CSPRNGs, podría ser útil resumir algunas funciones aleatorias y sus homólogos numpy.random:

Nota : NumPy está especializada para la construcción y manipulación de matrices grandes y multidimensionales. Si sólo tiene un único valor, basta voluntad azar y probablemente será más rápido también. Para las secuencias pequeñas, al azar puede ser incluso más rápido también, porque NumPy viene con algo de sobrecarga.

Ahora que hemos cubierto dos opciones fundamentales para PRNG, movimiento Vamos a algunas adaptaciones más seguros. CSPRNGs

en Python

os.urandom (): Sobre como aleatoria, ya que hace la función de

Python os.urandom () es utilizado tanto por los secretos y UUID (ambos de los cuales se le ve aquí en un momento). Sin entrar en demasiados detalles, os.urandom () genera bytes aleatorios del sistema operativo dependiente que con seguridad se puede llamar criptográficamente seguro: los sistemas operativos

  • en Unix, se lee bytes aleatorios desde el archivo especial / dev / urandom, que a su vez, “permitir el acceso al ruido ambiental recogido de los controladores de dispositivos y otras fuentes.” (Gracias, Wikipedia.) Esta es la información confusa que es particular de su hardware y el estado del sistema en un caso en el tiempo, pero al mismo tiempo lo suficientemente aleatoria.
  • En Windows, el C ++ CryptGenRandom función () se utiliza. Esta función es todavía técnicamente pseudoaleatorio, pero funciona mediante la generación de un valor de inicialización de variables tales como el ID de proceso, estado de la memoria, y así sucesivamente.

en sistemas operativos UNIX, se lee bytes aleatorios desde el fichero / dev / urandom especial, que a su vez “permitir el acceso al ruido ambiental recogido de los controladores de dispositivos y otras fuentes.” (Gracias, Wikipedia.) Esta es la información confusa que es particular de su hardware y el estado del sistema en un caso en el tiempo, pero al mismo tiempo lo suficientemente aleatoria.

En Windows, el C ++ CryptGenRandom función () se utiliza. Esta función es todavía técnicamente pseudoaleatorio, pero funciona mediante la generación de un valor de inicialización de variables tales como el ID de proceso, estado de la memoria, y así sucesivamente.

Con os.urandom (), no existe el concepto de sembrar manualmente. Aunque todavía técnicamente pseudoaleatoria, esta función alinea mejor con nuestra forma de pensar de la aleatoriedad. El único argumento es el número de bytes de retorno:

>>> os.urandom(3)
b'\xa2\xe8\x02'

>>> x = os.urandom(6)
>>> x
b'\xce\x11\xe7"!\x84'

>>> type(x), len(x)
(bytes, 6)

Antes de ir más lejos, esta podría ser una buena época para ahondar en una mini-lección sobre la codificación de caracteres. Mucha gente, incluido yo mismo, tienen algún tipo de reacción alérgica cuando ven bytes objetos y una larga lista de \ x caracteres. Sin embargo, es útil saber cómo las secuencias tales como x encima finalmente llegar a convertirse en cadenas o números.

os.urandom () devuelve una secuencia de bytes individuales:

>>> x
b'\xce\x11\xe7"!\x84'

Pero, ¿cómo esto finalmente llegar a convertirse en un str Python o secuencia de números?

En primer lugar, un recuerdo de los conceptos fundamentales de la computación, y es que un byte se compone de 8 bits. Se puede pensar en un poco como un solo dígito que es ya sea 0 ó 1. Un byte efectivamente elige entre 0 y 1 ocho veces, por lo tanto 01101100 y 11110000 podría representar bytes. Prueba de esto, que hace uso de Python f-secuencias introducidas en Python 3.6, en su intérprete:

>>> binary = [f'{i:0>8b}' for i in range(256)]
>>> binary[:16]
['00000000',
'00000001',
'00000010',
'00000011',
'00000100',
'00000101',
'00000110',
'00000111',
'00001000',
'00001001',
'00001010',
'00001011',
'00001100',
'00001101',
'00001110',
'00001111']

Esto es equivalente a [bin (i) para i en el rango (256)], con un poco de formato especial. bin () convierte un entero a su representación binaria como una cadena.

Dónde nos deja eso? Utilizando el rango de (256) anterior no es una elección al azar. (Sin juego de palabras.) Dado que se nos permite 8 bits, cada uno con 2 opciones, hay 2 ** 8 == 256 posibles bytes “combinaciones”.

Esto significa que cada byte se asigna a un número entero entre 0 y 255. En otras palabras, necesitaríamos más de 8 bits para expresar el entero 256. Esto se puede verificar comprobando que len (f '{256: 0> 8b } ') es ahora 9, no 8.

bien, ahora vamos a volver al tipo de datos bytes que se vio anteriormente, mediante la construcción de una secuencia de los bytes que corresponden a los números enteros de 0 a 255:

>>> bites = bytes(range(256))

Si se llama a la lista (picaduras), que obtendrá de nuevo a una lista de Python que va de 0 a 255. Pero si sólo imprimir picaduras, se obtiene una secuencia de aspecto desagradable llena de barras invertidas:

>>> bites
b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15'
'\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJK'
'LMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86'
'\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b'

# ...

Estas barras invertidas son secuencias de escape, y \ xhh representa el personaje con hh valor hexadecimal. Algunos de los elementos de las picaduras se muestran literalmente los caracteres imprimibles (tales como letras, números y puntuacion). La mayoría se expresan con escapes. \ X08 representa retroceso de un teclado, mientras que \ x13 es un retorno de carro (parte de una nueva línea, en los sistemas Windows).

I f tiene por qué un re f resher en hexadecimal un Decim un l, Ch un RLEs Código de Petzold: The Hidden L un ngu un ge es un gre un t pl un ce f o º un t. Hex es un b un se-16 sistema de numeración º un t, INSTE un hacer f usando de 0 a 9, los usos de 0 a 9 un nd un través f una es su b un dígitos SIC.

Por último, vamos a volver al punto de partida, con la secuencia de bytes aleatoria x. Espero que esto hace un poco más de sentido ahora. Llamando .hex () en un objeto bytes da una str de números hexadecimales, con cada uno correspondiente a un número decimal de 0 a 255:

>>> x
b'\xce\x11\xe7"!\x84'

>>> list(x)
[206, 17, 231, 34, 33, 132]

>>> x.hex()
'ce11e7222184'

>>> len(x.hex())
12

Una última pregunta: ¿cómo es b.hex () 12 caracteres anterior, a pesar de que x está a sólo 6 bytes? Esto se debe a dos dígitos hexadecimales corresponden exactamente a un solo byte. La versión str de bytes será siempre el doble de tiempo en lo que se refiere a nuestros ojos.

Incluso si el byte (como \ x01) no necesita un total de 8 bits para ser representado, b.hex () siempre se utilizarán dos dígitos hexadecimales por byte, por lo que el número 1 se representa como 01 en lugar de sólo 1 . Matemáticamente, sin embargo, ambos son del mismo tamaño.

Detalle técnico : Lo que ha diseccionado sobre todo aquí es cómo un objeto bytes convierte en un str de Python. Un otro detalle técnico es cómo bytes producidos por os.urandom () se convierten a un flotador en el intervalo [0,0, 1,0), como en la versión criptográficamente seguro de random.random (). Si usted está interesado en explorar más a fondo, este fragmento de código demuestra cómo int.from_bytes () hace que la conversión inicial a un número entero, usando un sistema de numeración de base 256. Con

que bajo su cinturón, el contacto de corriente de un módulo de reciente introducción, secretos, lo que hace que la generación de tokens seguros mucho más fácil de usar. Secretos mejor guardados de

Python

introdujo en Python 3.6 por uno de los más coloridos PEP por ahí, el módulo de secretos está destinado a ser el facto módulo de Python para generar criptográficamente seguro bytes aleatorios y cadenas.

Se puede extraer el código fuente del módulo, que es corto y dulce a cerca de 25 líneas de código. secretos es básicamente una envoltura alrededor de os.urandom (). Exporta sólo un puñado de funciones para la generación de números aleatorios, bytes, y cuerdas. La mayoría de estos ejemplos debe ser bastante explica por sí mismo:

>>> n = 16

>>> # Generate secure tokens
>>> secrets.token_bytes(n)
b'A\x8cz\xe1o\xf9!;\x8b\xf2\x80pJ\x8b\xd4\xd3'
>>> secrets.token_hex(n)
'9cb190491e01230ec4239cae643f286f'
>>> secrets.token_urlsafe(n)
'MJoi7CknFu3YN41m88SEgQ'

>>> # Secure version of `random.choice()`
>>> secrets.choice('rain')
'a'

Ahora bien, ¿qué tal un ejemplo concreto? Probablemente ha utilizado los servicios de acortador de URLs como tinyurl.com o bit.ly que convertir una URL difícil de manejar en algo así como https://bit.ly/2IcCp9u. La mayoría de los acortadores no hacen ningún hash complicado desde la entrada hasta la salida; que sólo generan una cadena aleatoria, asegúrese de que la cadena ya no se ha generado con anterioridad, y que luego atar de nuevo a la URL de entrada. digamos de

Let que después de echar un vistazo a la base de datos de la zona radicular, que se haya registrado el sitio short.ly . He aquí una función para que pueda empezar con su servicio:

# shortly.py

from secrets import token_urlsafe

DATABASE = {}

def shorten(url: str, nbytes: int=5) -> str:
ext = token_urlsafe(nbytes=nbytes)
if ext in DATABASE:
return shorten(url, nbytes=nbytes)
else:
DATABASE.update({ext: url})
return f'short.ly/{ext}

Es este un ejemplo real de pleno derecho? No. Yo apostaría que bit.ly hace las cosas de una manera un poco más avanzado que el almacenamiento de su mina de oro en un diccionario global de Python que no es persistente entre las sesiones. Sin embargo, es más o menos precisa conceptualmente:

>>> urls = (
... 'https://realpython.com/',
... 'https://docs.python.org/3/howto/regex.html'
... )

>>> for u in urls:
... print(shorten(u))
short.ly/p_Z4fLI
short.ly/fuxSyNY

>>> DATABASE
{'p_Z4fLI': 'https://realpython.com/',
'fuxSyNY': 'https://docs.python.org/3/howto/regex.html'}

Hold On: Una cosa que usted puede notar es que ambos resultados son de longitud 7 cuando solicitó 5 bytes. Espera, pensé que habías dicho que el resultado sería el doble de tiempo? Bueno, no exactamente, en este caso. Hay una cosa más en todo esto: token_urlsafe () utiliza la codificación Base64, donde cada personaje es de 6 bits de datos. (Es de 0 a 63, y los caracteres correspondientes. Los personajes son AZ, az, 0-9 y + /.)

Si originalmente especificar un cierto número de bytes nbytes, la longitud resultante de secrets.token_urlsafe (nbytes) será ser Math.ceil (nbytes * 8/6), que permite demostrar e investigar más a fondo si tienes curiosidad.

El fondo aquí es que, mientras secretos es en realidad sólo una envoltura alrededor de las funciones de Python existentes, puede ser su go-a cuando la seguridad es su principal preocupación.

Un último candidato: uuid

Una última opción para generar un testigo aleatorio es la función uuid4 () del módulo de UUID de Python. Un UUID es un único universalmente identificador, una secuencia de 128 bits (str de longitud 32) diseñado para “singularidad garantía a través del espacio y el tiempo.” uuid4 () es una de las funciones más útiles del módulo, y esta función también utiliza os.urandom ():

>>> import uuid

>>> uuid.uuid4()
UUID('3e3ef28d-3ff0-4933-9bba-e5ee91ce0e7b')
>>> uuid.uuid4()
UUID('2e115fcb-5761-4fa1-8287-19f4ee2877ac')

Lo bueno es que todas las funciones del UUID producen una instancia de la clase UUID, que encapsula el ID y tiene propiedades como .int, .bytes y .hex:

>>> tok = uuid.uuid4()
>>> tok.bytes
b'.\xb7\x80\xfd\xbfIG\xb3\xae\x1d\xe3\x97\xee\xc5\xd5\x81'

>>> len(tok.bytes)
16
>>> len(tok.bytes) * 8 # In bits
128

>>> tok.hex
'2eb780fdbf4947b3ae1de397eec5d581'
>>> tok.int
62097294383572614195530565389543396737

también puede haber visto algunas otras variaciones: uuid1 (), uuid3 (), y uuid5 (). La diferencia clave entre estos y uuid4 () es que esas tres funciones todos toman algún tipo de entrada y por lo tanto no cumplen con la definición de “aleatorio” en la medida en que una versión 4 UUID hace: uuid1

  • () utiliza su ID de host de la máquina y la hora actual por defecto. Debido a la dependencia en el tiempo actual de la resolución de nanosegundos, esta versión es donde UUID deriva la reclamación “garantizado singularidad a través del tiempo.”
  • uuid3 () y uuid5 () ambos toman un identificador de nombre y un nombre. El primero utiliza una de hash MD5 y los últimos usos SHA-1.

uuid1 () utiliza el ID de host de la máquina y la hora actual por defecto. Debido a la dependencia en el tiempo actual de la resolución de nanosegundos, esta versión es donde UUID deriva la reclamación “garantizado singularidad a través del tiempo.”

uuid3 () y uuid5 () ambos toman un identificador de nombre y un nombre. El primero utiliza una de hash MD5 y los últimos usos SHA-1.

uuid4 (), por el contrario, es totalmente pseudoaleatorio (o al azar). Se compone de 16 bytes conseguir a través de os.urandom (), que convierte a un entero big endian, y haciendo una serie de operaciones bit a bit para cumplir con la especificación formal.

Con suerte, por ahora usted tiene una idea buena de la distinción entre los diferentes “tipos” de datos al azar y cómo crearlos. Sin embargo, otro problema que puede venir a la mente es la de colisiones.

En este caso, una colisión simplemente se referiría a la generación de dos UUID las características determinadas. ¿Cuál es la probabilidad de que? Bueno, técnicamente no es cero, pero tal vez es lo suficientemente cerca: hay 2 ** 128 o 340 undecillones posibles valores uuid4. Por lo tanto, lo dejaré hasta usted para juzgar si esto es una garantía suficiente para dormir bien.

Un uso común de UUID es en Django, que tiene una UUIDField que se utiliza a menudo como una clave principal en la base de datos relacional subyacente de un modelo.

por qué no sólo “por defecto a” SystemRandom?

Además de los módulos seguros discutido aquí como secretos, módulo random de Python en realidad tiene una clase poco utilizado llamada SystemRandom que los usos os.urandom (). (SystemRandom, a su vez, también se utiliza por secretos. Todo es un poco de una web que se remonta a urandom ()).

En este punto, se puede preguntar por qué lo haría no sólo “por defecto a” este ¿versión? ¿Por qué no “estar siempre seguro” en lugar de impago a las funciones aleatorias deterministas que no son seguros criptográficamente?

ya he mencionado una razón: a veces desea que sus datos sean determinista y reproducible para que otros sigan junto con.

Pero la segunda razón es que CSPRNGs, al menos en Python, tienden a ser significativamente más lento que el PRNG. La prueba de dejar que eso con un guión, timed.py, que compara las versiones PRNG y CSPRNG de randint () usando timeit.repeat de Python ():

# timed.py

import random
import timeit

# The "default" random is actually an instance of `random.Random()`.
# The CSPRNG version uses `SystemRandom()` and `os.urandom()` in turn.
_sysrand = random.SystemRandom()

def prng() -> None:
random.randint(0, 95)

def csprng() -> None:
_sysrand.randint(0, 95)

setup = 'import random; from __main__ import prng, csprng'

if __name__ == '__main__':
print('Best of 3 trials with 1,000,000 loops per trial:')

for f in ('prng()', 'csprng()'):
best = min(timeit.repeat(f, setup=setup))
print('\t{:8s} {:0.2f} seconds total time.'.format(f, best))

Ahora para ejecutar desde el shell:

$ python3 .imed.py
Best of 3 trials with 1,000,000 loops per trial:
prng() 1.07 seconds total time.
csprng() 6.20 seconds total time.

Un 5x diferencia de tiempo es, sin duda una consideración válida además de la seguridad criptográfica la hora de elegir entre los dos.

Odds and Ends: Hashing

Un concepto que no ha recibido mucha atención en este tutorial es el de hash, lo que puede hacerse con el módulo hashlib de Python.

Un hash está diseñado para ser un mapeo de ida desde un valor de entrada a una cadena de tamaño fijo que es prácticamente imposible de realizar ingeniería inversa. Como tal, mientras que el resultado de una función hash puede “ver” como datos aleatorios, que en realidad no calificar bajo la definición aquí.

Crónica

que ha cubierto mucho terreno en este tutorial. En resumen, aquí es una comparación de alto nivel de las opciones disponibles para usted para la aleatoriedad de ingeniería en Python:

no dude en dejar algunos comentarios totalmente al azar abajo, y gracias por leer.

ofrece enlaces adicionales

  • random.org “verdaderos números aleatorios a cualquier usuario de Internet” derivado de ruido atmosférico. La sección
  • Recetas del módulo aleatorio tiene algunos trucos adicionales.
  • El artículo seminal sobre la Mersienne Twister apareció en 1997, si usted está en ese tipo de cosas.
  • Los itertools Recetas definir funciones para la elección al azar de un conjunto combinatorio, tal como de combinaciones o permutaciones.
  • scikit-learn incluye varios generadores de muestra al azar que se pueden utilizar para construir conjuntos de datos artificiales de tamaño y complejidad controlada.
  • Eli Bendersky se clava en random.randint () en su artículo Métodos lentas y rápidas para la generación de números enteros aleatorios en Python.
  • Peter Norvig un hormigón Introducción a la probabilidad usando Python es un recurso completo también. biblioteca
  • las pandas incluye un gestor de contexto que se puede utilizar para establecer un estado aleatorio temporal.
  • De desbordamiento de pila: Fechas de Generación de azar en un Dada RangeFastest manera de generar un Random-como única cadena con Random LengthHow al uso random.shuffle () en un aleatoria Elementos GeneratorReplace en unos números NumPy ArrayGetting desde / dev / random en Python
  • Fechas

  • Generación de azar en un intervalo dado
  • manera más rápida de generar una random.shuffle aleatoria como única cadena con la longitud aleatoria
  • cómo utilizar () en un generador aleatorio
  • Reemplazar elementos de una matriz NumPy
  • Introducir números de / dev / random en fechas Python
  • Generación de azar en un intervalo dado
  • más rápida manera de generar un Random-como única cadena con la longitud aleatoria
  • cómo utilizar random.shuffle () en un generador aleatorio
  • Reemplazar Elementos en una matriz de NumPy
  • Introducir números desde / dev / random en Python

Mira ahora Este tutorial tiene un vídeo relacionado curso creado por el equipo del real Python. Mira que junto con el tutorial escrito para profundizar su comprensión: Generación de datos aleatorios en Python

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *