Переменная

— Что за странная фантазия: назвать собаку именем жены?

— А что ты хочешь от Шульца, он вообще… фантазер. Знаешь, как он называет жену? Киса.

— Вы представляете, как жизнь у него началась?! Сидит, например, Шульц дома, ему скучно, он хочет позвать жену. И, естественно, он кричит: «Эмма, Эмма!» И что же происходит?! Собака думает, что зовут жену, и не двигается с места, а жена думает, что зовут собаку и тоже не двигается с места! Шульцу это надоело и он решил назвать собаку Гектором.

— Но Гектор — это мужское имя!

— Да… мужское, мужское… Но ведь как Шульц рассуждал?! (— Да, как рассуждал Шульц?) Характер у него тяжёлый — жена может от него уйти, собака — ни-ког-да. С другой стороны, человек он молодой и может жениться во второй раз. Где гарантия, что его новая жена не окажется тоже Альмой, м? Где гарантия? Поэтому он и дал собаке новое мужское имя. Собака, очевидно, этого не выдержала и… сдохла. Сдохла Гектором, будучи по… существу Эммой.

@Летучая мышь

dog

Условные инструкции

In [ ]:
# Не запускать, просто пример
if condition:
    do_smth1
else: 
    do_smth2
In [ ]:
a = input()
a = int(a)
if a > 10:
    print("a is greater than 10")
else:
    if a == 10:
        print("a is equal to 10")
    else:
        print("a is less than 10")
In [ ]:
a = input()
a = int(a)
if a > 10:
    print("a is greater than 10")
elif a == 10: # else if = elif
    print("a is equal to 10")
else:
    print("a is less than 10")
In [43]:
a = input()
a = int(a)
if a % 2 != 0:
    a = a - 1
print(a)
53
52

Замечание 1. Двоеточие после условия (в конце строки if) обязательно!

Замечание 2. После if и после else!

Замечание 3:

В питоне группы команд определяются ОТСТУПАМИ! За отступами нужно ВНИМАТЕЛЬНО следить! Отступами могут служить и пробелы и знаки табуляции, причём в любом количестве, главное, чтобы команды из одной группы находились на одном уровне.

Замечание 4:

В Питоне нет операторных скобок {

if условие1:
    команда1
    команда2
else:
    команда3
In [2]:
from __future__ import brackets
  File "<ipython-input-2-6bd1102a3dc1>", line 4
SyntaxError: from __future__ imports must occur at the beginning of the file

Жена

В свое время Сократ мне сказал: «Женись непременно. Попадется хорошая жена — станешь счастливым. Плохая — станешь философом.» Не знаю, что лучше. @Тот самый Мюнхгаузен

Написать в следующей ячейке код, которые, если значение переменной wife равно "плохая", печатает "Философ", а если равно "плохая" - "Счастливый". Если переменная wife содержит другое значение, то напечатать "Оригинальный"

In [4]:
wife = "good"
# писать здесь
if wife == "good":
    print("Happy")
elif wife == "bad":
    print("Philosopher")
else:
    print("Original")
Happy
In [44]:
wife = input("Describe your wife?")
# писать здесь
if wife == "good":
    print("Happy")
elif wife == "bad":
    print("Philosopher")
else:
    print("Weird")
Describe your wife?good
Happy

Циклы. For

Используем, когда хотим сделать определенное действие определенное число раз.

Например, отжаться 10 раз

In [45]:
for i in range(100): # делать 100 раз, i примет значения от 0 до 99
    if i % 17 == 0:
        print(i)
0
17
34
51
68
85
In [46]:
for i in range(10, 100):
    # делать 100 раз, i примет значения от 10 до 99
    if i % 5 == 0:
        print(i)
10
15
20
25
30
35
40
45
50
55
60
65
70
75
80
85
90
95
In [2]:
for i in range(10, 100, 2):
    # i от 10 до 98
    if i % 17 == 0:
        print(i)
34
68

Два важных соуса к for - это операторы break и continue

break позволяет досрочно выйти из цикла

In [48]:
# Проверка того, что число простое
a = input()
a = int(a)

if a > 1:
    is_prime = True
    for i in range(2, a): # итерироваться, начиная с 2 и заканчивая a - 1
        if a % i == 0: # если число делится на что-то из этого без остатка, 
            # то оно не простое
            is_prime = False
            break  # можем досрочно завершить цикл, 
            # у нас нет смысла что-либо проверять дальше
else:
    is_prime = False
    
print(is_prime)
612
False

continue позволяет досрочно перейти к следующей итерации цикла

In [4]:
for i in range(5):
    if i == 2 or i == 3:
        continue
    print(i)
0
1
4

Циклы. While

- Мы уже приехали?

- Нет.

- Уже приехали?

- Нет.

- Уже приехали?

- Нет.

- А теперь?

- Да.

- Честно?

- НЕТ!

© Шрек 2

shrek

До данного момента мы с вами разобрали цикл for. Этот цикл является наиболее часто используемым в питоне, однако иногда он все же неудобен. Например, если вы не знаете, сколько раз вам необходимо будет совершить определенное действие. Для такого рода проблем существует цикл while.

while не замена for

In [4]:
# Это пример НЕПРАВИЛЬНОГО использования while,
# тут намного правильнее делать цикл for
a = 0
while a < 10:
    print (a)
    a += 1
0
1
2
3
4
5
6
7
8
9
In [5]:
for a in range(0, 10):
    print(a)
0
1
2
3
4
5
6
7
8
9

Допустим, вы ведете диалог с пользователем и выполняете какое-то действие, пока он не введет "stop". Вот здесь без while обойтись сложно

In [11]:
answer = input("Input number: ")
while answer != "stop":
    answer = int(answer)
    if answer % 2 == 0:
        print("even")
    else:
        print("odd")
    answer = input("Input number: ")
Input number: 10
even
Input number: stop
In [50]:
answer = input("Input number: ")
while answer != "stop":
    answer = int(answer)
    if answer % 2 == 0:
        print("even")
    else:
        print("odd")
    # answer = input("Input number: ")
Input number: stop

joke

Базовые типы

  1. Целые числа

  2. Числа с плавающей запятой

  3. Логический тип

  4. Строковый тип (строго говоря, уже коллекции, т.к хранят последовательность символов)

Пример логического типа

In [9]:
a = 5
b = a == 5
print (b, type(b))
True <class 'bool'>

Числа с плавающей запятой хранят вещественные числа не с абсолютной точностью!

In [10]:
10 / 7 - 1 - 3/7
Out[10]:
5.551115123125783e-17
In [11]:
10 / 7 - 1 - 3/7 == 0
Out[11]:
False
In [12]:
10 / 7 - 1 - 3/7 < 10 ** (-7)
Out[12]:
True

Коллекции

Коллекции - это какие-то наборы объектов разного или одного типа. 100 кошек, 10 собак, набор - [арбуз, тыква, голый землекоп], - все это является коллекцией.

В Python существует несколько разных типов, которые помогают вам хранить коллекции объектов в удобном для вас виде. Одним из базовых является список

Списки

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

Есть несколько способов создать список, самым простым из них является просто заключить элемненты, из которых вы хотите создать список, в скобки

In [13]:
my_lst1 = ['apple', 5, True]

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

In [14]:
my_lst2 = ['apple', ['tomato', 'fish'], 5]

Можно создать и пустой список, то есть список без элементов

In [15]:
empty_lst = []

Индексация

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

Пример индексации

In [19]:
z = [3, 7, 4, 2]
In [20]:
z[3]
Out[20]:
2
In [21]:
z[-1]
Out[21]:
2
In [22]:
z[len(z) - 1]
Out[22]:
2
In [51]:
my_lst2 = ['apple', ['tomato', 'fish'], 5]
In [57]:
el = my_lst2[1]
el[0]
Out[57]:
'tomato'
In [17]:
my_lst2[-1]
Out[17]:
5
In [18]:
len(my_lst2)
Out[18]:
3

Напоминание для строк:

Индексация строк

Срезы

Точно так же, как и для строк, можно брать срезы

In [23]:
my_lst2
Out[23]:
['apple', ['tomato', 'fish'], 5]
In [16]:
my_lst2[0:-1]
Out[16]:
['apple', ['tomato', 'fish']]
In [13]:
my_lst2[0:0]
Out[13]:
[]
In [58]:
my_lst2[10:6]
Out[58]:
[]
In [17]:
my_lst2[-1:]
Out[17]:
[5]
In [14]:
my_lst2[-1]
Out[14]:
5
In [18]:
x = my_lst2[1]
x[0]
Out[18]:
'tomato'
In [18]:
my_lst2
Out[18]:
['apple', ['tomato', 'fish'], 5]
In [59]:
my_lst2[1:]
Out[59]:
[['tomato', 'fish'], 5]

Можно указать шаг, через который брать элементы

In [19]:
my_lst2[1::1]
Out[19]:
[['tomato', 'fish'], 5]
In [20]:
my_lst2[0::2]
Out[20]:
['apple', 5]
In [21]:
my_lst2[::-1]
Out[21]:
[5, ['tomato', 'fish'], 'apple']
In [24]:
my_lst2[0:2:2]
Out[24]:
['apple']

Проход по элементам списка (итерация)

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

In [21]:
my_lst3 = [1, 7, -5, 0, 32]
In [22]:
for i in range(len(my_lst3)):
    print(i, my_lst3[i])
0 1
1 7
2 -5
3 0
4 32

Однако в случае списков (и вообще всех коллекций в Python), можно использовать цикл for напрямую!

Именно этот путь рекомендуется использовать, а первый путь говорит о том, что автор кода, вероятнее всего, новичок

In [23]:
for elem in my_lst3:
    print(elem)
1
7
-5
0
32

for можно применить и для строк. В этом случае вы будете итерироваться по символам строки

In [25]:
s = "Hello, world"
for c in s:
    print(c)
H
e
l
l
o
,
 
w
o
r
l
d

Операции над списками

Списки можно складывать (называется уже известным вам умным словом конкатенация)

In [24]:
a = [2, 3, 4]
b = [-5, 10]
a + b
Out[24]:
[2, 3, 4, -5, 10]
In [27]:
a - b # Я не могу понять, а чего кто-то ожидал:) 
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-27-5631e6ac4f8e> in <module>()
----> 1 a - b # Я не могу понять, а чего кто-то ожидал:)

TypeError: unsupported operand type(s) for -: 'list' and 'list'
In [28]:
a * b # аналогично
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-28-9af333135275> in <module>()
----> 1 a * b # аналогично

TypeError: can't multiply sequence by non-int of type 'list'

Однако, список можно повторить несколько раз, умножив его на число, однако это не рекомендуется к использованию кроме самых очевидных случаев (чуть позже разберем, почему)

In [29]:
[0] * 5 # так делают
Out[29]:
[0, 0, 0, 0, 0]

Можно проверить, есть ли элемент в списке с помощью ключевого слова in

In [30]:
a = [1, 3, 10]
if 5 in a:
    print ("5 is in a")
else:
    print ("5 is not in a")
5 is not in a

Для строк работает аналогично

In [25]:
n = input()
if n in "ATGCUatgcu":
    print("nucleotide")
else:
    print("not")
at
nucleotide
In [31]:
n = input()
 
# перевести в верхний регистр
if n.upper() in "ATGCU": 
    print("nucleotide")
else:
    print("not")
a
nucleotide

Проверка списка на пустоту

Работает не только для списка, а для всех коллекций/контейнеров

In [31]:
if not a: # if a is empty
    print("HI")

b = [1]
if b: # if b is not empty
    print("HI")
HI
In [ ]:
if len(a) == 0: # if a is empty
    print("HI")
In [60]:
if [False]:
    print("Wow!")
Wow!

Изменяемость списков

В случае со строками, если вы попробуете изменить какой-то символ, то выскочит ошибка

In [61]:
a = "Hello, world!"
a[-1] = "?"
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-61-3428b86a429f> in <module>
      1 a = "Hello, world!"
----> 2 a[-1] = "?"

TypeError: 'str' object does not support item assignment

Приходится делать, например, так:

In [28]:
a = "Hello, world!"
b = a[0:-1] + "?"
print(a)
print(b)
b = a[:-1] + "?"
print(b)
Hello, world!
Hello, world?
Hello, world?

В случае со списками все намного проще. Они являются изменяемыми объектами

In [33]:
a = [1, -3, 10, 6]
In [34]:
a[-1] = 5
a
Out[34]:
[1, -3, 10, 5]
In [35]:
a
Out[35]:
[1, -3, 10, 5]

Изменяемые объекты. Проблемы.

In [38]:
a = [10, 5, 4]
b = a
a[-2] = 7

Что лежит в b?

In [39]:
b
Out[39]:
[10, 7, 4]

Если вспомнить аналогию про кошку, то вы назвали одну кошку разными именами. От этого кошка не раздвоилась.

cat

Потому, дразня кошку в переменной a, вы рискуете получить поцарапанные руки и в переменной b

In [40]:
colors = ['red', 'blue', 'green']
b = colors

colors

Чтобы бороться с таким поведением Python, вам придется заставить его скопировать список!

In [41]:
a = [10, 5, 4]
b = a[:] # берем срез всего списка - это его скопирует 
a[-2] = 7
print ("a", a)
print ("b", b)
a [10, 7, 4]
b [10, 5, 4]

Также можно использовать встроенную функцию Python - list

In [42]:
a = [10, 5, 4]
b = list(a)
a[-2] = 7
print ("a", a)
print ("b", b)
a [10, 7, 4]
b [10, 5, 4]
In [43]:
list("ATGCGAGCCG")
Out[43]:
['A', 'T', 'G', 'C', 'G', 'A', 'G', 'C', 'C', 'G']
In [62]:
list()
Out[62]:
[]

Также можно использовать метод изменяемых объектов Python - copy

In [44]:
a = [10, 5, 4]
b = a.copy()
a[-2] = 7
print("a", a)
print("b", b)
a [10, 7, 4]
b [10, 5, 4]

После обычной процедуры копирования изменения в списках будут разнесены, если мы не берем вложенные в них измененяемые объекты (например, списки). Однако если менять вложенный список, то изменения коснутся обеих списков

In [37]:
lst1 = ['a', 'b', ['ab', 'ba']]
lst2 = lst1.copy()
lst1[-1][0] = 5
lst2[-1][1] = "d"
lst2[0] = "c";
print(lst1)
print(lst2)
['a', 'b', [5, 'd']]
['c', 'b', [5, 'd']]

shallow_copy

Для вложенных списков и просто изменяемых объектов в изменяемых объектов - deepcopy

In [46]:
from copy import deepcopy

lst1 = ['a','b',['ab','ba']]

lst2 = deepcopy(lst1)

lst2[2][1] = "d"
lst2[0] = "c";

print(lst1)
print(lst2)
['a', 'b', ['ab', 'ba']]
['c', 'b', ['ab', 'd']]

deep_copy

Методы списка

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

append - Добавление в список

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

In [38]:
lst = []
for i in range(21):
    if i % 2 == 1:
        lst.append(i)
        
print (lst)
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

extend - хотим добавить в конец нашего списка все элементы из другого

In [48]:
a = [1,4]
b = [1, 2, 7]
c = a + b
print(a, b, c)
a[1] = 5
print(a, b, c)
[1, 4] [1, 2, 7] [1, 4, 1, 2, 7]
[1, 5] [1, 2, 7] [1, 4, 1, 2, 7]
In [49]:
lst = [1, 4]
lst.extend([1,2,7])
lst
Out[49]:
[1, 4, 1, 2, 7]

count - подсчитать число вхождений элемента в список

In [50]:
lst = [1, 7, -5, 6, 0, 1]
lst.count(1)
Out[50]:
2

sort - отсортировать список на месте

In [51]:
lst.sort()
lst
Out[51]:
[-5, 0, 1, 1, 6, 7]

Файлы

Люди делятся на два типа:

m

И

sh

Информация хранится на компьютерах в файлах.

Работа с файлами -- неотделимая часть жизни биоинформатика. До 90% работы среднестатистического биоинформатика уходит на парсинг файлов и их конвертацию между форматами.

Файл -- это данные, которые хранятся на некотором носителе, например, на жестком диске.

Чтение из файла

Для того, чтобы открыть новый файл на чтение служит команда open(filename, "r")

In [54]:
f = open('spring1.txt', "r")

f имееет имеет интересный тип, название которого не то чтобы много говорит, но этот тип объектов позволяет читать из себя данные.

In [55]:
type(f)
Out[55]:
_io.TextIOWrapper

Можно прочитать весь файл разом

In [56]:
print(f.read())
Бесконечно можно смотреть на три вещи: 
горящий огонь, 
бегущую воду 
и на собственный код месячной давности.

Открытый файл после окончания работы НАДО закрыть командной close

In [57]:
f.close()

Из файла также можно читать построчно:

In [58]:
f = open("spring2.txt", "r")
print(f.readline())
print(f.readline())
f.close()
- Мне сказали: умный человек!

- Ну мало ли, что про человека болтают.

In [63]:
print("\n\n\n")



Заметим, что прочитанная строка возвращается с "\n" на конце. Какую функцию надо использовать, чтобы его убрать?

In [40]:
f = open("spring2.txt", "r")
print(f.readline().strip())
print(f.readline().strip())
- Мне сказали: умный человек!
- Ну мало ли, что про человека болтают.

Когда файл дочитан до конца, функция readline возвращает пустую строку (без "\n" на конце)

In [41]:
print ("Returning empty string : |", f.readline(), "|", sep="")
f.close()
Returning empty string : ||

Казалось бы, можно организовать чтение всего файла следующим образом:

In [61]:
infile = open("spring3.txt", "r")
line = infile.readline()
while line != "":
    print(line.strip())
    line = infile.readline() # why not to strip line right here:? 

infile.close()
Ученые подсчитали, что
шансы реального существования
столь откровенно абсурдного
мира равняются одному на миллион.
Однако волшебники подсчитали, что
шанс «один на миллион» выпадает
в девяти случаях из десяти.

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

Если вам нужно обработать все строки из файла одинаковым способом, то этот способ наиболее предпочтителен - он не только компактнее и соответствует стилю Python, но он еще и быстрее.

In [62]:
infile = open("spring4.txt", "r")
for line in infile:
    print(line.strip())
infile.close()
Если разобраться, — сказал Ливитт, —
так это проблема из проблем.
Как дезинфицировать человеческое тело,
грязней которого, наверно,
нет ничего во всей Вселенной,
не уморив при этом человека?

Важно

Один раз пройдя по файлу, при попытке пройти по нему второй раз, вы ничего не прочитаете нового - вы уже в конце файла.

In [1]:
infile = open("tab.txt", "r")
for line in infile:
    print(line.strip())
    
for line in infile: #won't be executed
    print(line.strip())
infile.close()
#name   seqlen  class
mouse   100 +
human   120 -
cat 140 +

Аналогично, если из файла уже что-то читалось - второй раз оно прочитано не будет

Запись в файл

Открытие файла на запись - open(filename, "w") (это команда создает новый пустой файл)

Запись в файл осуществляется методов write

In [64]:
infile = open("Munchhausen1.txt", "w")

phrase = '''avsvsvsv''' # write doesn't append \n at the of string

infile.write(phrase)
infile.close()
In [66]:
f = open("Munchhausen1.txt", 'r')
print (f.read())
f.close()
avsvsvsv

Можно также записать в конец уже существующего файла, открыв его в append-mode ("a")

In [42]:
f = open("Munchhausen.txt", 'a')

s = '''saddsa\n'''
f.write("\n")
f.close()
f = open("Munchhausen.txt", 'a')
f.write(s)
f.write("@asdsa\n") 
f.close()
f = open("Munchhausen.txt", 'r')
print (f.read())
f.close()
В свое время Сократ мне сказал: 
"Женись непременно.
Попадется хорошая жена — станешь счастливым. 
Плохая — станешь философом."
Не знаю, что лучше

После свадьбы мы сразу уехали в свадебное путешествие. 
Я в Турцию, жена в Швейцарию,
и прожили там три года в любви и согласии.
@Тот самый Мюнхгаузен

saddsa
@asdsa

Почему важно закрывать файлы?

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

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

In [7]:
cat = "cat.txt"
f = open(cat, "w")
f.write("Hello,")
f.write("world\n")
g = open(cat, "r")
print (g.read())

In [8]:
cat = "cat.txt"
f = open(cat, "w")
f.write("Hello,")
f.write("world\n")
f.close()
g = open(cat, "r")
print (g.read())
Hello,world

Тут внезапно выяснится, что вы что-то записали в файл, не закрыв его, этого там не оказалось, ваша программа не нашла, чего искала, и упала.

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

А вот если его все же закрыть, то:

Более того, часто в биоинформатике вам приходится писать программы, работающие долгое время, возможно, отвечая на тысячи задач. Если так случится, что вы забываете на каждый запрос закрыть файл, то в какой-то момент вы не сможете открыть новый файл и ваша программа завершится аварийно. По-умному такая ситуация называется "утечка файловых дескрипторов".

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

In [69]:
# не запускайте этот код, если не готовы перезагружать тетрадь
opened_files = []

for i in range(1, 10000):
    fl = open(str(i), "w")
    opened_files.append(fl)
ERROR:root:Internal Python error in the inspect module.
Below is the traceback from this internal error.

Traceback (most recent call last):
  File "/Users/dmitrypenzar/miniconda3/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 2862, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-69-dec5f1f8a0f1>", line 5, in <module>
    fl = open(str(i), "w")
OSError: [Errno 24] Too many open files: '7112'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/dmitrypenzar/miniconda3/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 1806, in showtraceback
    stb = value._render_traceback_()
AttributeError: 'OSError' object has no attribute '_render_traceback_'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/dmitrypenzar/miniconda3/lib/python3.6/site-packages/IPython/core/ultratb.py", line 1090, in get_records
  File "/Users/dmitrypenzar/miniconda3/lib/python3.6/site-packages/IPython/core/ultratb.py", line 311, in wrapped
  File "/Users/dmitrypenzar/miniconda3/lib/python3.6/site-packages/IPython/core/ultratb.py", line 345, in _fixed_getinnerframes
  File "/Users/dmitrypenzar/miniconda3/lib/python3.6/inspect.py", line 1483, in getinnerframes
  File "/Users/dmitrypenzar/miniconda3/lib/python3.6/inspect.py", line 1441, in getframeinfo
  File "/Users/dmitrypenzar/miniconda3/lib/python3.6/inspect.py", line 696, in getsourcefile
  File "/Users/dmitrypenzar/miniconda3/lib/python3.6/inspect.py", line 725, in getmodule
  File "/Users/dmitrypenzar/miniconda3/lib/python3.6/inspect.py", line 709, in getabsfile
  File "/Users/dmitrypenzar/miniconda3/lib/python3.6/posixpath.py", line 376, in abspath
OSError: [Errno 24] Too many open files
---------------------------------------------------------------------------