One place for hosting & domains

      módulo

      Cómo usar el módulo pathlib para manipular las rutas de sistemas de archivos en Python 3


      El autor seleccionó el COVID-19 Relief Fund para que reciba una donación como parte del programa Write for DOnations.

      Introducción

      Python 3 incluye el módulo pathlib para manipular rutas de sistemas de archivos de forma agnóstica en cualquier sistema operativo. El módulo pathlib es similar al os.path, pero pathlib ofrece una interfaz de nivel más alto, y, a menudo, más conveniente, que os.path.

      Podemos identificar archivos en una computadora con rutas jerárquicas. Por ejemplo, podemos identificar el archivo wave.txt en una computadora con esta ruta: /Users/sammy/ocean/wave.txt. Cada sistema operativo tiene una manera ligeramente distinta de representar rutas. Windows puede representar la ruta al archivo wave.txt de la siguiente manera: C:Userssammyoceanwave.txt.

      El módulo pathlib le puede resultar útil si desea a crear o mover archivos en el sistema de archivos de su programa de Python, enumerar los archivos del sistema de archivos que coincidan con una extensión o un patrón determinado o crear rutas de archivos apropiadas para el sistema operativo basadas en colecciones de cadenas sin procesar. Si bien es posible usar otras herramientas (como el módulo os.path) para realizar muchas de estas tareas, el módulo pathlib le permite realizar estas operaciones con un alto grado de legibilidad y una cantidad de código mínima.

      En este tutorial, revisaremos algunas de las maneras de usar el módulo pathlib para representar y manipular las rutas de los sistemas de archivos.

      Requisitos previos

      Para sacar el máximo provecho de este tutorial, se recomienda tener cierta familiaridad con la programación en Python 3. Puede consultar estos tutoriales para obtener la información de fondo necesaria:

      Cómo crear instancias Path

      El módulo pathlib proporciona varias clases, pero una de las más importantes es la clase Path. Las instancias de la clase Path representan una ruta a un archivo o un directorio en el sistema de archivos de nuestra computadora.

      Por ejemplo, el siguiente código inicia una instancia Path que representa una parte de la ruta a un archivo wave.txt:

      from pathlib import Path
      
      wave = Path("ocean", "wave.txt")
      print(wave)
      

      Si ejecutamos este código, obtendremos un resultado como el siguiente:

      Output

      ocean/wave.txt

      from pathlib import Path permite que la clase Path esté disponible en nuestro programa. Luego, Path("ocean", "wave.txt") crea una instancia de Path nueva. El resultado muestra que Python ha añadido el separador / adecuado del sistema operativo entre los dos componentes de la ruta que le proporcionamos: "ocean" y "wave.txt".

      Nota: Sus resultados pueden diferir ligeramente de los que se muestran como ejemplo en este tutorial en función del sistema operativo que utilice. Si utiliza Windows, por ejemplo, su resultado para este primer ejemplo puede tener este aspecto: oceanwave.txt.

      Actualmente, el objeto Path asignado a la variable wave contiene una ruta relativa. En otras palabras, ocean/wave.txt puede existir en varias ubicaciones de nuestro sistema de archivos. Por ejemplo, puede estar presente en /Users/user_1/ocean/wave.txt o /Users/user_2/research/ocean/wave.txt, pero no especificamos exactamente a cuál nos estamos refiriendo. Por el contrario, una ruta absoluta se refiere inequívocamente a una ubicación en el sistema de archivos.

      Puede usar Path.home() para obtener la ruta absoluta al directorio principal del usuario actual:

      home = Path.home()
      wave_absolute = Path(home, "ocean", "wave.txt")
      print(home)
      print(wave_absolute)
      

      Si ejecutamos este código, obtendremos un resultado similar al siguiente:

      Output

      /Users/sammy /Users/sammy/ocean/wave.txt

      Nota: Como se mencionó anteriormente, su resultado variará dependiendo de su sistema operativo. Por supuesto, su directorio principal también será distinto de /Users/sammy.

      Path.home() devuelve una instancia Path con una ruta absoluta al directorio principal del usuario actual. Luego, pasamos esta instancia de Path y las cadenas "ocean" y "wave.txt" a otro constructor de Path para crear una ruta absoluta al archivo wave.txt. El resultado indica que la primera línea es el directorio principal y la segunda, el directorio principal más ocean/wave.txt.

      Este ejemplo también ilustra una característica importante de la clase Path: el constructor Path acepta tanto cadenas como objetos preexistentes de Path.

      Analicemos con mayor detalle cómo es que el constructor Path admite tanto cadenas como de objetos de Path:

      shark = Path(Path.home(), "ocean", "animals", Path("fish", "shark.txt"))
      print(shark)
      

      Si ejecutamos este código de Python, obtendremos un resultado similar al siguiente:

      Output

      /Users/sammy/ocean/animals/fish/shark.txt

      shark es un Path a un archivo que construimos usando tanto objetos Path (Path.home() y Path("fish", "shark.txt")) como cadenas ("ocean" y "animals"). El constructor Path gestiona de forma inteligente ambos tipos de objetos y los une de forma correcta usando el separador correspondiente del sistema operativo, en este caso: /.

      Acceder a los atributos de los archivos

      Ahora que hemos aprendido a crear instancias de Path, vamos a repasar cómo puede usar esas instancias para acceder a información sobre un archivo.

      Podemos usar los atributos name y suffix para acceder a los nombres y los sufijos de archivos:

      wave = Path("ocean", "wave.txt")
      print(wave)
      print(wave.name)
      print(wave.suffix)
      

      Al ejecutar este código, obtendremos un resultado similar al siguiente:

      Output

      /Users/sammy/ocean/wave.txt wave.txt .txt

      Este resultado indica que el nombre del archivo al final de nuestra ruta es wave.txt y el sufijo de ese archivo es .txt.

      Las instancias de Path también ofrecen la función with_name, que le permite crear de forma sencilla un objeto Path nuevo con un nombre distinto:

      wave = Path("ocean", "wave.txt")
      tides = wave.with_name("tides.txt")
      print(wave)
      print(tides)
      

      Si ejecutamos este código, obtendremos un resultado similar al siguiente:

      ocean/wave.txt
      ocean/tides.txt
      

      El código, primero, construye una instancia Path que apunta a un archivo llamado wave.txt. Luego, invoca el método with_name en wave para devolver una segunda instancia Path que apunta a un archivo nuevo denominado tides.txt. La parte del directorio ocean/ de la ruta permanece intacta, por lo tanto, la ruta final queda establecida como ocean/tides.txt

      Acceder a antecesores

      A veces, resulta útil acceder a directorios que contienen una ruta determinada. Consideremos un ejemplo:

      shark = Path("ocean", "animals", "fish", "shark.txt")
      print(shark)
      print(shark.parent)
      

      Si ejecutamos este código, obtendremos un resultado similar al siguiente:

      Output

      ocean/animals/fish/shark.txt ocean/animals/fish

      El atributo parent en una instancia de Path devuelve el antecesor más inmediato de una ruta de archivos determinada. En este caso, devuelve el directorio que contiene el archivo shark.txt: ocean/animals/fish.

      Podemos acceder al atributo parent varias veces seguidas para recorrer el árbol de ancestros de un archivo determinado:

      shark = Path("ocean", "animals", "fish", "shark.txt")
      print(shark)
      print(shark.parent.parent)
      

      Si ejecutamos este código, obtendremos el siguiente resultado:

      Output

      ocean/animals/fish/shark.txt ocean/animals

      El resultado es similar al anterior, pero, ahora, hemos llegado a un nivel más alto al acceder a .parent por segunda vez. El directorio ocean/animals se encuentra dos directorios por encima de shark.txt.

      Usar Glob para enumerar archivos

      También es posible usar la clase Path para enumerar archivos usando el método glob.

      Imaginemos que tenemos una estructura de directorios similar a la siguiente:

      └── ocean
          ├── animals
          │   └── fish
          │       └── shark.txt
          ├── tides.txt
          └── wave.txt
      

      Un directorio ocean que contiene los archivos tides.txt y wave.txt. Tenemos un archivo denominado shark.txt anidado en el directorio ocean, un directorio animals y otro fish: ocean/animals/fish.

      Para enumerar todos los archivos .txt del directorio ocean, podríamos escribir lo siguiente:

      for txt_path in Path("ocean").glob("*.txt"):
          print(txt_path)
      

      Este código tendría un resultado similar al siguiente:

      Output

      ocean/wave.txt ocean/tides.txt

      El patrón glob __"*.txt" busca todos los archivos que terminan en .txt. Como el código del ejemplo ejecuta ese glob en el directorio ocean, devuelve los dos archivos .txt del directorio ocean: wave.txt y tides.txt.

      Nota: Para duplicar los resultados que se muestran en este ejemplo, copie la estructura de directorios que se ilustra aquí en su computadora.

      También podemos usar el método glob de manera recursiva. Para enumerar todos los archivos .txt del directorio ocean y todos sus subdirectorios, podemos escribir lo siguiente:

      for txt_path in Path("ocean").glob("**/*.txt"):
          print(txt_path)
      

      Al ejecutar este código, obtendríamos un resultado similar al siguiente:

      Output

      ocean/wave.txt ocean/tides.txt ocean/animals/fish/shark.txt

      La sección ** del patrón glob coincidirá con este directorio y todos sus subdirectorios de manera recursiva. Por tanto, no solo tenemos los archivos wave.txt y tides.txt en el resultado, sino que también recibimos el archivo shark.txt que estaba anidado en ocean/animals/fish.

      Calcular rutas relativas

      Podemos usar el método Path.relative_to para calcular rutas relacionadas entre sí. El método relative_to es útil cuando, por ejemplo, se desea recuperar una porción de una ruta de archivos larga.

      Analice el siguiente código:

      shark = Path("ocean", "animals", "fish", "shark.txt")
      below_ocean = shark.relative_to(Path("ocean"))
      below_animals = shark.relative_to(Path("ocean", "animals"))
      print(shark)
      print(below_ocean)
      print(below_animals)
      

      Si ejecutamos este código, obtendremos un resultado similar al siguiente:

      Output

      ocean/animals/fish/shark.txt animals/fish/shark.txt fish/shark.txt

      El método relative_to devuelve un nuevo objeto Path relacionado con el argumento determinado. En nuestro ejemplo, calculamos el Path a shark.txt en relación con el directorio ocean y, luego, en relación con los directorios ocean y animals.

      Si relative_to no puede calcular una respuesta porque le indicamos una ruta no relacionada, presenta un ValueError:

      shark = Path("ocean", "animals", "fish", "shark.txt")
      shark.relative_to(Path("unrelated", "path"))
      

      Obtendremos una excepción ValueError generada a partir de este código que será similar a la siguiente:

      Output

      Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/Python3.8/pathlib.py", line 899, in relative_to raise ValueError("{!r} does not start with {!r}" ValueError: 'ocean/animals/fish/shark.txt' does not start with 'unrelated/path'

      unrelated/path no forma parte de ocean/animals/fish/shark.txt, por lo tanto, Python no puede calcular una ruta relativa.

      Conclusión

      El módulo pathlib es un componente importante de la biblioteca estándar de Python que nos permite manipular rutas de sistemas de archivos de forma rápida en cualquier sistema operativo. En este tutorial, ha aprendido a usar algunas de las herramientas clave de pathlib para acceder a los atributos de archivos, enumerar archivos con patrones glob y desplazarse por archivos y directorios principales.

      El módulo pathlib expone clases y utilidades adicionales que no abarcamos en este tutorial. Ahora que tiene una referencia, puede usar la documentación del módulo pathlib para obtener más información sobre otras clases y utilidades disponibles.

      Si está interesado en utilizar otras bibliotecas de Python, consulte los siguientes tutoriales:



      Source link

      Como usar o módulo pathlib para manipular os caminhos de sistema de arquivos no Python 3


      O autor selecionou a COVID-19 Relief Fund​​​​​ para receber uma doação como parte do programa Write for DOnations.

      Introdução

      O Python 3 inclui o módulo pathlib para manipular caminhos de sistema de arquivos de maneira independente, seja qual for o sistema operacional. O pathlib é semelhante ao módulo os.path, mas o pathlib oferece um nível mais elevado — e muitas vezes mais conveniente — de interface do que o os.path.

      Podemos identificar arquivos em um computador com caminhos hierárquicos. Por exemplo, podemos identificar o arquivo wave.txt em um computador com este caminho: /Users/sammy/ocean/wave.txt. Os sistemas operacionais representam caminhos de maneira ligeiramente diferente. O Windows pode representar o caminho para o arquivo wave.txt como C:Userssammyoceanwave.txt.

      O módulo pathlib pode ser útil para você se em seu programa Python você estiver criando ou movendo arquivos no sistema de arquivos, listando arquivos no sistema de arquivos em que todos correspondam a uma dada extensão ou padrão, ou criando caminhos de arquivo apropriados ao sistema operacional baseados em coleções de strings brutas. Embora seja possível usar outras ferramentas (como o módulo os.path) para realizar muitas dessas tarefas, o módulo pathlib permite que você execute essas operações com um alto grau de legibilidade e uma quantidade mínima de código.

      Neste tutorial, vamos revisar algumas das maneiras de usar o módulo pathlib para representar e manipular os caminhos de sistema de arquivos.

      Pré-requisitos

      Para tirar o máximo proveito deste tutorial, é recomendado ter alguma familiaridade com programação em Python 3. Você pode revisar esses tutoriais para as informações básicas necessárias:

      Construindo instâncias Path

      O módulo pathlib oferece várias classes, mas uma das mais importantes é a classe Path. As instâncias da classe Path representam um caminho para um arquivo ou diretório no sistema de arquivos do nosso computador.

      Por exemplo, o código a seguir cria uma instância Path que representa parte do caminho para um arquivo wave.txt:

      from pathlib import Path
      
      wave = Path("ocean", "wave.txt")
      print(wave)
      

      Se executarmos esse código, receberemos um resultado como o seguinte:

      Output

      ocean/wave.txt

      from pathlib import Path torna a classe Path disponível para nosso programa. Em seguida, Path("ocean", "wave.txt") cria uma nova instância do Path. Imprimir o resultado mostra que o Python adicionou o separador de sistema operacional / apropriado entre os dois componentes do caminho que demos a ele: "ocean" e "wave.txt".

      Nota: dependendo do seu sistema operacional, o resultado pode variar ligeiramente dos resultados de exemplo exibidos neste tutorial. Se estiver utilizando o Windows, por exemplo, seu resultado para este primeiro exemplo se pareceria com oceanwave.txt.

      Agora, o objeto Path atribuído à variável wave contém um caminho relativo. Em outras palavras, ocean/wave.txt pode existir em vários lugares em nosso sistema de arquivos. Para exemplificar, ele pode existir em /Users/user_1/ocean/wave.txt ou /Users/user_2/research/ocean/wave.txt, mas não especificamos exatamente a qual deles estamos nos referindo. Um caminho absoluto, por outro lado, refere-se sem sombra de dúvidas a uma localização específica no sistema de arquivos.

      Use o Path.home() para obter o caminho absoluto para o diretório home do usuário atual:

      home = Path.home()
      wave_absolute = Path(home, "ocean", "wave.txt")
      print(home)
      print(wave_absolute)
      

      Se executarmos esse código, receberemos um resultado parecido com o seguinte:

      Output

      /Users/sammy /Users/sammy/ocean/wave.txt

      Nota: como mencionado anteriormente, seu resultado irá variar dependendo do seu sistema operacional. Seu diretório home, por consequência, também será diferente de /Users/sammy.

      Path.home() retorna uma instância Path com um caminho absoluto para o diretório home do usuário atual. Em seguida, passamos essa instância Path e as strings "ocean" e "wave.txt" para outro construtor Path de forma a criar um caminho absoluto para o arquivo wave.txt. O resultado mostra que a primeira linha é o diretório home, e a segunda linha é o diretório home mais ocean/wave.txt.

      Este exemplo também ilustra uma característica importante da classe Path: o construtor Path aceita tanto strings quanto objetos Path pré-existentes.

      Vamos analisar as strings e objetos Path no construtor Path um pouco mais de perto:

      shark = Path(Path.home(), "ocean", "animals", Path("fish", "shark.txt"))
      print(shark)
      

      Se executarmos esse código Python, receberemos um resultado semelhante ao seguinte:

      Output

      /Users/sammy/ocean/animals/fish/shark.txt

      shark é um Path para um arquivo que construímos usando dois objetos Path (Path.home() e Path("fish", "shark.txt")) e as strings ("ocean" e "animals"). O construtor Path lida com os dois tipos de objetos de maneira inteligente e une-os corretamente usando o separador de sistema operacional adequado, neste caso, /.

      Acessando os atributos de arquivo

      Agora que aprendemos como construir instâncias Path, vamos analisar como você pode usar essas instâncias para acessar informações sobre um arquivo.

      Podemos usar os atributos name e suffix para acessar os nomes e sufixos dos arquivos:

      wave = Path("ocean", "wave.txt")
      print(wave)
      print(wave.name)
      print(wave.suffix)
      

      Ao executar este código, receberemos um resultado semelhante ao seguinte:

      Output

      /Users/sammy/ocean/wave.txt wave.txt .txt

      Este resultado mostra que o nome do arquivo no final do nosso caminho é wave.txt e o sufixo desse arquivo é .txt.

      As instâncias Path também oferecem a função with_name que permite criar rapidamente um novo objeto Path com um nome diferente:

      wave = Path("ocean", "wave.txt")
      tides = wave.with_name("tides.txt")
      print(wave)
      print(tides)
      

      Se executarmos o código acima, receberemos um resultado como o seguinte:

      ocean/wave.txt
      ocean/tides.txt
      

      Primeiro, o código constrói uma instância Path que aponta para um arquivo chamado wave.txt. Em seguida, chamamos o método with_name em wave para retornar uma segunda instância Path que aponta para um novo arquivo chamado tides.txt. A porção de diretório ocean/ do caminho permanece inalterada, deixando o caminho final como sendo ocean/tides.txt

      Acessando diretórios ancestrais

      Às vezes, é útil acessar diretórios que contêm um dado caminho. Vamos considerar um exemplo:

      shark = Path("ocean", "animals", "fish", "shark.txt")
      print(shark)
      print(shark.parent)
      

      Se executarmos esse código, receberemos um resultado parecido com o seguinte:

      Output

      ocean/animals/fish/shark.txt ocean/animals/fish

      O atributo parent em uma instância Path retorna o ancestral mais próximo de um determinado caminho de arquivo. Neste caso, ele retorna o diretório que contém o arquivo shark.txt: ocean/animals/fish.

      Podemos acessar o atributo parent várias vezes seguidas para percorrer a árvore de ancestralidade de um dado arquivo:

      shark = Path("ocean", "animals", "fish", "shark.txt")
      print(shark)
      print(shark.parent.parent)
      

      Se executarmos esse código, receberemos o seguinte resultado:

      Output

      ocean/animals/fish/shark.txt ocean/animals

      O resultado é semelhante ao resultado anterior, mas agora percorremos mais um nível acessando .parent uma segunda vez. Dois diretórios acima de shark.txt, você encontrará o diretório ocean/animals.

      Usando Glob para listar arquivos

      Também é possível usar a classe Path para listar arquivos usando o método glob.

      Suponha que tivéssemos uma estrutura de diretório que se parecia com esta:

      └── ocean
          ├── animals
          │   └── fish
          │       └── shark.txt
          ├── tides.txt
          └── wave.txt
      

      Um diretório ocean contém os arquivos tides.txt e wave.txt. Temos um arquivo chamado shark.txt contido no diretório ocean, um diretório animals e um diretório fish: ocean/animals/fish.

      Para listar todos os arquivos .txt no diretório ocean, podemos utilizar:

      for txt_path in Path("ocean").glob("*.txt"):
          print(txt_path)
      

      Esse código produziria um resultado como este:

      Output

      ocean/wave.txt ocean/tides.txt

      O padrão glob "*.txt" encontra todos os arquivos terminados em .txt. Como a amostra de código executa esse glob no diretório ocean, ela retorna os dois arquivos .txt no diretório ocean: wave.txt e tides.txt.

      Nota: se você quiser replicar os resultados mostrados neste exemplo, você precisará imitar a estrutura de diretórios aqui ilustrada em seu computador.

      Também podemos usar o método glob recursivamente. Para listar todos os arquivos .txt no diretório ocean e todos os seus subdiretórios, podemos utilizar:

      for txt_path in Path("ocean").glob("**/*.txt"):
          print(txt_path)
      

      Se executarmos esse código, receberemos um resultado como o seguinte:

      Output

      ocean/wave.txt ocean/tides.txt ocean/animals/fish/shark.txt

      A parte ** do padrão glob irá corresponder a esse diretório e todos os diretórios abaixo dele, recursivamente. Dessa forma, não só temos os arquivos wave.txt e tides.txt no resultado, mas também recebemos o arquivo shark.txt que estava contido em ocean/animals/fish.

      Computando caminhos relativos

      Podemos usar o método Path.relative_to para computar caminhos em relação uns aos outros. O método relative_to é útil quando, por exemplo, você quiser recuperar parte de um caminho de arquivo longo.

      Considere o código a seguir:

      shark = Path("ocean", "animals", "fish", "shark.txt")
      below_ocean = shark.relative_to(Path("ocean"))
      below_animals = shark.relative_to(Path("ocean", "animals"))
      print(shark)
      print(below_ocean)
      print(below_animals)
      

      Se executarmos o código acima, receberemos um resultado como o seguinte:

      Output

      ocean/animals/fish/shark.txt animals/fish/shark.txt fish/shark.txt

      O método relative_to retorna um novo objeto Path relativo ao argumento dado. Em nosso exemplo, computamos o Path para o shark.txt relativo ao diretório ocean, e então relativo tanto ao diretório ocean quanto ao diretório animals.

      Se relative_to não puder computar uma resposta porque lhe fornecemos um caminho não relacionado, ele gera um ValueError:

      shark = Path("ocean", "animals", "fish", "shark.txt")
      shark.relative_to(Path("unrelated", "path"))
      

      Receberemos uma exceção ValueError gerada a partir deste código que será algo parecido com isto:

      Output

      Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/Python3.8/pathlib.py", line 899, in relative_to raise ValueError("{!r} does not start with {!r}" ValueError: 'ocean/animals/fish/shark.txt' does not start with 'unrelated/path'

      unrelated/path não faz parte de ocean/animals/fish/shark.txt, então não existe nenhuma maneira para o Python computar um caminho relativo.

      Conclusão

      O módulo pathlib é uma parte poderosa da Biblioteca Padrão do Python que nos permite manipular caminhos do sistema de arquivos rapidamente em qualquer sistema operacional. Neste tutorial, aprendemos a usar alguns utilitários chave do pathlib para acessar atributos de arquivo, listar arquivos com padrões glob e percorrer arquivos e diretórios pais.

      O módulo pathlib também oferece classes e utilitários adicionais que não abordamos neste tutorial. Agora que você tem um conhecimento base, use a documentação do módulo pathlib para aprender mais sobre outras classes e utilitários disponíveis.

      Se estiver interessado em usar outras bibliotecas do Python, confira os seguintes tutoriais:



      Source link

      Cómo usar el módulo collections en Python 3


      El autor seleccionó el COVID-19 Relief Fund para que reciba una donación como parte del programa Write for DOnations.

      Introducción

      Python 3 tiene varias estructuras de datos integradas, incluyendo tuplas, diccionarios y listas. Las estructuras de datos nos proporcionan una forma de organizar y almacenar datos. El módulo collections nos ayuda a completar y manipular las estructuras de datos de forma eficiente.

      En este tutorial, veremos tres clases del módulo collections para ayudarle a trabajar con tuples, diccionarios y listas. Usaremos namedtuples para crear tuplas con campos con nombre, defaultdict para agrupar de forma concisa la información en diccionarios, y deque para añadir elementos de forma eficiente a cualquier lado de un objeto lista.

      Para este tutorial, trabajaremos principalmente con un inventario de peces que necesitamos modificar a medida que se añaden o retiran peces a un acuario ficticio.

      Requisitos previos

      Para sacar el máximo partido a este tutorial, se recomienda que esté algo familiarizado con los tipos de datos tupla, diccionario y lista, con su sintaxis y con cómo recuperar datos desde ellos. Puede revisar estos tutoriales para encontrar la información básica necesaria:

      Añadir campos con nombre a las tuplas

      Las tuplas de Python son secuencias de elementos ordenadas de forma inmutable o inalterable. Las tuplas se utilizan frecuentemente para representar datos en columnas; por ejemplo, líneas de un archivo CSV o filas de una base de datos SQL. Un acuario puede mantener un seguimiento de su inventario de peces como una serie de tuplas.

      Una tupla de peces individual:

      ("Sammy", "shark", "tank-a")
      

      Esta tupla está compuesta por tres elementos de cadena.

      Aunque es útil en cierta forma, esta tupla no indica claramente qué representa cada uno de sus campos. En realidad, el elemento 0 es un nombre, el elemento 1 es una especie y el elemento 2 es el depósito.

      Explicación de los campos de la tupla de peces:

      nombre especie tanque
      Sammy tiburón tanque-a

      Esta tabla deja claro que cada uno de los tres elementos de la tupla tiene un significado claro.

      namedtuple del módulo collections le permite añadir nombres explícitos a cada elemento de una tupla para hacer que estos significados sean claros en su programa Python.

      Vamos a usar namedtuple para generar una clase que claramente denomine a cada elemento de la tupla de peces:

      from collections import namedtuple
      
      Fish = namedtuple("Fish", ["name", "species", "tank"])
      

      from collections import namedtuple proporciona a su programa Python acceso a la función de fábrica namedtuple. La invocación de la función namedtuple() devuelve una clase que está vinculada al nombre Fish. La función namedtuple() tiene dos argumentos: el nombre deseado de nuestra nueva clase "Fish" y una lista de elementos denominados ["name", "species", "tank"].

      Podemos usar la clase Fish para representar la tupla de peces anterior:

      sammy = Fish("Sammy", "shark", "tank-a")
      
      print(sammy)
      

      Si ejecuta este código, verá el siguiente resultado:

      Output

      Fish(name="Sammy", species="shark", tank='tank-a')

      sammy se instancia usando la clase Fish. sammy es una tupla con tres elementos claramente nombrados.

      Se puede acceder a los campos de sammy por su nombre o con un índice de tupla tradicional:

      print(sammy.species)
      print(sammy[1])
      

      Si ejecutamos estas dos invocaciones print, veremos el siguiente resultado:

      Output

      shark shark

      Acceder a .species devuelve el mismo valor que acceder al segundo elemento de sammy usando [1]​​​.

      Usar namedtuple desde el módulo collections hace que su programa sea más legible al tiempo que mantiene las propiedades importantes de una tupla (que son inmutables y están ordenadas).

      Además, la función de fábrica namedtuple añade varios métodos adicionales para las instancias de Fish.

      Utilice ._asdict() para convertir una instancia en un diccionario:

      print(sammy._asdict())
      

      Si ejecutamos print, verá un resultado como el siguiente:

      Output

      {'name': 'Sammy', 'species': 'shark', 'tank': 'tank-a'}

      Invocar .asdict() en sammy devuelve una asignación de diccionario de cada uno de los tres nombres de campo con sus correspondientes valores.

      Las versiones de Python anteriores a 3.8 pueden mostrar esta línea de forma ligeramente diferente. Es posible, por ejemplo, que vea OrderedDict en vez del diccionario simple mostrado aquí.

      Nota: En Python, los métodos con guiones bajos precedentes se consideran, normalmente, “privados”. Los métodos adicionales proporcionados por namedtuple (por ejemplo, _asdict(), ._make(), ._replace(), etc.), sin embargo, son públicos.

      Recoger datos en un diccionario

      A menudo es útil recopilar datos en los diccionarios Python. defaultdict del módulo collections puede ayudarnos a ensamblar información en diccionarios de forma rápida y concisa.

      defaultdict nunca plantea un KeyError. Si no está presente una clave, defaultdict solo inserta y devuelve un valor de marcador de posición:

      from collections import defaultdict
      
      my_defaultdict = defaultdict(list)
      
      print(my_defaultdict["missing"])
      

      Si ejecutamos este código, veremos un resultado como el siguiente:

      Output

      []

      defaultdict inserta y devuelve un valor de marcador de posición en vez de lanzar un KeyError. En este caso, especificamos el valor de marcador de posición como una lista.

      Los diccionarios regulares, por el contrario, lanzarán un KeyError sobre las claves que faltan:

      my_regular_dict = {}
      
      my_regular_dict["missing"]
      

      Si ejecutamos este código, veremos un resultado como el siguiente:

      Output

      Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'missing'

      El diccionario regular my_regular_dict plantea un KeyError cuando intentamos acceder a una clave que no está presente.

      defaultdict se comporta de forma diferente a un diccionario regular. En vez de plantear un KeyError sobre una clave que falta, defaultdict invoca el valor de marcador de posición sin argumentos para crear un nuevo objeto. En este caso list() para crear una lista vacía.

      Continuando con nuestro ejemplo de acuario ficticio, digamos que tenemos una lista de tuplas de peces que representan el inventario de un acuario:

      fish_inventory = [
          ("Sammy", "shark", "tank-a"),
          ("Jamie", "cuttlefish", "tank-b"),
          ("Mary", "squid", "tank-a"),
      ]
      

      Existen tres peces en el acuario; sus nombres, especies y tanque se anotan en estas tres tuplas.

      Nuestro objetivo es organizar nuestro inventario por tanque; queremos conocer la lista de peces presentes en cada tanque. En otras palabras, queremos un diccionario que asigne "tank-a" a ["Jamie", "Mary"] y "tank-b" a ["Jamie"].

      Podemos usar defaultdict para agrupar los peces por tanque:

      from collections import defaultdict
      
      fish_inventory = [
          ("Sammy", "shark", "tank-a"),
          ("Jamie", "cuttlefish", "tank-b"),
          ("Mary", "squid", "tank-a"),
      ]
      fish_names_by_tank = defaultdict(list)
      for name, species, tank in fish_inventory:
          fish_names_by_tank[tank].append(name)
      
      print(fish_names_by_tank)
      

      Cuando ejecutemos este código, veremos el siguiente resultado:

      Output

      defaultdict(<class 'list'>, {'tank-a': ['Sammy', 'Mary'], 'tank-b': ['Jamie']})

      fish_names_by_tank se declara como un defaultdict que va por defecto a insertar list() en vez de lanzar un KeyError. Ya que esto garantiza que cada clave en fish_names_by_tank apuntará a una lista, podemos invocar libremente .append() para añadir nombres a la lista de cada tanque.

      defaultdict le ayuda aquí porque reduce la probabilidad de KeyErrors inesperados. Reducir los KeyErrors inesperados significa que su programa puede escribirse de forma más clara y con menos líneas. Más concretamente, el idioma defaultdict le permite evitar instanciar manualmente una lista vacía para cada tanque.

      Sin defaultdict, el cuerpo de bucle for podría haber tenido un aspecto más similar a este:

      More Verbose Example Without defaultdict

      ...
      
      fish_names_by_tank = {}
      for name, species, tank in fish_inventory:
          if tank not in fish_names_by_tank:
            fish_names_by_tank[tank] = []
          fish_names_by_tank[tank].append(name)
      

      Usar simplemente un diccionario regular (en vez de un defaultdict) significa que el cuerpo de bucle for siempre tiene que comprobar la existencia de tank dado en fish_names_by_tank. Solo tras haber verificado que tank ya está presente en fish_names_by_tank, o que ha sido inicializado con un [], podremos anexar el nombre del pez.

      defaultdict puede ayudar a reducir el código de plantilla cuando se completan diccionarios, porque nunca plantea un KeyError.

      Usar deque para añadir elementos de forma eficiente a cada lado de una colección

      Las listas de Python son secuencias de elementos ordenadas mutables, o alterables. Python puede anexar a listas en tiempo constante (la longitud de la lista no tiene efecto sobre el tiempo en que se tarda en anexar), pero insertar al principio de una lista puede ser más lento (el tiempo que tarda aumenta a medida que la lista aumenta).

      En términos de la notación Big O, anexar a una lista es una operación O(1) de tiempo constante. Insertar al principio de una lista, por el contrario, es más lento con el rendimiento de O(n).

      Nota: Los ingenieros de software a menudo miden el rendimiento de los procedimientos usando algo llamado la notación “Big O”. Cuando el tamaño de una entrada no tiene efecto sobre el tiempo que se tarda en realizar un procedimiento, se dice que se ejecuta en tiempo constante u O(1) (“Big O de 1”) Como ha aprendido antes, Python puede anexar a listas con un rendimiento de tiempo constante, conocido como O(1).

      A veces, el tamaño de una entrada afecta directamente a la cantidad de tiempo que se tarda en ejecutar un procedimiento. Insertar al principio de una lista Python, por ejemplo, es más lento cuantos más elementos haya en la lista. La notación Big O utiliza la letra n para representar el tamaño de la entrada. Esto significa que añadir elementos al principio de una lista Python se ejecuta en “tiempo lineal” u O(n) (“Big O de n”).

      En general, los procedimientos O(1) son más rápidos que los procedimientos O(n).

      Podemos insertar al principio de una lista Python:

      favorite_fish_list = ["Sammy", "Jamie", "Mary"]
      
      # O(n) performance
      favorite_fish_list.insert(0, "Alice")
      
      print(favorite_fish_list)
      

      Si ejecutamos lo siguiente, veremos un resultado como el siguiente:

      Output

      ['Alice', 'Sammy', 'Jamie', 'Mary']

      El método .insert(index, object) en la lista nos permite insertar "Alice" al principio de favorite_fish_list. Notablemente, sin embargo, insertar al principio de una lista tiene un rendimiento O(n). A medida que la longitud de favorite_fish_list aumenta, el tiempo para insertar un pez al principio de la lista aumentará proporcionalmente y tardará cada vez más.

      deque (pronunciado “deck”) del módulo collections es un objeto tipo listado que nos permite insertar elementos al principio o al final de una secuencia con un rendimiento de tiempo constante O(1).

      Insertar un elemento al principio de un deque:

      from collections import deque
      
      favorite_fish_deque = deque(["Sammy", "Jamie", "Mary"])
      
      # O(1) performance
      favorite_fish_deque.appendleft("Alice")
      
      print(favorite_fish_deque)
      

      Al ejecutar este código, veremos el siguiente resultado:

      Output

      deque(['Alice', 'Sammy', 'Jamie', 'Mary'])

      Podemos instanciar un deque usando una colección de elementos preexistente, en este caso una lista de nombres de tres peces favoritos. Invocar el método appendleft de favorite_fish_deque nos permite insertar un elemento al principio de nuestra colección con un rendimiento O(1). El rendimiento O(1) significa que el tiempo que se requiere para añadir un elemento al principio de favorite_fish_deque no aumentará incluso si favorite_fish_deque tiene miles o millones de elementos.

      Nota: Aunque deque añade entradas al principio de una secuencia de forma más eficiente que una lista, deque no realiza todas sus operaciones de forma más eficiente que una lista. Por ejemplo, acceder a un elemento aleatorio en un deque tiene un rendimiento O(n), pero acceder a un elemento aleatorio en una lista tiene un rendimiento O(1). Utilice deque cuando sea importante insertar o eliminar elementos de cualquier lado de su colección rápidamente. Podrá ver una comparativa completa del rendimiento de tiempo en la wiki de Python.

      Conclusión

      El módulo collections es una parte potente de la biblioteca estándar de Python que le permite trabajar con datos de forma concisa y eficiente. Este tutorial ha cubierto tres de las clases proporcionadas por el módulo collections incluyendo namedtuple, defaultdict y deque.

      Desde aquí, puede usar la documentación del módulo collectionpara aprender más sobre otras clases y utilidades disponibles. Para obtener más información sobre Python en general, puede leer nuestra serie de tutoriales Cómo codificar en Python 3.



      Source link