Откроем текстовый файл на чтение (когда второй аргумент не указан, файл открывается именно на чтение).
f=open('text.txt')
f,type(f)
Получился объект f
одного из файловых типов. Что с ним можно делать? Можно его использовать в for
цикле, каждый раз будет возвращаться очередная строка файла (включая '\n'
в конце; в конце последней строки текстового файла '\n'
может и не быть).
for s in f:
print(s)
Теперь файл нужно закрыть.
f.close()
Такой стиль работы с файлом (f=open(...)
; работа с f
; f.close()
) на самом деле не рекомендуется. Гораздо правильнее использовать оператор with
. Он гарантирует, что файл будет закрыт как в том случае, когда исполнение тела with
нормально дошло до конца, так и тогда, когда при этом произошло исключение, и мы покинули тело with
аварийно.
В операторе with может использоваться любой объект класса, реализующего методы __enter__
и __exit__
. Обычно это объект-файл, возвращаемый функцией open
.
with open('text.txt') as f:
for s in f:
print(s[:-1])
Метод f.read(n)
читает n
символов (когда файл близится к концу и прочитать именно n
символов уже невозможно, читает меньше; в самый последний раз он читает 0 символов и возвращает ''
). Прочитаем файл по 1 символу.
with open('text.txt') as f:
while True:
c=f.read(1)
if c=='':
break
else:
print(c)
Вызов f.read()
без аргумента читает файл целиком (что не очень разумно, если в нём много гигабайт).
with open('text.txt') as f:
s=f.read()
s
f.readline()
читает очередную строку (хотя проще использовать for s in f:
).
with open('text.txt') as f:
while True:
s=f.readline()
if s=='':
break
else:
print(s)
Метод f.readlines()
возвращает список строк (опять же его лучше не применять для очень больших файлов).
with open('text.txt') as f:
l=f.readlines()
l
Теперь посмотрим, чем же оператор with
лучше, чем пара open
- close
.
def a(name):
global f
f=open(name)
s=f.readline()
n=1/0
f.close()
return s
a('text.txt')
f.closed
f.close()
Произошло исключение, мы покинули функцию до строчки close
, и файл не закрылся.
def a(name):
global f
with open(name) as f:
s=f.readline()
n=1/0
return s
a('text.txt')
f.closed
Теперь всё в порядке.
Чтобы открыть файл на запись, нужно включить второй аргумент 'w'
.
f=open('newtext.txt','w')
f.write('aaa\n')
f.write('bbb\n')
f.write('ccc\n')
f.close()
Метод write
возвращает число записанных символов.
Опять же, лучше использовать with.
with open('newtext.txt','w') as f:
f.write('aaa\n')
f.write('bbb\n')
f.write('ccc\n')
!cat newtext.txt
Эта функция копирует старый текстовый файл в новый. Если строки нужно как-нибудь обработать, в последней строчке вместо line
будет стоять что-нибудь вроде f(line)
.
def copy(old_name,new_name):
with open(old_name) as old,open(new_name,'w') as new:
for line in old:
new.write(line)
copy('text.txt','newtext.txt')
!cat newtext.txt
Если в программе используется какой-нибудь ресурс, который обязательно надо освободить после использования (например, сетевое соединение или соединение с базой данных), то лучше написать класс, реализующий методы __enter__
и __exit__
, и использовать этот ресурс в блоке with
.
class Connection:
def __init__(self):
self.opened=False
def __enter__(self):
print('Открываем')
self.opened=True
def __exit__(self,ex_type,ex_value,ex_traceback):
if ex_value:
print(f'Exception {ex_value}')
print('Закрываем')
self.opened=False
def f(x):
with Connection() as conn:
x=1/x
return x
f(1)
f(0)
В интерактивной сессии (или в программе, запущенной с командной строки) можно попросить пользователя что-нибудь ввести. Аргумент функции input
- это приглашение для ввода (prompt). Можно использовать просто input()
, тогда приглашения не будет. Но это неудобно, т.к. в этом случае трудно заметить, что программа чего-то ждёт.
s=input('Введите целое число ')
s
n=int(s)
n
Питон - интерпретатор, поэтому он может во время выполнения программы интерпретировать строки как куски исходного текста на языке питон. Так, функция eval
интерпретирует строку как выражение и вычисляет его (в текущем контексте - подставляя текущие значения переменных).
s=input('Введите выражение ')
s
eval(s)
А функция exec
интерпретирует строку как оператор и выполняет его. Оператор может менять значения переменных в текущем пространстве имён.
s=input('Введите оператор ')
s
exec(s)
x
Строка s
может быть результатом длинного и сложного вычисления. Но лучше таких фокусов не делать, так как программа фактически становится самомодифицирующейся. Такие программы очень сложно отлаживать.
Для работы с путями к файлам и директориям в стандартной библиотеке существует модуль pathlib
. Объект класса Path
представляет собой путь к файлу или директории.
from pathlib import Path
Path()
возвращает текущую директорию.
p=Path()
p
Очень полезный метод resolve
приводит путь к каноническому виду.
p.resolve()
Путь может быть записан в совершенно идиотском виде; resolve
его исправит.
p=Path('.././/book')
p=p.resolve()
p
Статический метод cwd
возвращает текущую директорию (current working directory).
Path.cwd()
Если p
- путь к директории, то можно посмотреть все файлы в ней.
for f in p.iterdir():
print(f)
Если p
- путь к директории, то p/'fname'
- путь к файлу fname
в ней (он, конечно, тоже может быть директорией).
p2=p/'b101_numbers.ipynb'
p2
Существует ли такой файл?
p2.exists()
Является ли он симлинком, директорией, файлом?
p2.is_symlink(),p2.is_dir(),p2.is_file()
Части пути p2
.
p2.parts
Родитель - директория, в которой находится этот файл.
p2.parent,p2.parent.parent
Имя файла, его основа и суффикс.
p2.name,p2.stem,p2.suffix
Метод stat
возвращает всякую ценную информацию о файле.
s=p2.stat()
s
Например, его размер в байтах.
s.st_size
Я написал полезную утилиту для поиска одинаковых файлов. Ей передаётся произвольное число аргументов - директорий и файлов. Она рекурсивно обходит директории, находит размер всех файлов (симлинки игнорируются) и строит словарь, сопоставляющий каждому размеру список файлов, имеющих такой размер. Это простой этап, не требующий чтения (возможно больших) файлов. После этого файлы из тех списков, длина которых $>1$, сравниваются функцией cmp
из библиотечного модуля filecmp
(что, конечно, требует их чтения).
!cat dup.py
!ls test
!ls test/sub
!./dup.py test
В питоне можно работать с переменными окружения как с обычным словарём.
from os import environ
environ['PATH']
environ['ABCD']
environ['ABCD']='abcd'
environ['ABCD']
Мы не просто добавили пару ключ-значение в словарь, а действительно добавили новую переменную к текущему окружению. Если теперь вызвать из питона какую-нибудь внешнюю программу, то она эту переменную увидит. Эта переменная исчезнет, когда закончится выполнение текущей программы на питоне (или интерактивная сессия).