Python — os module

Добавление вложения \ тела письма при помощи модуля email

# create the message
msg = MIMEMultipart()
msg = from_addr
msg = subject
msg = formatdate(localtime=True)

if body_text:
msg.attach( MIMEText(body_text) )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

importos

importsmtplib

importsys

fromconfigparserimportConfigParser

fromemailimportencoders

fromemail.mime.text importMIMEText

fromemail.mime.base importMIMEBase

fromemail.mime.multipart importMIMEMultipart

fromemail.utilsimportformatdate

 
#———————————————————————-

defsend_email_with_attachment(subject,body_text,to_emails,cc_emails,bcc_emails,file_to_attach)

«»»

    Send an email with an attachment
    «»»

base_path=os.path.dirname(os.path.abspath(__file__))

config_path=os.path.join(base_path,»email.ini»)

header=’Content-Disposition’,’attachment; filename=»%s»‘%file_to_attach

# get the config

ifos.path.exists(config_path)

cfg=ConfigParser()

cfg.read(config_path)

else

print(«Config not found! Exiting!»)

sys.exit(1)

# extract server and from_addr from config

host=cfg.get(«smtp»,»server»)

from_addr=cfg.get(«smtp»,»from_addr»)

# create the message

msg=MIMEMultipart()

msg»From»=from_addr

msg»Subject»=subject

msg»Date»=formatdate(localtime=True)

ifbody_text

msg.attach(MIMEText(body_text))

msg»To»=’, ‘.join(to_emails)

msg»cc»=’, ‘.join(cc_emails)

attachment=MIMEBase(‘application’,»octet-stream»)

try

withopen(file_to_attach,»rb»)asfh

data=fh.read()

attachment.set_payload(data)

encoders.encode_base64(attachment)

attachment.add_header(*header)

msg.attach(attachment)

exceptIOError

msg=»Error opening attachment file %s»%file_to_attach

print(msg)

sys.exit(1)

emails=to_emails+cc_emails

server=smtplib.SMTP(host)

server.sendmail(from_addr,emails,msg.as_string())

server.quit()

if__name__==»__main__»

emails=»mike@someAddress.org»,»nedry@jp.net»

cc_emails=»someone@gmail.com»

bcc_emails=»anonymous@circe.org»

subject=»Test email with attachment from Python»

body_text=»This email contains an attachment!»

path=»/path/to/some/file»

send_email_with_attachment(subject,body_text,emails,cc_emails,bcc_emails,path)

DirEntry attributes being properties

In some ways it would be nicer for the DirEntry is_X() and
stat() to be properties instead of methods, to indicate they’re
very cheap or free. However, this isn’t quite the case, as stat()
will require an OS call on POSIX-based systems but not on Windows.
Even is_dir() and friends may perform an OS call on POSIX-based
systems if the dirent.d_type value is DT_UNKNOWN (on certain
file systems).

Also, people would expect the attribute access entry.is_dir to
only ever raise AttributeError, not OSError in the case it
makes a system call under the covers. Calling code would have to have
a try/except around what looks like a simple attribute access,
and so it’s much better to make them methods.

Комбинация os и fnmatch

Решение, использующее подпроцессы, элегантно, но требует большого количества кода. Вместо этого, давайте объединим методы из двух модулей os и fnmatch. Этот вариант также работает с Python 2 и 3.

В качестве первого шага, импортируем модули os и fnmatch. Далее определим каталог, в котором нужно перечислить файлы, используя os.listdir(), а также шаблон для фильтрации файлов. В цикле for выполняется итерация списка записей, хранящихся в переменной listOfFiles.

В завершение, с помощью fnmatch отфильтровываются искомые записи и распечатываются соответствующие записи в stdout.

Результат выполнения

Deriving new paths

A path can be joined with another using the operator:

>>> p = PurePosixPath('foo')
>>> p / 'bar'
PurePosixPath('foo/bar')
>>> p / PurePosixPath('bar')
PurePosixPath('foo/bar')
>>> 'bar' / p
PurePosixPath('bar/foo')

As with the constructor, multiple path components can be specified, either
collapsed or separately:

>>> p / 'bar/xyzzy'
PurePosixPath('foo/bar/xyzzy')
>>> p / 'bar' / 'xyzzy'
PurePosixPath('foo/bar/xyzzy')

A joinpath() method is also provided, with the same behaviour:

>>> p.joinpath('Python')
PurePosixPath('foo/Python')

The with_name() method returns a new path, with the name changed:

>>> p = PureWindowsPath('c:/Downloads/pathlib.tar.gz')
>>> p.with_name('setup.py')
PureWindowsPath('c:/Downloads/setup.py')

It fails with a ValueError if the path doesn’t have an actual name:

>>> p = PureWindowsPath('c:/')
>>> p.with_name('setup.py')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pathlib.py", line 875, in with_name
    raise ValueError("%r has an empty name" % (self,))
ValueError: PureWindowsPath('c:/') has an empty name
>>> p.name
''

The with_suffix() method returns a new path with the suffix changed.
However, if the path has no suffix, the new suffix is added:

>>> p = PureWindowsPath('c:/Downloads/pathlib.tar.gz')
>>> p.with_suffix('.bz2')
PureWindowsPath('c:/Downloads/pathlib.tar.bz2')
>>> p = PureWindowsPath('README')
>>> p.with_suffix('.bz2')
PureWindowsPath('README.bz2')

Выявление ошибок

Иногда, в ходе работы, ошибки случаются. Файл может быть закрыт, потому что какой-то другой процесс пользуется им в данный момент или из-за наличия той или иной ошибки разрешения. Когда это происходит, может появиться IOError. В данном разделе мы попробуем выявить эти ошибки обычным способом, и с применением оператора with. Подсказка: данная идея применима к обоим способам.

Python

try:
file_handler = open(«test.txt»)
for line in file_handler:
print(line)
except IOError:
print(«An IOError has occurred!»)
finally:
file_handler.close()

1
2
3
4
5
6
7
8

try

file_handler=open(«test.txt»)

forline infile_handler

print(line)

exceptIOError

print(«An IOError has occurred!»)

finally

file_handler.close()

В описанном выше примере, мы помещаем обычный код в конструкции try/except. Если ошибка возникнет, следует открыть сообщение на экране

Обратите внимание на то, что следует удостовериться в том, что файл закрыт при помощи оператора finally. Теперь мы готовы взглянуть на то, как мы можем сделать то же самое, пользуясь следующим методом:

Python

try:
with open(«test.txt») as file_handler:
for line in file_handler:
print(line)
except IOError:
print(«An IOError has occurred!»)

1
2
3
4
5
6

try

withopen(«test.txt»)asfile_handler

forline infile_handler

print(line)

exceptIOError

print(«An IOError has occurred!»)

Как вы можете догадаться, мы только что переместили блок with туда же, где и в предыдущем примере. Разница в том, что оператор finally не требуется, так как контекстный диспетчер выполняет его функцию для нас.

Создание и удаление папок через Pathlib

Классический модуль используется только для манипуляции строками пути. Чтобы что-то сделать с путем, например, создать директорию, нам нужен модуль . Модуль предоставляет набор функций для работы с файлами и каталогами, например: для создания директории, для переименования, а для получения ее размера.

Давайте напишем некоторые из этих операций с помощью модуля , а затем перепишем тот же код с помощью модуля Pathlib.

Пример кода, написанный с использованием модуля :

Python

if os.path.isdir(path):
os.rmdir(path)

1
2

ifos.path.isdir(path)

os.rmdir(path)

Если мы используем объекты модуля Pathlib для достижения той же функциональности, конечный код будет читабельнее и легче для понимания:

Python

if path.is_dir()
path.rmdir()

1
2

ifpath.is_dir()

path.rmdir()

В модуле сложновато найти утилиты, связанные с путем. Модуль Pathlib решает эту проблему, заменяя утилиты модуля методами объектов путя. Давайте попробуем разобраться в этом на примере следующего кода:

Python

outpath = os.path.join(os.getcwd(), ‘output’)
outpath_tmp = os.path.join(os.getcwd(), ‘output.tmp’)
generate_data(output_tmp)

if os.path.getsize(output_tmp):
os.rename(outpath_tmp, outpath)
else: # Ничего не происходит
os.remove(outpath_tmp)

1
2
3
4
5
6
7
8

outpath=os.path.join(os.getcwd(),’output’)

outpath_tmp=os.path.join(os.getcwd(),’output.tmp’)

generate_data(output_tmp)

ifos.path.getsize(output_tmp)

os.rename(outpath_tmp,outpath)

else# Ничего не происходит

os.remove(outpath_tmp)

Здесь функция принимает путь к файлу в качестве параметра и записывает данные в другой путь. Однако, если файл, который передается в качестве параметра, не изменяется, так как в последний раз была выполнена функция , генерируется пустой файл. В этом случае пустой файл заменяется предыдущей версией файла.

Переменная сохраняет данные, соединяя текущий рабочий каталог с названием файла «output». Мы также создаем временную версию, названную . Если размер временной версии не равен нулю, что означает, что это не пустой файл, тогда временная версия переименовывается в , в противном случае временная версия удаляется, а старая версия сохраняется.

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

Попробуем переписать вышеуказанный код с модулем Pathlib:

Python

from pathlib import Path

outpath = Path.cwd() / ‘output’
outpath_tmp = Path.cwd() / ‘output_tmp’

generate_data(output_tmp)

if outpath_tmp.stat().st_size:
outpath_tmp.rename(outpath)
else: # Ничего не производится
Path_tmp.unlink()

1
2
3
4
5
6
7
8
9
10
11

frompathlib importPath

outpath=Path.cwd()’output’

outpath_tmp=Path.cwd()’output_tmp’

generate_data(output_tmp)

ifoutpath_tmp.stat().st_size

outpath_tmp.rename(outpath)

else# Ничего не производится

Path_tmp.unlink()

При использовании Pathlib становится , а оператор нужен для объединения путей на месте . Вместе с модулем Pathlib можно значительно упростить код, задействуя операторы и вызовы метода.

Популярные методы и их предназначение:

  • : Возвращает путь объекта текущей рабочей директории;
  • : Возвращает путь объекта домашней директории;
  • : Возвращает информацию о пути;
  • : Меняет режим и уровень доступа файла;
  • : Получение всех файлов которые соответствую паттерну, например (все картинки) или (все песни);
  • : создает новую папку по данному пути;
  • : Открывает файл, созданный в пути;
  • : Переименовывает файл или директорию указанной цели;
  • : Удаляет пустую директорию;
  • : Удаляет файл или символическую ссылку.

Как использовать модуль Pathlib?

Для работы с Pathlib в Python требуется импортировать все классы данного модуля, используя следующую команду:

Python

from pathlib import *

1 frompathlib import*

В качестве первого задания давайте извлечем текущую рабочую директорию и домашнюю директорию объектов, используя следующий код:

Python

current_dir = Path.cwd()
home_dir = Path.home()

print(current_dir)
print(home_dir)

1
2
3
4
5

current_dir=Path.cwd()

home_dir=Path.home()

print(current_dir)

print(home_dir)

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

Python

import pathlib

current_dir = pathlib.Path.cwd()
home_dir = pathlib.Path.home()

print(current_dir)
print(home_dir)

1
2
3
4
5
6
7

importpathlib

current_dir=pathlib.Path.cwd()

home_dir=pathlib.Path.home()

print(current_dir)

print(home_dir)

Methods not following symlinks by default

There was much debate on python-dev (see messages in this thread)
over whether the DirEntry methods should follow symbolic links or
not (when the is_X() methods had no follow_symlinks parameter).

Initially they did not (see previous versions of this PEP and the
scandir.py module), but Victor Stinner made a pretty compelling case on
python-dev that following symlinks by default is a better idea, because:

  • following links is usually what you want (in 92% of cases in the
    standard library, functions using os.listdir() and
    os.path.isdir() do follow symlinks)
  • that’s the precedent set by the similar functions
    os.path.isdir() and pathlib.Path.is_dir(), so to do
    otherwise would be confusing
  • with the non-link-following approach, if you wanted to follow links
    you’d have to say something like if (entry.is_symlink() and
    os.path.isdir(entry.path)) or entry.is_dir()
    , which is clumsy

As a case in point that shows the non-symlink-following version is
error prone, this PEP’s author had a bug caused by getting this
exact test wrong in his initial implementation of scandir.walk()
in scandir.py (see Issue #4 here).

In the end there was not total agreement that the methods should
follow symlinks, but there was basic consensus among the most involved
participants, and this PEP’s author believes that the above case is
strong enough to warrant following symlinks by default.

Как выполнять код интерактивно

Есть больше 4 способов запустить Python-скрипт интерактивно. Рассмотрим их все подробно.

Использование import для запуска скриптов

Импорт модулей для загрузки скриптов и библиотек используется постоянно. Можно даже написать собственный скрипт (например code1.py) и импортировать его в другой файл без необходимости повторять то же самое.

Вот как нужно импортировать code1.py в новом скрипте.

Копировать

Но таким образом импортируется все содержимое файла code1.py. Это не проблема до тех пор, пока не появляется необходимость, в том, чтобы код был оптимизирован и быстро работал.

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

Вот как это обычно делается.

Копировать

Теперь появляется возможность использовать в новом файле так, будто бы эта функция была написана здесь.

Использование importlib для запуска кода

из importlib позволяет импортировать и исполнять другие Python-скрипты.

Это работает очень просто. Для скрипта code1.py нужно сделать следующее:

Копировать

И нет необходимости добавлять .py в .

Разберем случай, когда есть сложная структура папок, и нужно использовать importlib. Предположим, что структура следующая:

В таком случае, написав, например, , вы получите ошибку. Это называется относительным импортом и работает за счет явного использования относительного пути.

Так, для запуска скрипта level3.py можно написать так:

Копировать

Запуск кода с помощью runpy

Модуль ищет и исполняет Python-скрипт без импорта. Он также легко используется, ведь достаточно просто вызывать имя модуля в .

Вот как, например, выполнить code1.py с помощью runpy.

Копировать

Запуск кода динамически

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

Вот как она помогает выполнять код динамически на примере строки.

Копировать

Однако этот способ уже устарел. Он медленный и непредсказуемый, а Python предлагает массу других вариантов.

Return values being pathlib.Path objects

With Antoine Pitrou’s new standard library pathlib module, it
at first seems like a great idea for scandir() to return instances
of pathlib.Path. However, pathlib.Path‘s is_X() and
stat() functions are explicitly not cached, whereas scandir
has to cache them by design, because it’s (often) returning values
from the original directory iteration system call.

And if the pathlib.Path instances returned by scandir cached
stat values, but the ordinary pathlib.Path objects explicitly
don’t, that would be more than a little confusing.

Guido van Rossum explicitly rejected pathlib.Path caching stat in
the context of scandir here,
making pathlib.Path objects a bad choice for scandir return
values.

Construction

We will present construction and joining together since they expose
similar semantics.

The simplest way to construct a path is to pass it its string representation:

>>> PurePath('setup.py')
PurePosixPath('setup.py')

Extraneous path separators and "." components are eliminated:

>>> PurePath('a///b/c/./d/')
PurePosixPath('a/b/c/d')

If you pass several arguments, they will be automatically joined:

>>> PurePath('docs', 'Makefile')
PurePosixPath('docs/Makefile')

Joining semantics are similar to os.path.join, in that anchored paths ignore
the information from the previously joined components:

>>> PurePath('/etc', '/usr', 'bin')
PurePosixPath('/usr/bin')

However, with Windows paths, the drive is retained as necessary:

>>> PureWindowsPath('c:/foo', '/Windows')
PureWindowsPath('c:/Windows')
>>> PureWindowsPath('c:/foo', 'd:')
PureWindowsPath('d:')

Also, path separators are normalized to the platform default:

>>> PureWindowsPath('a/b') == PureWindowsPath('a\\b')
True

Extraneous path separators and "." components are eliminated, but not
".." components:

>>> PurePosixPath('a//b/./c/')
PurePosixPath('a/b/c')
>>> PurePosixPath('a/../b')
PurePosixPath('a/../b')

Multiple leading slashes are treated differently depending on the path
flavour. They are always retained on Windows paths (because of the UNC
notation):

>>> PureWindowsPath('//some/path')
PureWindowsPath('//some/path/')

On POSIX, they are collapsed except if there are exactly two leading slashes,
which is a special case in the POSIX specification on
(this is also necessary for Cygwin compatibility):

>>> PurePosixPath('///some/path')
PurePosixPath('/some/path')
>>> PurePosixPath('//some/path')
PurePosixPath('//some/path')

Calling the constructor without any argument creates a path object pointing
to the logical «current directory» (without looking up its absolute path,
which is the job of the cwd() classmethod on concrete paths):

Зачем использовать модуль Pathlib?

Если вы некоторое время работали с языком Python, у вас может возникнуть вопрос. Зачем нужен модуль Pathlib, когда уже есть модули , , и прочие? Это хороший вопрос. Давайте попробуем ответить на него, разобрав следующий пример.

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

Python

import os

outpath = os.path.join(os.getcwd(), ‘output’)
outpath_file = os.path.join(outpath, ‘out.xlsx’)

1
2
3
4

importos

outpath=os.path.join(os.getcwd(),’output’)

outpath_file=os.path.join(outpath,’out.xlsx’)

Альтернативный способ:

Python

outpath_file = os.pathjoin(os.path.join(os.getcwd(), ‘output’), «out.xlsx»)

1 outpath_file=os.pathjoin(os.path.join(os.getcwd(),’output’),»out.xlsx»)

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

Данный код можно переписать, используя модуль Pathlib:

Python

from pathlib import Path
outpath = Path.cwd() / ‘output’ / ‘output.xlsx’

1
2

frompathlib importPath

outpath=Path.cwd()’output»output.xlsx’

Шаблон вложенности функций в модуле заменяется классом модуля Pathlib, что представляет путь через объединение методов и атрибутов. Умная перегрузка оператора делает код читабельным и простым в обращении.

Другое преимущество метода, предоставляемого модулем Pathlib, заключается в том, что объект создается вместо строкового представления пути. У этого объекта есть несколько удобных методов, что имеют значительное преимущество перед работой с необработанными строками, которые представляют пути.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *