Skip to content

Latest commit

 

History

History
305 lines (240 loc) · 5.37 KB

File metadata and controls

305 lines (240 loc) · 5.37 KB

Infinity in python

max_val = float("inf")
min_val = float("-inf")

FUNCTIONS

At least one argument

def min(first, *args):
    res = first
    ...

Unpacking

xs = {-5, 12, 13}
min(*xs)
min(*[-5, 12, 13])
min(*(-5, 12, 13))

Default argument value init-ing only once, at the moment of bytecode compiling

def unique(iterable, seen=set()): # BAD!!
    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.__defaults__  # ({1, 2, 3}, )

Fix for example before

def unique(iterable, seen=None):    # Nice!
    seen = set(seen or [])
    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" values

bool(0) # False
bool(0.0) # False
bool("") # False
bool([]) # False
bool({}) # False
bool(tuple()) # False
bool(None) # False
...

Arguments, Key-word Arguments

pass

Packing (catching), lol

first, *rest = range(1,5)
print(first, rest)  # (1, [2, 3, 4])

*rest, last = range(1,5)
print(rest, last)  # ([1, 2, 3], 5)

first, *rest, last = range(1,5)
print(first, rest, last)  # (1, [2, 3], 5)

# ================================

for a, *b in [range(4), range(2)]:
    print(b)
# [1, 2, 3]
# [1]

Module "dis" shows interpreter's instructions

import dis

dis.dis('first, *rest, last = (1, 2, 3)')
#   1           0 LOAD_CONST               0 ((1, 2, 3))
#              2 EXTENDED_ARG             1
#              4 UNPACK_EX              257
#              6 STORE_NAME               0 (first)
#              8 STORE_NAME               1 (rest)
#             10 STORE_NAME               2 (last)
#             12 LOAD_CONST               1 (None)
#             14 RETURN_VALUE

Instructions executing from right to left

x, (x, y) = 1, (2, 3)
print(x)    # 2

Object of first class????

Namespaces and Scope in Python (Области видимости)

def make_min(*, lo, hi):
    def inner(first, *args):
        res = hi
        for arg in (first, ) + args:
            if arg < res and lo < arg < hi:
                res = arg
        return max(res, lo)
    return inner

bounded_min = make_min(lo=0, hi=255)
bounded_min(-5, 12, 13)  # 0
min             # builtin <built-in function min>
min = 42        # global

def f(*args):
    min = 2     # enclosing
    def g():
        min = 4 # local
        print(min)

# LEGB
#
# При обращении к переменной он ищет снизу вверх
# local -> enclosing -> global -> builtin
#
# подф. -> функ -> модуль -> интерпретатор
#

print(globals())
def f():
    min = 2
    print(locals())

Names searching is dynamic process

def f():
    print(i)

for i in range(4):
    f()

# 0
# 1
# 2
# 3

You can take global var, but don't change it

min = 42
def f():
    min += 1
    return min

f() # UnboundLocalError: ....

# =============================
min = 42
def f():
    global min # this works
    min += 1
    return min

Nonlocal (looks wired)

def cell(value=None):
    def get():
        return value
    def set(update):
        nonlocal value
        value = update
    return get, set

get, set = cell()
set(42)
get()   # 42

Functional programming

Higher-order functions

lambda arguments: expression
def <lambda>(arguments):
    return expresion
list(
    map(lambda x: str(x), range(4))
) # ['0', '1', '2', '3']
map(lambda s: s.strip(), open("./file.txt"))
list(
    map(
        lambda x, y: x ** y,
        [2, 3], range(1,8)
    )
)   # [2, 9]
# [2 ** 1, 3 ** 2]

filter

xs = [0, None, [], {}, set(), "", 42]
list(filter(None, xs)) # [42]
# если инструкции нет, то просто сами элементы проверяются на истинность

ZIP из MAP

a = (1, 2, 3)
b = (6, 6, 6)
c = (3, 2, 1)

list(
    zip(a, b, c)
)   # [(1, 6, 3), (2, 6, 2), (3, 6, 1)]

list(
    map(lambda *args: args, a, b, c)
)   # [(1, 6, 3), (2, 6, 2), (3, 6, 1)]

# Ибо из-за *args он распаковывает полученные картежи
# Т.е. для превой итерации везде берет по первому элементу,
# для второй по второму итд
# 
# А может и нет xD

Generators with Predicates

[x ** 2 for x in range(10) if x % 2 == 1]
#  [1, 9, 25, 49, 81]

# пришел на замену
list(
    map(
        lambda x: x ** 2,
        filter(
            lambda x: x % 2 == 1,
            range(10)
        )
    )
)

is

x = 10

if x is 10:
    # DO NOT DO THIT!
    # "is" checking objects by reference, and small integers just have same reference
    
    
    # ТАК ПИСАТь НЕ НАДО ибо сравнение происходит по ссылке
    # и если для маленьких чисел это отработает гладко, то для больших нет

if x == 10:
    # do this!