Python 2019

*Основа материала - курсы Сергея Лебедева и Алексея Кладова

Лекция 1

Введение, история, ликбез

История

  • 1989 первый код
  • 1994 — Python 1.0 (→)
  • 1996 — Java 1.0, Ruby 1.0

 

Окружение для ОС Amoeba

Источники вдохновения

ABC

HOW TO RETURN words document:
   PUT {} IN collection
   FOR line IN document:
      FOR word IN split line:
         IF wordnot.incollection:
            INSERT word IN collection
   RETURN collection

Modula-3

TRY
  DO.Something()
EXCEPT
| IO.Error=> IO.Put("An I/O error occurred.")
END;
  • 2000 — Python 2, PEP
  • 2008 — Python 3
  • 2018 — Гвидо больше не BDLF
  • Хотелось простой, понятный, удобный и полезный язык с открытым исходным кодом.
  • Получилось:

 

 

 

 

  • Что делает функция magic?

Цели и результаты

def magic(top):
    acc = []
    for entry in os.scandir(top):
        if entry.is_file() and entry.name.endwith(".py"):
            acc.append(entry.path)
    return acc

Python — динамический интерпретируемый язык.

>>> def add(x, y):
...     return x + y
... 
>>> def bar(x):
...     add(x, "1", "2") # не ошибка
... 
>>> add.__code__ = bar.__code__
>>> add(42)
Traceback (most recent call last)
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in bar
TypeError: bar() takes 1 positional argument but 3 [...]

Python — динамический интерпретируемый язык.

$ cat ./hello.py
message= "Hello, world!"
$ python -m dis ./hello.py
  0 LOAD_CONST0 ('Hello, world!')
  3 STORE_NAME0 (message)
  6 LOAD_CONST1 (None)
  9 RETURN_VALUE

Интерпретаторы

Идеи

Файл, модуль, пространство имен

>>> import hello
>>> hello
<module 'hello' from '[...]/hello.py'>
>>> dir(hello)
['__builtins__', '__cached__', '__doc__', '__file__','__loader__', '__name__', '__package__', '__spec__','message']
>>> hello.__name__, hello.__file__
('hello', '[...]/hello.py')
>>> print(hello.message)
"Hello, world!"

Отступы вместо скобочек

>>> while True:
... print(42)
  File "<stdin>", line 2
    print(42)
        ^
IndentationError: expected an indented block

Всё есть объект

>>> import hello
>>> type(hello)
<class 'module'>
>>> type(type(hello))
<class 'type'>
>>>type(type(type(hello)))
<class 'type'>

Встроенные типы

None

>>> None               # аналог null, но полноценный объект
>>> res = print(None)  # любая функция возвращает значение
None
>>> res == None        # неделайте так
True
>>> res is None        # делайте лучше так
True
>>> id(res)            # в CPython -- адрес
140503861261072
>>> id(None)
140503861261072

bool

>>> to_be = False
>>> to_be ornot to_be        # слова вместо значков
True
>>> x = 1
>>> y = 2
>>> x**2 + y**2 < 5 == True  # True синглтон, не делайте так
False
>>> x**2 + y**2 < 5 is True  # но и так тоже не делайте
False
>>> x**2 + y**2 < 5
False

bool

>>> False and print('also')      # short-circuiting!
False
>>> res = True and print('also')
also
>>> assert res is None, "print should return None"
>>> False or 92                  # работает с любым значением
92

assert

>>> x = 100
>>> y = 3
>>> assert x % y == 0, (x, y)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: (100, 3)

Number

>>> True + False + True  # bool тоже числа
2
>>> 0
0
>>> 2**128               # сколько угодно знаков
340282366920938463463374607431768211456
>>> 1.0                  # double
1.0
>>> float('inf')
inf
>>> int('92')
>>> 92
>>> 90 + 2j              # комплексные числа тоже есть
(90+2j)

Number

>>> 3 / 2    # вещественное деление
1.5
>>> 4 / 2
2.0
>>> 4 // 2   # деление состатком
2
>>> 3 // 2
1
>>> -3 // 2  # как в алгебре!
-2
>>> -1 % 3   # С/Java/Rust скажут -1
2

Number

>>> x = 10
>>> 0 <= x and x < 100
True
>>> 0 <= x < 100
True

list

>>> []
[]
>>> xs = [1, 2, 3,]
>>> len(xs)
3
>>> xs[0]
1
>>> xs[0] = 0
>>> xs
[0, 2, 3]

list

>>> xs = [1, 2] * 3
>>> xs
[1, 2, 1, 2, 1, 2]
>>> xs = [[0] * 3] * 3  # не делайте так
>>> xs[0][0] = 1
>>> xs
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]  # :-(

list

>>> [1] + [2, 3] + [4]  # O(?)
[1, 2, 3, 4]
>>> xs = [1, 2, 3]
>>> xs.append(4)        # O(?)
>>> xs
[1, 2, 3, 4]
>>> xs.pop()            # O(?)
4
>>> xs
[1, 2, 3]
>>> xs.pop(0)           # O(?)
1
>>> xs
[2, 3]
>>> xs.insert(0, 92)    # O(?)
>>> xs
[92, 2, 3]
>>> xs += [1]           # так делать не стоит
>>> xs
[92, 2, 3, 1]

slices

>>> xs = list(range(5))
>>> xs
[0, 1, 2, 3, 4]
>>> xs[len(xs) - 1]
4
>>> xs[-1]
4
>>> xs[2:4]
[2, 3]
>>> xs[:-2]
[0, 1, 2]
>>> xs[::2]
[0, 2, 4]

slices

>>> y = xs[:]  # или y = list(xs)
>>> y[0] = 92
>>> y
[92, 1, 2, 3, 4]
>>> xs
[0, 1, 2, 3, 4]

slices, weird edition

>>> xs[:100]  # слайс может выходить за границу
[0, 1, 2, 3, 4]
>>> xs[100]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
>>> xs[1:-1:2] = [None] * 2  # работает присваивание
>>> xs
[0, None, 2, None, 4]
>>> every_second = slice(None, None, 2)
>>> list(range(10))[every_second]
[0, 2, 4, 6, 8]

str

>>> s = "hello"  # 'hello'
>>> len(s)
5
>>> s[:-1]
'hell'
>>> s[0]
'h'
>>> s[1] = "i"   # в отличие от списков, строки не изменяемы
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  TypeError: 'str' object does not support item assignment
>>> "<>" + "." * 8 + "<"
'<>........<'

str

>>> "hello \nworld".splitlines()  # разбить на строчки
['hello ', 'world']
>>> "a b  c".split()              # на слова
['a', 'b', 'c']
>>> "\thello ".strip()            # убрать пробелы
'hello'
>>> ", ".join(["a", "b", "c"])    # соединить список строк
'a, b, c'                         # через разделитель
>>> str(42)
'42'

str

>>> foo = 42
>>> "foo = %s" % foo             # %-оператор (old style)
'foo = 42'
>>> "foo = {}".format(foo)       # str.format (new style)
'foo = 42'
>>> f"foo = {foo}"               # f-Strings (+3.6)
'foo = 42'
>>> 
>>> a = 10
>>> b = 117
>>> f"{a:<4}: foo\n{b:<4}: bar"  # выравнивание
10  : foo
117 : bar
>>> f"{a:+^12}"                  # padding
'+++++10+++++'

tuple

>>> date = ("September", 2018)
>>> len(date)                    # API, каку списка
2
>>> date[1] = 2019               # но менять нельзя
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> xs = ([], [])
>>> xs[0].extend([1, 2, 3])
>>> xs([1, 2, 3], [])

tuple

>>> ()                           # пустой кортеж
()
>>> 1
1
>>> (1, )                        # кортеж из одного элемента
(1,)
>>> date = "September", 2018     # скобки опциональны
>>> date
('September', 2018)

tuple

>>> def div_mod(x, y):
...     return x // y, x % y
... 
>>> d, m = div_mod(10, 3)
>>> assert (d, m) == (3, 1)

set

>>> xs = {1, 2, 3}  # множество (hash set)
>>> 1 in xs
True
>>> 92 not in xs
True
>>> xs.add(1)
>>> xs.add(92)
>>> xs
{1, 2, 3, 92}       # в множестве нет повторений
>>> set()           # для пустого множества нет литерала
set()
>>> 1 in [1, 2, 3]  # O(?)
True
>>> "world" in "hello, world"
True

set

>>> {1, 2, 3}.union({3, 4, 5})  # или |
{1, 2, 3, 4, 5}
>>> {1, 2, 3} & {3, 4, 5}       # или .intersection
{3}
>>> {1, 2, 3} ^ {3, 4, 5}       # или .symmetric_difference
{1, 2, 4, 5}
>>> xs = {1, 2, 3}
>>> xs.discard(2)      # в реальной жизни операция удаления
>>> xs                 # -- редкая
{1, 3}

set

>>> xs = set()
>>> xs.add([])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

dict

>>> date = {"year": 2018, "month": "September"}
>>> len(date)
2
>>> date["year"]         # KeyError еслик лючанет,
2018                     # в отличие от Java
>>> date.get("day", 14)  # Значение поумолчанию
14
>>> date["day"] = 14
>>> date.pop("year")
2018

dict

>>> date.keys()
dict_keys(['month', 'day'])     # set
>>> date.values()
dict_values(['September', 14])  # не set
>>> date.items()                # set!
dict_items([('month', 'September'), ('day', 14)])

dict

>>> date.items() | {1: 2}.items()
{('day', 14), ('month', 'September'), (1, 2)}
>>> date.items() | {1: []}.items()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

dict

>>> 'day' in date.keys()  # плохо!
True
>>> 'day' in date
True

dict

>>> d = {}
>>> d["a"] = 1
>>> d["b"] = 2
>>> d["c"] = 3
>>> list(d.keys())
['a', 'b', 'c']     # порядок гарантируется
  • None;
  • True, False;
  • int, float, complex;
  • str;
  • list, set, dict, tuple.

 

- одинаковый API для похожих типов.

- могущественные операции.

- не надо ничего изобретать, нужно брать и программировать

 

Документация:

https://docs.python.org/3/library/stdtypes.html

Резюме

Выражения

if

if 0 <= n and n < len(xs):
    print(xs[n])

ternary if

x = 50
y = 25
small = x if x < y else y
# int small = x < y ? x : y;

if

# :( :( :(
if x[0] < 100 and x[1] > 100 and (is_full_moon() or not is_thursday()) and user.is_admin:
    pass

if

# >:(
if x[0] < 100 and x[1] > 100
    and (is_full_moon() or not is_thursday())
    and user.is_admin:
    pass

if

# :( :( :(
if x[0] < 100 and x[1] > 100 \
    and (is_full_moon() or not is_thursday()) \
    and user.is_admin:
    pass

if

# :( :(
if (x[0] < 100 and x[1] > 100
    and (is_full_moon() or not is_thursday())
    and user.is_admin):
    pass

if

# :|
value_in_range = x[0] < 100 and x[1] > 100
good_date = is_full_moon() or not is_thursday()
if value_in_range and good_date and user.is_admin:
    pass

while

i = 0
while i < 4:
    i += 1
i

Truthy/Falsy

>>> bool(True)
True
>>> bool(0)
False
>>> bool(1)
True
>>> bool([])
False
>>> bool([0])
True

Truthy/Falsy

(False,             # Falsy!
 None,
 0, 0.0, 0j,
 "", [], (), set(), {})

Truthy/Falsy

if len(xs) == 0: # плохо!
    pass

if xs:
    pass

if not xs:
    pass

for

for x in [1, 2, 3]:
    print(x)

for line in open("./HBA1.txt"):  # как правильно
    pass                         # -- вследующих сериях

for ch in "foobar":
    pass

for

for i in range(10):
    print(x)

for i in range(2, 10, 3):
    print(x)

for i in range(9, -1, -1):     # :(
    print(x)

for i in reversed(range(10)):  # :)
    print(x)

for i in reversed("hello"):
    print(x)

for i in reversed([1, 2, 3]):
    print(x)

break

target = 92
for item in items:
    if item == target:
        print("Found!", item)
        break

break

target = 92
for item in items:
    if item == target:
        print("Found!", item)
        break
print("Not found")  # :( 

break

target = 92
found = False  # :( :( :(
for item in items:
    if item == target:
        print("Found!", item)
        found = True
        break
if not found:
    print("Not found")

break

target = 92
for item in items:
    if item == target:
        print("Found!", item)
        break
else:
    print("Not found")

continue

target = 92
res = []
for item in items:
    if item != target:
        continue
    res.append(item)
  • Нет C-style for
  • Итерироваться можно по всему
  • else к for и while

 

Документация:

https://docs.python.org/3/reference/compound_stmts.html

Резюме

PEP 8

  • PEP 8 содержит стилистические рекомендации по оформлению кода на Python.
  • Базовые рекомендации:
    • 4 пробела для отступов;
    • длина строки не более 79 символов для кода и не более 72 символов для документации и комментариев;
    • lower_case_with_underscores  для переменных и имен функций, UPPER_CASE_WITH_UNDERSCORES для констант.

PEP 8: базовые рекомендации

  • Унарные операции без пробелов, бинарные с одним пробелом с обеих сторон

PEP 8: выражения

exp = -1.05
value = (item_value / item_count) * offset / exp
  • Для списков или кортежей с большим количеством элементов используйте перенос сразу после запятой
tems = [
    'this is the first', 'set of items',
    'with more items', 'to come in this line',
    'like this'
]
  • Не пишите тело оператора на одной строке с одним оператором

PEP 8: операторы (1)

if bar: x += 1             # Плохо
while bar: do_something()  # Плохо

if bar:                    # Лучше
    x += 1
while bar:                 # Лучше
    do_domething()
  • Не используйте Йода-сравнения в if и while
if 'md5' == method:        # Плохо
    pass

if method == 'md5':        # Лучше
    pass

Для сравнения на равенство

  • объектов используйте операторы == и !=,
  • синглтонов используйте is и is not,
  • булевых значений используйте сам объект или оператор not, например

 

PEP 8: операторы (2)

  • Проверяйте отсутствие элемента в словаре с помощью оператора not in
if foo:                  while not bar:
    # ...                    # ...
if not key in d:  # Плохо
if key not in d:  # Лучше
  • Не используйте пробелы до или после скобок при объявлении и вызове функции

PEP 8: функции

  • Документируйте функции следующим образом
def foo (x, y):  # Плохо
    pass

foo( 42, 24 )    # Плохо
def something_useful(arg, **options):
    """One-line summary.
    
    Optional longer description of the function
    behaviour.
    """
  • Разделяйте определения функций двумя пустыми строками.

Q & A

Made with Slides.com