Получение абсолютных путей

В предыдущем разделе функция glob.glob() возвращала список относительных путей. В первом примере пути имели вид 'examples\feed.xml', а во втором относительные пути были даже короче, например, 'romantest1.py'. Пока вы остаётесь в текущем рабочем каталоге, по этим относительным путям можно будет открывать файлы или получать их метаданные. Но если вы захотите получить абсолютный путь — то есть тот, который включает все имена каталогов до корневого или до буквы диска, вам понадобится функция os.path.realpath().

>>> import os
>>> print(os.getcwd())
c:\Users\pilgrim\diveintopython3\examples
>>> print(os.path.realpath('feed.xml'))

c:\Users\pilgrim\diveintopython3\examples\feed.xml

Генераторы списков

В генераторах списков можно использовать любые выражения Python.

С помощью генераторов списков можно легко отобразить один список в другой, применив некоторую функцию к каждому элементу.

>>> a_list = [1, 9, 8, 4] >>> [elem * 2 for elem in a_list] [2, 18, 16, 8] [1]
>>> a_list [1, 9, 8, 4] [2]
>>> a_list = [elem * 2 for elem in a_list] >>> a_list [2, 18, 16, 8] [3]
  1. ↑ Чтобы понять, что здесь происходит, прочитайте генератор справа налево. a_list — отображаемый список. Python последовательно перебирает элементы списка a_list, временно присваивая значение каждого элемента переменной elem. Затем применяет функцию elem * 2 и добавляет результат в возвращаемый список.
  2. ↑ Генератор создаёт новый список, не изменяя исходный.
  3. ↑ Можно присвоить результат работы генератора списка отображаемой переменной. Python создаст новый список в памяти и, когда результат работы генератора будет получен, присвоит его исходной переменной.

В генераторах списков можно использовать любые выражения Python, включая функции модуля os, применяемые для работы с файлами и каталогами.

>>> import os, glob >>> glob.glob('*.xml') ['feed-broken.xml', 'feed-ns0.xml', 'feed.xml'] [1]
>>> [os.path.realpath(f) for f in glob.glob('*.xml')] ['c:\\Users\\pilgrim\\diveintopython3\\examples\\feed-broken.xml', 'c:\\Users\\pilgrim\\diveintopython3\\examples\\feed-ns0.xml', 'c:\\Users\\pilgrim\\diveintopython3\\examples\\feed.xml'] [2]
  1. ↑ Это выражение возвращает список всех .xml-файлов в текущем рабочем каталоге.
  2. ↑ Этот генератор принимает список всех .xml-файлов и преобразует его в список полных путей.

При генерировании списков можно также фильтровать элементы, чтобы отбросить некоторые значения.

>>> import os, glob
>>> [f for f in glob.glob('*.py') if os.stat(f).st_size > 6000] ['pluraltest6.py', 'romantest10.py', 'romantest6.py', 'romantest7.py', 'romantest8.py', 'romantest9.py'] [1]
  1. ↑ Чтобы профильтровать список, добавьте оператор if в конце генератора списка. Выражение, стоящее после оператора if, будет вычислено для каждого элемента списка. Если это выражение будет истинно, данный элемент будет обработан и включён в генерируемый список. В данной строке генерируется список всех .py-файлов в текущей директории, а оператор if фильтрует этот список, оставляя только файлы размером больше 6000 байт. Таких файлов только шесть, поэтому будет сгенерирован список из шести имён файлов.

Все рассмотренные примеры генераторов списков использовали простые выражения: умножение числа на константу, вызов одной функции или просто возврат элемента списка без изменений (после фильтрации). Но при генерации списков можно использовать выражения любой сложности.

>>> import os, glob
>>> [(os.stat(f).st_size, os.path.realpath(f)) for f in glob.glob('*.xml')] [(3074, 'c:\\Users\\pilgrim\\diveintopython3\\examples\\feed-broken.xml'), (3386, 'c:\\Users\\pilgrim\\diveintopython3\\examples\\feed-ns0.xml'), (3070, 'c:\\Users\\pilgrim\\diveintopython3\\examples\\feed.xml')] >>> import humansize [1]
>>> [(humansize.approximate_size(os.stat(f).st_size), f) for f in glob.glob('*.xml')] [('3.0 KiB', 'feed-broken.xml'), ('3.3 KiB', 'feed-ns0.xml'), ('3.0 KiB', 'feed.xml')] [2]
  1. ↑ Этот генератор ищет все .xml-файлы в текущем рабочем каталоге, получает размер каждого файла (вызывая функцию os.stat()), и создает кортеж из размера файла и абсолютного пути каждого файла (вызывая функцию os.path.realpath()).
  2. ↑ Этот генератор, основанный на предыдущем, вызывает функцию approximate_size(), передавая ей размер каждого .xml-файла.

Генераторы словарей

Генератор словаря похож на генератор списка, но вместо списка он создает словарь.

>>> import os, glob
>>> metadata = [(f, os.stat(f)) for f in glob.glob('*test*.py')] [1]
>>> metadata[0] ('alphameticstest.py', nt.stat_result(st_mode=33206, st_ino=0, st_dev=0, st_nlink=0, st_uid=0, st_gid=0, st_size=2509, st_atime=1247520344, st_mtime=1247520344, st_ctime=1247520344)) [2]
>>> metadata_dict = {f:os.stat(f) for f in glob.glob('*test*.py')} [3]
>>> type(metadata_dict) <class 'dict'> [4]
>>> list(metadata_dict.keys()) ['romantest8.py', 'pluraltest1.py', 'pluraltest2.py', 'pluraltest5.py', 'pluraltest6.py', 'romantest7.py', 'romantest10.py', 'romantest4.py', 'romantest9.py', 'pluraltest3.py', 'romantest1.py', 'romantest2.py', 'romantest3.py', 'romantest5.py', 'romantest6.py', 'alphameticstest.py', 'pluraltest4.py'] [5]
>>> metadata_dict['alphameticstest.py'].st_size 2509 [6]
  1. ↑ Это не генератор словаря, это генератор списка. Он находит все файлы с расширением .py, проверяет их имена, а затем создает кортеж из имени файла и метаданных файла (вызывая функцию os.stat()).
  2. ↑ Каждый элемент результирующего списка — кортеж.
  3. ↑ Это генератор словаря. Синтаксис подобен синтаксису генератора списка, но с двумя отличиями. Во-первых, он заключён в фигурные скобки, а не в квадратные. Во-вторых, вместо одного выражения для каждого элемента он содержит два, разделённые двоеточием. Выражение слева от двоеточия (в нашем примере f) является ключом словаря; выражение справа от двоеточия (в нашем примере os.stat(f)) — значением.
  4. ↑ Генератор словаря возвращает словарь.
  5. ↑ Ключи данного словаря — это просто имена файлов, полученные с помощью glob.glob('*test*.py').
  6. ↑ Значение, связанное с каждым ключом, получено с помощью функции os.stat(). Это означает, что в этом словаре мы можем по имени файла получить его метаданные. Один из элементов метаданных (st_size) — это размер файла. Размер файла alphameticstest.py — 2509 байт.

Также, как и в генераторах списков, вы можете включать в генераторы словарей условие if, чтобы отфильтровать входную последовательность с помощью выражения-условия, вычисляющегося для каждого элемента.