Skip to content
Etsu edited this page Oct 3, 2017 · 42 revisions

Dict to string

''.join('{}{}'.format(key, val) for key, val in adict.items())

Magic to transform string representation of a Dictionary to a dictionary

string = ast.literal_eval(string)
assert type(new_dict) is dict

Read multiple parameters from console

def main():
    a, b = map(int, input().split())
    res = a + b
    print(res)


if __name__ == "__main__":
    main()

Which BLAS we use in out numpy and spark

import numpy as np
np.show_config()

Classes

class Song:
    def __init__(self, artist, song):
        self.artist = artist
        self.song = song
        self.tags = []


    def add_tags(self, *args):
        self.tags.extend(args)


song1 = Song("artist_name1", "song_name2")
song1.add_tags("tag1", "tag2")

song2 = Song("artist_name3", "song_name4")
song2.add_tags("tag3", "tag4")

song2.tags
class MoneyBox:
    def __init__(self, capacity):
        self.capacity = capacity
        self.value = 0

    def can_add(self, v):
        if (v <= (self.capacity - self.value)):
            return True
        else:
            return False

    def add(self, v):
        self.value = self.value + v

Check instance

isinstance(x,y)

Check class

type()

Unit-test

import unittest

class TestStringMethods(unittest.TestCase):

  def test_upper(self):
      self.assertEqual('foo'.upper(), 'FOO')

  def test_isupper(self):
      self.assertTrue('FOO'.isupper())
      self.assertFalse('Foo'.isupper())

  def test_split(self):
      s = 'hello world'
      self.assertEqual(s.split(), ['hello', 'world'])
      # Проверим, что s.split не работает, если разделитель - не строка
      with self.assertRaises(TypeError):
          s.split(2)

if __name__ == '__main__':
    unittest.main()

Функции

Синтаксис объявления функций

# return использовать не обязательно, функция вернёт None

# Для документации функции используются строковые литералы
>>> def foo():
...     """I return 42."""
...     return 42
...

# После объявлении функции документация доступна через определённый атрибут
>>> foo.__doc__
'I return 42.'

# В интерпретаторе удобнее пользоваться встроенной функцией
>>> help(foo)  # или foo? в IPython.

Улучшение функции min()

>>> def min(x, y):                #    __o
...     return x if x < y else y  #  _`\<,_
...                               # (_)/ (_)

# 1. Находить минимум произвольного количества аргументов
>>> min(-5, 12, 13)
-5

# 2. Использовать функцию min для кортежей, списков, множеств и других последовательностей 
>>> xs = {-5, 12, 13}
>>> min(???)
-5

# 3. Ограничить минимум произвольным отрезком [lo, hi]
>>> bounded_min(-5, 12, 13, lo=0, hi=255)
12

# 4. По заданным lo и hi строить функцию bounded_min (фабрика функций)
>>> bounded_min = make_min(lo=0, hi=255)
>>> bounded_min(-5, 12, 13)
12

Упаковка агрументов

# 1.a
def min(*args):  # type(args) == tuple
    res = float("inf")  # инициализируем бесконечностью
    for arg in args:
        if arg < res:
            res = arg
        return res

# >>> min(-5, 12, 13)
# -5

# >>> min()
# inf
1.b
def min(first, *args):
    res = first
    # ...

# min()
# TypeError: min() missing 1 required [...] argument: 'first'

Распаковка аргументов

# 2.a
# Синтаксис будет работать с любым объектом, поддерживающим протокол итератора
# Итератор - что-то, что можно обойти

>> xs = {-5, 12, 13}  # но вообще set лучше не юзать
>>> min(*xs)  # здесь он не критичен, но вообще, распаковывать set - странная идея
-5

>>> min(*[-5, 12, 13])
-5

>>> min(*(-5, 12, 13))
-5
...

Ключевые аргументы: аргументы по умолчанию

# 3.a
def bounded_min(first, *args, lo=float("-inf"),
                hi=float("inf")):
    res = hi
    # итерируемся по первому элементу + всё остальное
    for arg in (first, ) + args:  # args - это кортеж, 
                                  # соответственно fisrt тоже надо превратить к кортеж :)
        if arg < res and lo < arg < hi:
            res = arg
    return max(res, lo)

# >>> bounded_min(-5, 12, 13, lo=0, hi=255)
# 12

Ключевые элементы: подводные камни

# Нужно было написать функцию, которая принимает что-то, 
# по чему можно итерироваться и возвращает список уникальных элементов
def unique(iterable, seen=set()):
    acc = []
    for item in iterable:
        if item not in seen:
            seen.add(item)
            acc.append(item)
    return acc

# >>> xs = [1, 1, 2, 3]
# >>> unique(xs)
# [1, 2, 3]

# >>> unique(xs)
# []
# Так происходит, потому что значение по умолчанию инициализируется ровно один раз -
#                                                   - в момент компиляции в байт-код
# Т.е. все вызовы unique() будут различать значения атрибута seen
# Вывод: никогда не использовать изменяемые значения в качестве значений по умолчанию
# (никакие списки, никакие словари)

# Атрибут __defaults__ - кортеж с инициализированными значениями элементов по умолчанию
# >>> unique.__defaults__
# ({1, 2, 3},)

Ключевые элементы: правильная инициализация

def unique(iterable, seen=None):  # None не изменяемый, потому что он Singleton
    seen = set(seen or [])  # None --- falsy. 
    # Поэтому если аргумент=None, то он станет пустым списком
    # OR подразумевает операции над булевыми переменными,
    #                        поэтому, если они не булевы, 
    #                        то он попытается их привести к таковым
    # А если первая штука truesy, то мы берём её значение
    
    acc = []
    for item in iterable:
        if item not in seen:
            seen.add(item)
            acc.append(item)
    return acc


# >>> xs = [1, 1, 2, 3]
# >>> unique(xs)
# [1, 2, 3]

# >>> unique(xs)
# [1, 2, 3]

Falsy:

None
0
0,00
""
[] () {}
set()

Ключевые аргуенты: и только ключевые

# Если функция имеет фиксированную арность, 
# то ключевые агрументы можно передавать без явного указания имени:
>>> def flatten(xs, depth=None):
...     pass
...
>>> flatten([1, [2], 3], depth=1)
>>> flatten([1, [2], 3], 1)

# Можно явно потребовать, чтобы часть аргументов всегда передавалась как ключевые:
>>> def flatten(xs, *, depth=None):  # звёздочка всё кушает и не связывает это с именем
# Всё, что идёт после звёздочки - ключевые аргументы
...     pass
...
>>> flatten([1, [2], 3], 2)
TypeError: flatten() takes 1 positional argument [...]

Ключевые аргументы: упаковка и распаковка

def runner(cmd, **kwargs):
    if kwargs.get("verbose", True):
        print("Logging enabled")

>>> runner("mysqld", limit=42)
Logging enabled
>>> runner("mysqld", **{"verbose": False})
>>> options = {"verbose": False}
>>> runner("mysqld", **options)

Упаковка и распаковка

# Присваивание
acc = []
seen = set()
(acc, seen) = ([], set())

# В качестве правого объекта можно использовать любой объект,
# поддерживающий протокол итератора
x, y, z = [1, 2, 3]
x, y, z = {1, 2, 3}  # unordered
x, y, z = "xyz"
x, y = y, x  # по сути справа - tuple (y, x)

# Скобки обычно опускают, но иногда они бывают полезны
rectangle = (0, 0), (4, 4)
(x1, y1), (x2, y2) = rectangle

Расширенный синтаксис распаковки

# В Python 3.0 можно юзать * (что-то мы распакуем, а что-то обратно запакуем)
# rest всегда приводится к списку и копирует то, что справа
>>> first, *rest = range(1, 5)
>>> first, rest
(1, [2, 3, 4])

# * можно использовать в любом месте приложения
>>> first, *rest, last = range(1, 5)
>>> last
4

>>> first, *rest, last = [42]
ValueError: need more than 1 values to unpack

# Работает рекурсивно тоже
>>> *_, (first, *rest) = [range(1, 5)] * 5
>>> fisrt
1

https://www.python.org/dev/peps/pep-3132/

Распаковка и цикл for

# Синтаксис распаковки работает и в цикле for, например:
for a, *b in [range(4), range(2)]:
    print(b)

# [1, 2, 3]
# [1]

Распаковка и байткод

>>> import dis
>>> dis.dis("first, *rest, last = ('a', 'b', 'c')")
     0 LOAD_CONST               4 (('a', 'b', 'c'))
     3 UNPACK_EX              257
     6 STORE_NAME               0 (first)
     9 STORE_NAME               1 (rest)
    12 STORE_NAME               2 (last)
    15 LOAD_CONST               3 (None)
    18 RETURN_VALUE
# Мораль: присваивание в Python работает слева-направо
>>> x, (x, y) = 1, (2, 3)  # не надо так писать :)
>>> x
2
>>> dis.dis("first, *rest, last = ['a', 'b', 'c']")
     0 LOAD_CONST               0 (1)
     3 LOAD_CONST               1 (2)
     6 LOAD_CONST               2 (3)
     9 BUILD_LIST               3
    12 UNPACK_EX              257
    15 STORE_NAME               0 (first)
    18 STORE_NAME               1 (rest)
    21 STORE_NAME               2 (last)
    24 LOAD_CONST               3 (None)
    27 RETURN_VALUE
# Мораль: Синтаксически схожие конструкции могут 
#         иметь различную семантику времени исполнения

Упаковка и распаковка: резюме

# Функции в Python могут принимать произвольное количество
# позиционных и ключевых аргументов

# Для объявления таких функций используется синтаксис упаковки,
# а для вызова синтаксис распаковки
>>> def f(*args, **kwargs):
...     pass
...
>>> f(1, 2, 3, **{"foo":42})

# Синтаксис распаковки также можно использовать при присваивании
# нескольких аргументов в цикле for:
>>> first, *rest = range(4)
>>> for first, *rest in [range(4), range(2)]:
...     pass
...
Clone this wiki locally