CursosEmpresasBlogLiveConfPrecios

Generadores

Clase 14 de 21 • Curso Profesional de Python

Clase anteriorSiguiente clase

Contenido del curso

Introducción
  • 1
    ¿Qué necesitas saber para tomar el curso?

    ¿Qué necesitas saber para tomar el curso?

    03:15
  • 2
    ¿Cómo funciona Python?

    ¿Cómo funciona Python?

    07:49
  • 3
    Cómo organizar las carpetas de tus proyectos

    Cómo organizar las carpetas de tus proyectos

    07:15
Static Typing
  • 4
    ¿Qué son los tipados?

    ¿Qué son los tipados?

    10:26
  • 5
    Tipado estático en Python

    Tipado estático en Python

    14:26
  • 6
    Practicando el tipado estático

    Practicando el tipado estático

    13:33
Conceptos avanzados de funciones
  • 7
    Scope: alcance de las variables

    Scope: alcance de las variables

    06:32
  • 8
    Closures

    Closures

    08:21
  • 9
    Programando closures

    Programando closures

    07:00
  • 10
    Decoradores

    Decoradores

    06:19
  • 11
    Programando decoradores

    Programando decoradores

    13:05
Estructuras de datos avanzadas
  • 12
    Iteradores

    Iteradores

    13:52
  • 13
    La sucesión de Fibonacci

    La sucesión de Fibonacci

    14:01
  • 14
    Generadores

    Generadores

    07:22
  • 15
    Mejorando nuestra sucesión de Fibonacci

    Mejorando nuestra sucesión de Fibonacci

    06:53
  • 16
    Sets

    Sets

    10:58
  • 17
    Operaciones con sets

    Operaciones con sets

    06:09
  • 18
    Eliminando los repetidos de una lista

    Eliminando los repetidos de una lista

    05:20
Bonus
  • 19
    Manejo de fechas

    Manejo de fechas

    08:44
  • 20
    Time zones

    Time zones

    08:46
Conclusión
  • 21
    Completaste la trilogía. ¿Cómo seguir?

    Completaste la trilogía. ¿Cómo seguir?

    01:30
    Andrés Gutiérrez Arcia

    Andrés Gutiérrez Arcia

    student•
    hace 4 años

    Yo uso generadores para retornar un resultado de una consulta en BigQuery. Como son muchísimos datos, es ideal iterar sobre el resultado de manera lazy

      Fredy Garcia

      Fredy Garcia

      student•
      hace 4 años

      Hola Andrés que tal?, es muy interesante, me puedes compartir un ejemplo, por favor?

      Julio Gutierrez

      Julio Gutierrez

      company_admin•
      hace 4 años

      Tienes algún ejemplo? Saludos.

    Miguel Angel Reyes Moreno

    Miguel Angel Reyes Moreno

    student•
    hace 4 años

    Generadores

    Sugar syntax de los iteradores. Los generadores son funciones que guardan un estado. Es un iterador escrito de forma más simple.

    def my_gen(): """un ejemplo de generadores""" print('Hello world!') n = 0 yield n # es exactamente lo mismo que return pero detiene la función, cuando se vuelva a llamar a la función, seguirá desde donde se quedó print('Hello heaven!') n = 1 yield n print('Hello hell!') n = 2 yield n a = my_gen() print(next(a)) # Hello world! print(next(a)) # Hello heaven! print(next(a)) # Hello hell! print(next(a)) StopIteration

    Ahora veremos un generator expression (es como list comprehension pero mucho mejor, porque podemos manejar mucha cantidad de información sin tener problemas de rendimiento):

    #Generator expression my_list = [0,1,4,7,9,10] my_second_list = [x*2 for x in my_list] #List comprehension my_second_gen = ()x*2 for x in my_list]) #Generator expression
      Luis Alejandro Vera Hernandez

      Luis Alejandro Vera Hernandez

      student•
      hace 4 años

      Gracias por el resumen

      Javier Suárez Meerhoff

      Javier Suárez Meerhoff

      student•
      hace 4 años

      gracias!

    Pedro Alvarado Garcia

    Pedro Alvarado Garcia

    student•
    hace 4 años

    En el minuto 5:44 más bien seria el doble, no el cuadrado.

      Pablo Antipan Quiñenao

      Pablo Antipan Quiñenao

      student•
      hace 4 años

      Tenes razon Pedro! Seguramente al profesor se le fue un '*'. Con ello son efectivamente los cuadrados!

    Christian Molina Vázquez

    Christian Molina Vázquez

    student•
    hace 4 años

    Python internamente utiliza operaciones con generadores para aumentar el rendimiento. Tal es el caso de máx , min o sum. Ejemplo:

    suma = sum([i for i in range(100)]) # Crea la lista en memoria. suma_gen = sum(i for i in range(100)) #Itera sobre los valores.

    El el primer caso, creamos una lista que no nos servirá y se termina guardando el espacio en memoria, en el segundo caso se itera cada valor hasta obtener el resultado sin la necesidad de guardar en memoria cada valor.

      Giovanni Osorio

      Giovanni Osorio

      student•
      hace 4 años

      no funciona, desde que se utiliza la función sum() for fuera de los [] o () se anula el generador y la lista

      al utilizar

      print(type(suma)) print(type(suma_gen)) >>> <class 'int'> <class 'int'>
      Juan Antonio Aramburo Pasapera

      Juan Antonio Aramburo Pasapera

      student•
      hace 3 años

      No es de que suma y suma_gen sean generadores, ambos son la suma de los primeros 100 números, es decir, enteros. Lo que pasa es que en suma_gen, la suma se hace sumando lo que va devolviendo el generador entonces no tienes que almacenar la lista. Mientras que en sum, primero creas la lista con list comprenhension y luego iteras sobre ella para hacer la suma. Entonces supongo que sum_gen será más eficiente, al menos en memoria.

    Carlos José Tun Pinzón

    Carlos José Tun Pinzón

    student•
    hace 4 años

    Generator Expression

    Es lo mismo que un iterador pero escrito de forma más elegante.

    Un "list comprehension" es una manera sencilla de implementar un ciclo el cual nos permite crear una nueva lista con elementos basados en los valores de una lista existente. Dicha lista creada almacena cada uno de estos nuevos valores.

    A diferencia de un List comprehension que puede ocupar mucha memoria pues cada valor es almacenado en la variable, un Generator expression solo los recorre, sin guardarlos en una lista nueva. Permite traer un elemento a la vez cuando se recorra usando un ciclo for.

    # Generator expression my_list = [0, 1, 4, 7, 9, 10] my_second_list = [x*2 for x in my_list] # List comprehension my_second_gen = (x*2 for x in my_list) # Generator expression

    Como se puede ver en el ejemplo, la diferencia en la sintaxis únicamente es en el uso de paréntesis en lugar del uso de corchetes.

    Ventajas de los Generadores:

    • Es mas fácil de escribir que un iterador
    • Ahorra Tiempo y Memoria
    • Permite guardar secuencias infinitas
    Luis Kennedy Saavedra Fuentes

    Luis Kennedy Saavedra Fuentes

    student•
    hace 4 años

    Buenos días.

    Mi script para ver la diferencia del tiempo al ejecutarse una list comprehension y un iterator expression

    from datetime import datetime LIST = [1, 2, 4, 5, 20, 100, 500, 1000] def list_comprehension(): """Function run as start""" time_start = datetime.now() list_comprehension = [x*2 for x in LIST] time_final = datetime.now() time = time_final -time_start print(f'Time for create list comprehension: {time}') print(f'list_comprehension: {list_comprehension}') return time def generator_expression(): """Function run as start""" time_start = datetime.now() generator_expression = (x*2 for x in LIST) time_final = datetime.now() time = time_final -time_start for i in generator_expression: print(i) print(f'Time for create generator espression: {time}') return time def run(): """Function run as start""" x = list_comprehension() y = generator_expression() print(f'Difference: {x - y}') if __name__ == '__main__': run()
      Luis Rivero

      Luis Rivero

      student•
      hace 4 años

      También puedes hacer uso de un decorador:

      from datetime import datetime #decorador def execution_time(func): def wrapper(*args, **kwargs): initial_time = datetime.now() func(*args, **kwargs) final_time = datetime.now() time_execution = final_time - initial_time second_execution = str(time_execution.total_seconds()) print(f'El tiempo de ejecución fue de: {second_execution} segundos') return wrapper @execution_time def with_list_comprehension(): my_list = [1,4,5,10,20,22,33,55] my_second_list = [x**2 for x in my_list] print(my_second_list) @execution_time def with_generator(): my_list = [1,4,5,10,20,22,33,55] my_second_gen = (x**2 for x in my_list) print(next(my_second_gen)) #solo muestra 1 if __name__ == '__main__': with_list_comprehension() with_generator()
    Jesús Velázquez Jiménez

    Jesús Velázquez Jiménez

    student•
    hace 4 años

    Los Generadores son iteradores con Sugar Syntax.

    Yield es una palabra clave que se usa para retornar de una función sin destruir los estados de las variables locales y cuando se llama a la función, la ejecución comienza desde el último yield declarado. Toda función que contenga la palabra clave yield es denominada como un generador.

      María Jimena Rodríguez Contreras

      María Jimena Rodríguez Contreras

      student•
      hace 4 años

      gracias

    Pablo Aquino

    Pablo Aquino

    student•
    hace 4 años
    • yield, es similar a return, con la diferencia que la próxima vez que se llame a la función, esta continuará desde el último yield.
    • Un generador es similar a un iterador.
    oscar yesid vargas pedraza

    oscar yesid vargas pedraza

    student•
    hace 4 años

    si ejecutamos el siguiente código:

    if __name__ == "__main__": my_list = [1, 2, 3, 4] new_list = [x for x in my_list] new_gene = (x for x in my_list) print(next(new_gene)) print(next(new_gene)) print(next(new_gene)) print(next(new_gene))

    obtenemos una secuencia de números

    # 1 # 2 # 3 # 4

    Al ejecutarlo así me fue mas fácil comprenderlo

    Sebastián Andrade

    Sebastián Andrade

    student•
    hace 4 años

    El codigo del generator expression podria programarse a modo de funcion asi?

    def gen(arr): for i in arr: yield i**2
      Pablo Antipan Quiñenao

      Pablo Antipan Quiñenao

      student•
      hace 4 años

      Hola! Encontré muy interesante tu código! Ahora bien, solo a modo de opinion, el profesor indica que la idea es NO emplear un array. Empleando tu misma idea, escribiría esto:

      def c_gen(max=None): n = 0 while n ** 2 < max: yield n ** 2 n += 1 this_gen = c_gen(10) for item in this_gen: print(item)

      Saludos!!

      Cesar Hernández Ramírez

      Cesar Hernández Ramírez

      student•
      hace 4 años

      Me encantó lo que propuso @pablo, pero sí @sebastian, así sería la manera de programarse a manera de función, especialmente cuando trabajes con un array preestablecido y finito esa sería la manera de hacerlo, o si puedes replicar los datos de ese array con alguna formula en código, es ideal usar la manera que propone @pablo

    Gabriel Missael Barco

    Gabriel Missael Barco

    student•
    hace 4 años

    Generadores

    • Los iteradores tienen sugar syntax 💖. Son llamados generadores, los cuales son funciones que guardan un estado 🤔.

    • Los generadores son funciones: 🔥

      def my_gen(): """Un ejemplo de generadores""" print("Hello world!") n = 0 yield n print("Hello heaven!") n = 1 yield n print("Hello hell!") n = 2 yield n # Lo instanciamos a = my_gen() print(next(a)) # Hello world! print(next(a)) # Hello heaven! print(next(a)) # Hello hell! print(next(a)) # StopIteration
    • yield este keyword es análoga al return, pero no termina la función, le pone pausa. La siguiente ejecución, corre después de este punto 👀.

    • Generator expression. 🤯 Se trae un elemento a la vez, y no ocupa toda la memoria 😯.

      my_list = [0, 1, 2, 3, 4, 5, 6] my_second_list = [x*2 for x in my_list] # List comprehension my_second_gen = (x*2 for x in my_list) # Generator expression
    • La ventaja de los generadores es que es más fácil de escribir que un iterador, y tiene las mismas ventajas que este último. 💕

    Giovanni Osorio

    Giovanni Osorio

    student•
    hace 4 años

    lista de numeros impares VS generador de numeros impares

    import time impares = [2*i+1 for i in range(100)] # Crea la lista en memoria de numeros impares impares_gen = (2*i+1 for i in range(100)) #Itera sobre los numeros impares print(impares) print(type(impares)) print(impares_gen) print(type(impares_gen)) for i in impares_gen: print(i) time.sleep(1)
    Screenshot 2021-08-16 at 22.02.29.png
    Antonio Demarco Bonino

    Antonio Demarco Bonino

    student•
    hace 4 años

    ¡Qué buen tema! Claramente el saber no ocupa lugar y una vez estudiado tenemos tres obligaciones: practicar, practicar y practicar... Siempre practicar.

    Luis Alejandro Vera Hernandez

    Luis Alejandro Vera Hernandez

    student•
    hace 4 años

    Que alegria poder conocer este tema, simplifica mucho la sintaxis que la de un iterador

    Ventajas de los Generadores:

    • Es mas fácil de escribir que un iterador
    • Ahorra Tiempo y Memoria
    • Permite guardar secuencias infinitas
    Yeison Pachon Muñoz

    Yeison Pachon Muñoz

    student•
    hace 3 años

    Algún ejemplo real donde se utilicen los generator?

    Luis Kennedy Saavedra Fuentes

    Luis Kennedy Saavedra Fuentes

    student•
    hace 4 años

    Buenas noches. No me quedó muy claro. Generadores almacena o no? Al final dice que un generador puede almacenar secuencias, y antes dices que a diferencia de list comprehension, no almacena. O si me pueden aclarar un pcoo mas este punto por favor. Gracias.

      Nicolás Arias González

      Nicolás Arias González

      student•
      hace 4 años

      El generador almacena su estado interno, mas no almacena los datos como tal.

      Suponiendo que tienes un generador que te devuelve X + 1, donde X es el número de veces que has llamado al generador. Internamente él almacenará el valor de X, no tiene la necesidad de "recordar" cuales fueron los valores generados anteriormente.

      Por el contrario, cuando usas un list comprehension, te da como resultado una nueva lista con todos los valores que se generaron.

      El resultado de esto es que un generador requiere menos memoria para operar que un list comprehension, ya que el primero almacena mucha menos información a la vez.

      Cristian Collazos

      Cristian Collazos

      student•
      hace 4 años

      Un recurso que me sirvio bastante para entender a profundidad los generadores.

    Reinaldo Mendoza

    Reinaldo Mendoza

    student•
    hace 4 años

    Que cosa tan rara, nunca había visto ese yield, no se me ocurre por lo pronto una utilidad, pero seguro la debe tener, debe ser difícil acceder a una función que no sabes que va a retornar

    Mateo Echavarria

    Mateo Echavarria

    student•
    hace 4 años

    La principal diferencia entre List Comprehesion y Generator Expression además de los [ ] y ( ). Es que la List Comprehesion realiza todas las operaciones y luego de terminar muestra el resultado, mientras que el Generator Expression hace la operación solo si se le pide, y va una a una. ¿Es así?

    Angel Mejia

    Angel Mejia

    student•
    hace 4 años

    Los generadores ahorran memoria y tiempo de ejecución al obtener los elementos de la estructura (iterador) solo cuando se le solicite.

    Carlos Esteban Lara Gil

    Carlos Esteban Lara Gil

    student•
    hace 4 años

    #APUNTES DE LA CLASE :snake:

    Los GENERADORES son un "Sugar syntax" de los iteradores. Los generadores son funciones que guardan un estado.

    • Se usa yield el cual es como un return pero pausa la función hasta donde estaba el yield. Empieza desde donde se llamó el último yield, La función guarda un estado
    def my_gen(): """ Un ejemplo de generadores""" print('Hello world') n = 0 yield n print("hello heaven") n = 1 yield n print("hello hell") n = 2 yield n a = my_gen() print(next(a)) print(next(a)) print(next(a)) print(next(a)) StopIteration

    Cada vez que ejecuto next(a) el código ejecuta desde el yield donde está. Cuando se acaban los yield usamos el StopIteration

    Generator expression

    Trae un elemento a la vez cuándo se recorre

    my_list = [0,1,2,3,4,5] my_second_list = [x*2 for x in my_list] my_second_gen = (x*w for x in my_list)

Escuelas

  • Desarrollo Web
    • Fundamentos del Desarrollo Web Profesional
    • Diseño y Desarrollo Frontend
    • Desarrollo Frontend con JavaScript
    • Desarrollo Frontend con Vue.js
    • Desarrollo Frontend con Angular
    • Desarrollo Frontend con React.js
    • Desarrollo Backend con Node.js
    • Desarrollo Backend con Python
    • Desarrollo Backend con Java
    • Desarrollo Backend con PHP
    • Desarrollo Backend con Ruby
    • Bases de Datos para Web
    • Seguridad Web & API
    • Testing Automatizado y QA para Web
    • Arquitecturas Web Modernas y Escalabilidad
    • DevOps y Cloud para Desarrolladores Web
  • English Academy
    • Inglés Básico A1
    • Inglés Básico A2
    • Inglés Intermedio B1
    • Inglés Intermedio Alto B2
    • Inglés Avanzado C1
    • Inglés para Propósitos Específicos
    • Inglés de Negocios
  • Marketing Digital
    • Fundamentos de Marketing Digital
    • Marketing de Contenidos y Redacción Persuasiva
    • SEO y Posicionamiento Web
    • Social Media Marketing y Community Management
    • Publicidad Digital y Paid Media
    • Analítica Digital y Optimización (CRO)
    • Estrategia de Marketing y Growth
    • Marketing de Marca y Comunicación Estratégica
    • Marketing para E-commerce
    • Marketing B2B
    • Inteligencia Artificial Aplicada al Marketing
    • Automatización del Marketing
    • Marca Personal y Marketing Freelance
    • Ventas y Experiencia del Cliente
    • Creación de Contenido para Redes Sociales
  • Inteligencia Artificial y Data Science
    • Fundamentos de Data Science y AI
    • Análisis y Visualización de Datos
    • Machine Learning y Deep Learning
    • Data Engineer
    • Inteligencia Artificial para la Productividad
    • Desarrollo de Aplicaciones con IA
    • AI Software Engineer
  • Ciberseguridad
    • Fundamentos de Ciberseguridad
    • Hacking Ético y Pentesting (Red Team)
    • Análisis de Malware e Ingeniería Forense
    • Seguridad Defensiva y Cumplimiento (Blue Team)
    • Ciberseguridad Estratégica
  • Liderazgo y Habilidades Blandas
    • Fundamentos de Habilidades Profesionales
    • Liderazgo y Gestión de Equipos
    • Comunicación Avanzada y Oratoria
    • Negociación y Resolución de Conflictos
    • Inteligencia Emocional y Autogestión
    • Productividad y Herramientas Digitales
    • Gestión de Proyectos y Metodologías Ágiles
    • Desarrollo de Carrera y Marca Personal
    • Diversidad, Inclusión y Entorno Laboral Saludable
    • Filosofía y Estrategia para Líderes
  • Diseño de Producto y UX
    • Fundamentos de Diseño UX/UI
    • Investigación de Usuarios (UX Research)
    • Arquitectura de Información y Usabilidad
    • Diseño de Interfaces y Prototipado (UI Design)
    • Sistemas de Diseño y DesignOps
    • Redacción UX (UX Writing)
    • Creatividad e Innovación en Diseño
    • Diseño Accesible e Inclusivo
    • Diseño Asistido por Inteligencia Artificial
    • Gestión de Producto y Liderazgo en Diseño
    • Diseño de Interacciones Emergentes (VUI/VR)
    • Desarrollo Web para Diseñadores
    • Diseño y Prototipado No-Code
  • Contenido Audiovisual
    • Fundamentos de Producción Audiovisual
    • Producción de Video para Plataformas Digitales
    • Producción de Audio y Podcast
    • Fotografía y Diseño Gráfico para Contenido Digital
    • Motion Graphics y Animación
    • Contenido Interactivo y Realidad Aumentada
    • Estrategia, Marketing y Monetización de Contenidos
  • Desarrollo Móvil
    • Fundamentos de Desarrollo Móvil
    • Desarrollo Nativo Android con Kotlin
    • Desarrollo Nativo iOS con Swift
    • Desarrollo Multiplataforma con React Native
    • Desarrollo Multiplataforma con Flutter
    • Arquitectura y Patrones de Diseño Móvil
    • Integración de APIs y Persistencia Móvil
    • Testing y Despliegue en Móvil
    • Diseño UX/UI para Móviles
  • Diseño Gráfico y Arte Digital
    • Fundamentos del Diseño Gráfico y Digital
    • Diseño de Identidad Visual y Branding
    • Ilustración Digital y Arte Conceptual
    • Diseño Editorial y de Empaques
    • Motion Graphics y Animación 3D
    • Diseño Gráfico Asistido por Inteligencia Artificial
    • Creatividad e Innovación en Diseño
  • Programación
    • Fundamentos de Programación e Ingeniería de Software
    • Herramientas de IA para el trabajo
    • Matemáticas para Programación
    • Programación con Python
    • Programación con JavaScript
    • Programación con TypeScript
    • Programación Orientada a Objetos con Java
    • Desarrollo con C# y .NET
    • Programación con PHP
    • Programación con Go y Rust
    • Programación Móvil con Swift y Kotlin
    • Programación con C y C++
    • Administración Básica de Servidores Linux
  • Negocios
    • Fundamentos de Negocios y Emprendimiento
    • Estrategia y Crecimiento Empresarial
    • Finanzas Personales y Corporativas
    • Inversión en Mercados Financieros
    • Ventas, CRM y Experiencia del Cliente
    • Operaciones, Logística y E-commerce
    • Gestión de Proyectos y Metodologías Ágiles
    • Aspectos Legales y Cumplimiento
    • Habilidades Directivas y Crecimiento Profesional
    • Diversidad e Inclusión en el Entorno Laboral
    • Herramientas Digitales y Automatización para Negocios
  • Blockchain y Web3
    • Fundamentos de Blockchain y Web3
    • Desarrollo de Smart Contracts y dApps
    • Finanzas Descentralizadas (DeFi)
    • NFTs y Economía de Creadores
    • Seguridad Blockchain
    • Ecosistemas Blockchain Alternativos (No-EVM)
    • Producto, Marketing y Legal en Web3
  • Recursos Humanos
    • Fundamentos y Cultura Organizacional en RRHH
    • Atracción y Selección de Talento
    • Cultura y Employee Experience
    • Gestión y Desarrollo de Talento
    • Desarrollo y Evaluación de Liderazgo
    • Diversidad, Equidad e Inclusión
    • AI y Automatización en Recursos Humanos
    • Tecnología y Automatización en RRHH
  • Finanzas e Inversiones
    • Fundamentos de Finanzas Personales y Corporativas
    • Análisis y Valoración Financiera
    • Inversión y Mercados de Capitales
    • Finanzas Descentralizadas (DeFi) y Criptoactivos
    • Finanzas y Estrategia para Startups
    • Inteligencia Artificial Aplicada a Finanzas
    • Domina Excel
    • Financial Analyst
    • Conseguir trabajo en Finanzas e Inversiones
  • Startups
    • Fundamentos y Validación de Ideas
    • Estrategia de Negocio y Product-Market Fit
    • Desarrollo de Producto y Operaciones Lean
    • Finanzas, Legal y Fundraising
    • Marketing, Ventas y Growth para Startups
    • Cultura, Talento y Liderazgo
    • Finanzas y Operaciones en Ecommerce
    • Startups Web3 y Blockchain
    • Startups con Impacto Social
    • Expansión y Ecosistema Startup
  • Cloud Computing y DevOps
    • Fundamentos de Cloud y DevOps
    • Administración de Servidores Linux
    • Contenerización y Orquestación
    • Infraestructura como Código (IaC) y CI/CD
    • Amazon Web Services
    • Microsoft Azure
    • Serverless y Observabilidad
    • Certificaciones Cloud (Preparación)
    • Plataforma Cloud GCP

Platzi y comunidad

  • Platzi Business
  • Live Classes
  • Lanzamientos
  • Executive Program
  • Trabaja con nosotros
  • Podcast

Recursos

  • Manual de Marca

Soporte

  • Preguntas Frecuentes
  • Contáctanos

Legal

  • Términos y Condiciones
  • Privacidad
  • Tyc promociones
Reconocimientos
Reconocimientos
Logo reconocimientoTop 40 Mejores EdTech del mundo · 2024
Logo reconocimientoPrimera Startup Latina admitida en YC · 2014
Logo reconocimientoPrimera Startup EdTech · 2018
Logo reconocimientoCEO Ganador Medalla por la Educación T4 & HP · 2024
Logo reconocimientoCEO Mejor Emprendedor del año · 2024
De LATAM conpara el mundo
YoutubeInstagramLinkedInTikTokFacebookX (Twitter)Threads