Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@deniskrumko
Created April 4, 2019 10:20
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save deniskrumko/6c18d61bcddc972bfe82c5676d285371 to your computer and use it in GitHub Desktop.
Save deniskrumko/6c18d61bcddc972bfe82c5676d285371 to your computer and use it in GitHub Desktop.
Python things

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


Можно присвоить значение одной функции - другой функции

foo.__code__ = bar.__code__

Дизассемблирование кода

python -m dis hello.py

None & NoneType

None - это объект NoneType, и есть только один инстанс, т.е. это синглтон.


Оператор or - ленивый

Если левая часть истина - то правая даже не будет вычисляться.


Слайсы с шагом

>>> s = '1234567890'
>>> s[::2]
'13579'

Для проверки наличия в словаре - можно не писать keys()

>>> d = {'a': 1}
>>> 'a' in d.keys()
True
>>> 'a' in d
True

При распаковке словаря в словаре происходит подмена значений!

>>> a = {'name': 'Denis', 'surname': 'Krumko'}
>>> {**a, 'name': 'Blablabla'}
{'name': 'Blablabla', 'surname': 'Krumko'}

Область видимости - LEGB

min                ## (B)uilitins
min = 42           ## (G)lobal

def f(*args):
    min = 2
    def g():       ## (E)nclosing
        min = 4    ## (L)ocal
        print(min)

Для присваивания - сложнее. Всегда берется локальная видимость. Но для этого есть операторы global и nonlocal.


Как выразить zip через map ?

a = '123'
b = 'abc'
c = 'xyz'
zip(a, b, c)
map(lambda *args: args, a, b, c)

functools.singledispatch - декоратор для изменения поведения для типов

@functools.singledispatch
def pack(obj):
    ## Поведение по умолчанию
    pass

@pack.register(int)
def _(obj):
    ## Поведение для int
    pass

lstrip, rstrip, strip - принимают строки элементов которые нужно удалить

>>> 'axxxaxabcx'.lstrip('xa')  ## 'x' и 'a' удаляются независимо а не слитно
'bcx'

split - может не принимать аргумент или принимать количество разрезов

  • без аргументов идет разрез по пробельному символу
  • любое кол-во пробельных символов - это 1 символ
>>> '\t  \n  foo  bar \n'.split()
['foo', 'bar']
  • а второй аргумент - это кол-во разрезов
  • если указать их хоть 1000 - ошибки тут не будет
>>> 'foo.bar.tz'.split('.', 1)
['foo', 'bar.tz']

А вот так легко получить расширение

>>> 'foo.bar.tz'.rsplit('.', 1)
['foo.bar', 'tz']

Метод partition возвращает кортеж из трех элементов

  • до разделителя, разделитель, после разделителя
>>> 'foo.bar.tz'.partition('.')
('foo', '.', 'bar.tz')

>>> 'foo.bar.tz'.rpartition('.')
('foo.bar', '.', 'tz')

startswith и endswith могут принимать кортеж!

>>> 'foobar'.endswith(('bar', 'baz'))
True

>>> 'foobar'.startswith(('hey', 'man'))
False

find и index - для поиска позиции в строке

  • find - возвращает или позицию или -1
  • index - кидает ValueError если не была найдена позиция
  • могут принимать 2 и 3 аргументы для обозначения позиции, будет работать как 'abracadabra'[0:3].find('ra')
  • для поиска справа есть rfind и rindex
>>> 'abracadabra'.find('ra')
2

>>> 'abracadabra'.find('ra', 0, 3)
-1

>>> 'abracadabra'.find('x')
-1

>>> 'abracadabra'.index('x')
ValueError: substring not found

replace может принимать кол-во замен

  • замены все еще идут слева направо
>>> 'abracadabra'.replace('ra', 'XX')
'abXXcadabXX'

>>> 'abracadabra'.replace('ra', 'XX', 1)
'abXXcadabra'

translate - для замены по словарю замен

  • но принимает не символы, а КОД символа (ЧТО ВАЩЕ ЗАЧЕМ)
>>> translation_map = {ord('a'): '*', ord('b'): '?'}

>>> 'abracadabra'.translate(translation_map)
'*?r*c*d*?r*'

TODO: Реализовать синглтон декораторк класса или просто класс


Функция round - работает как банковское округление!

>>> round(1.5) == round(2.5)
True

Потому что "rounding is done toward the even choice".


Чему будут равны x и y ?

>>> x = [[1, 2, 3]] * 2
>>> y = [[1, 2, 3] for i in range(2)]

>>> x[0][1] = 200
>>> y[0][1] = 200

>>> x
[[1, 200, 3], [1, 200, 3]]

>>> y
[[1, 200, 3], [1, 2, 3]]

Когда мы "умножаем" список, то мы делаем ссылки на один и тот же объект. НО объекты должны быть mutable, типа списка.


Что вернет дважды вызванный append без аргументов?

>>> def append(x=[]):
        x.append(len(x))
        return x

>>> append(['a', 'b'])
['a', 'b', 2]

>>> append()
[0]  # тут мы записали в x значение 0
>>> append()
[0, 1]  # тут в x остался 0, т.е. длина == 1, поэтому добавили 1

Вывод: не объявлять в kwargs mutable элементы, типа списков.


Что выведет print ?

>>> x = [lambda: i for i in range(3)]
>>> print(x[0]())
2
>>> print(x[1]())
2

Может быть будет проще понять: [lambda: i for i in range(3)] --> [(lambda: i) for i in range(3)]

lambda: i возвращает значение i. В конце цикла i будет равняться 2. Поэтому все три элемента в x условно возвращают lambda: 2, что по факту просто 2.


Чему будет равно выражение

>>> sum({1: 1, 2: 2, 1.0: 3}.values())
5

Вызов {1: 1, 2: 2, 1.0: 3} преобразуется в {1: 3, 2: 2}.


Как происходит доступ к атрибуту класса. Где он хранится?

class C:
    name = 'abc'

>>> C().name
'abc'
>>> C.name
'abc'
>> C.__dict__['name']
'abc'

Но если объявить private attrubute...

class C:
    __secret = 'found it!'

    def p(self):
        return self.__secret

    def x(self):
        return self._C__secret

>>> C().__secret
AttributeError
>>> C.__secret
AttributeError
>> C.__dict__['__secret']
KeyError

>>> C._C__secret
'found it!'
>> C.__dict__['_C__secret']
'found it!'
>>> C().p()
'found it!'
>>> C().x()
'found it!'

Напишите реализацию декоратора

@multiply(5)
def function(foo):
    return foo

>>> function(2)
10

Ответ:

def multiply(x):
    def decorator(f):
        def wrap(*args, **kwargs):
            return f(*args, **kwargs) * x
        return wrap
    return decorator

или через Class based decorator:

class multiply:
    def __init__(self, x):
        self.x = x

    def __call__(self, f):
        def decorated(*args, **kwargs):
            return f(*args, **kwargs) * self.x
        return decorated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment