ru
Feedback
Hello World

Hello World

Открыть в Telegram

Подписывается челик на канал, а он ему как раз 🎩 По рекламе: @my_little_trump

Больше
2 456
Подписчики
Нет данных24 часа
Нет данных7 дней
Нет данных30 день
Архив постов
Memoization part 3. И напоследок, в стандартной библиотеке functools уже отлично реализован подобный декоратор, который называется lru_cache. LRU расшифровывается как Least Recently Used.
from functools import lru_cache

@clock
@lru_cache()
def fib(n):
    if n < 2:
        return n
    return fib(n-2) + fib(n-1)

print('fib(20) =', fib(20))
lru_cache имеет два необязательных аргумента: 📌 maxsize — это количество хранимых результатов. 📌 typed — при равном true, например, значения 1 и 1.0 будут считаться разными (поскольку это разные типы). 📎 Мемоизация довольно простая и эффективная практика. А благодаря functools.lru_cache, ей удобно пользоваться в Python. #lru #memoization

Memoization part 2. Декоратор clock выглядит так:
def clock(func):
    def clocked(*args, **kwargs):
        t0 = time.time() # начальное время
        result = func(*args, **kwargs)
        elapsed = time.time() - t0 # конечное время
        arg_1st = []

        if args:
            arg_1st.append(', '.join(repr(arg) for arg in args))
        if kwargs:
            pairs = ['%s=%r' % (k, w) for k, w in sorted(kwargs.items())]
            arg_1st.append(', '.join(pairs))

        arg_str = ', '.join(arg_1st)

        print(f'[{elapsed}s] {func.__name__}({arg_str}) -> {result}')
        return result
    return clocked
Засекаем время выполнения нашей функции, а дальше просто выводим это в красивый принт. Не забудьте импортировать модуль time. Для memoize напишем следующую функцию:
def memoize(f):
    cache = {}

    def decorate(*args):
        if args in cache:
            return cache[args]
        else:
            cache[args] = f(*args)
            return cache[args]
    return decorate
Или через лямбду:
def memoize(f):
    cache = {}
    return lambda *args: cache[args] if args in cache else cache.update({args: f(*args)}) or cache[args]
Таким образом:
@memoize
@clock
def fib(n):
    if n < 2:
        return n
    return fib(n-2) + fib(n-1)

print('fib(200) =', fib(200))
Out [0]: [0.0035719871520996094s] fib(200) -> 280571172992510140037611932413038677189525

Memoization. ➖Это способ оптимизации, при котором сохраняется результат выполнения функции и этот результат используется при следующем вызове. Возьмем рекурсивную реализацию нахождения числа Фибоначчи и посмотрим на время выполнения.
@clock
def fib(n):
    if n < 2:
        return n
    return fib(n-2) + fib(n-1)

print('fib(20) =', fib(20))
Out [0]: [0.22741317749023438s] fib(20) -> 6765
➖При увеличении числа, время работы алгоритма будет очень быстро расти, плюс возможна ошибка RecursionError. ➖Для оптимизации подобного алгоритма хорошо подходит метод мемоизации, то есть сохранение и повторное использования ранее вычисленных значений.
_fib_cache = {1: 1, 2: 1}  # ключ - номер числа, значение - число Фибоначчи 

@clock
def mem_fib(n):
    result = _fib_cache.get(n)
    if result is None:
        result = mem_fib(n-2) + mem_fib(n-1)
        _fib_cache[n] = result
    return result

print('mem_fib(200) =', mem_fib(200))
Out [0]: [0.011016845703125s] mem_fib(200) -> 280571172992510140037611932413038677189525
В следующем посте разберем декоратор @clock, а также декорирование самой мемоизации.

Dict. Пара коротких заметок по поводу словарей. 📌 Для того, чтобы взять “срез” словаря, можно поступить так:
import itertools

m_dict = {‘1’:’1’, ‘2’:’2’, ‘3’:’3’, ‘4’:’4’, ‘5’:’5’}
m_dict = dict(itertools.islice(m_dict.items(), 3))
Out[0]: {‘1’:’1’, ‘2’:’2’, ‘3’:’3’}
📌 Для того, чтобы сложить два словаря:
m_dict1 = {‘1’:’1’, ‘2’:’2’}
m_dict2 = {‘3’:’3’, ‘4’:’4’}
m_dict = dict(m_dict1, **m_dict2)
Out[0]: {‘1’:’1’, ‘2’:’2’, ‘3’:’3’, ‘4’:’4’}
P.S. Если будете копировать, поправьте кавычки. Телеграм их исправляет на нечитаемые python-ом. #dict

Bare * asterisk В Python 3 можно использовать оператор * в списках параметров функции, чтобы наверняка использовать keyword аргументы.
>>> def f(a, b, *, c='x', d='y', e='z'):
...     return 'Hello'
То есть, мы должны прямо указать именованые параметры в виде key=value.
>>> f(1, 2, 'p', 'q', 'v')
TypeError: 
"f() takes 2 positional arguments but 5 were given"
>>> f(1, 2, c='p', d='q',e='v')
'Hello’
#bareasterisk

photo content

# Способы проверки того, что # все элементы списка одинаковы:
>>> lst = ['a', 'a', 'a']
>>> len(set(lst)) == 1
True
>>> all(x == lst[0] for x in lst)
True
>>> lst.count(lst[0]) == len(lst)
True
# Способы расположены от “most pythonic”, к “least pythonic” # и от менее эффективных, до более эффективных. # Решение с len(set()) сразу приходит на ум, однако # конструирование множества расходует как память, так и время.

Градиентный спуск. Градиентный спуск — самый используемый алгоритм обучения, он применяется почти в каждой модели машинного обучения. Градиентный спуск — это, по сути, и есть то, как обучаются модели. Без ГС машинное обучение не было бы там, где сейчас. Метод градиентного спуска с некоторой модификацией широко используется для обучения персептрона и глубоких нейронных сетей, и известен как метод обратного распространения ошибки. Что такое градиентный спуск. Градиентный спуск — метод нахождения минимального значения функции многих переменных. Минимизация любой такой функции означает поиск самой глубокой впадины в этой функции. Поиск минимума в машинном обучении означает получение наименьшей возможной ошибки или повышение точности модели. Мы увеличиваем точность, перебирая набор учебных данных при настройке параметров нашей модели (весов и смещений). Суть алгоритма – процесс получения наименьшего значения ошибки. Аналогично это можно рассматривать как спуск во впадину в попытке найти золото на дне ущелья (самое низкое значение ошибки). Перейдем к практике. Рассмотрим самый простейший случай применения градиентного спуска, а именно, поиск минимума заданной функции. В одномерном случае, градиент функции (в проекции на выбранную ось) представяет собой обычную одномерную производную. Возьмем функцию f(x) = x^4 - 3x^3 + 1, с производной f’(x) = 4x^3 - 9x^2. Выберем начальную точку x0 = 6 (начальная точка может быть практически любой, за исключением концов отрезка, если мы рассматриваем нашу функцию на отрезке). Выберем размер шага gamma = 0.01 (шаг, с которым мы будем “скатываться” в ямку минимума). Если выбрать слишком большой шаг, можно проскочить минимум, а если слишком маленький, то в случае сложной функции с несколькими минимумами, можно оказаться в локальном минимуме вместо глобального. Попробуйте поиграть с этими двумя параметрами. Где же код? А вот он.
def get_min(x, df, gamma):
    eps = 1e-6
    max_iters = 10000
    for _ in range(max_iters):
        curr_x = x
        x = curr_x - gamma * df(curr_x)
        if abs(x - curr_x) < eps:
            break

    return x

df = lambda x: 4 * x**3 - 9 * x**2
res = get_min(6, df, 0.01)
print(f’Minimum at {res:.2f}’)
Out[1]: Minimum at 2.25
#NN #gradient

Что нужно знать программисту для того, чтобы писать хороший код? Изучить популярный язык или даже несколько недостаточно, чтобы стать программистом. Чтобы писать отличный код, необходимо разбираться в науках и языках. Хотя их не так уж и много, погружение занимает порядочно времени. Но оно того стоит. Так что приступим. Английский язык ➖Лучше понимать код. ➖Читать мануалы. ➖Взаимодействовать с иностранными заказчиками. Полезная литература: English for Information Technology. Career path Software Engineering. Oxford English for Information Technology. Professional English in Use ICT. Check Your English Vocabulary for Computers and IT. Математика ➖Большинству программистов хватит умения выполнять простые операции и знания нескольких формул. ➖Продвинутый же уровень математики позволяет программисту писать сложные алгоритмы, которые применяются в графике, аналитике, сортировке, построении маршрутов и машинном обучении. Полезная литература: Томас Кормен. «Алгоритмы: построение и анализ». Дональд Кнут. «Искусство программирования». Логика ➖Все программы построены на логике. Они получают какие-то данные, проводят вычисления и, в зависимости от результата, делают что-то еще. ➖В реальных программах логики очень много, поэтому в ней нужно разбираться хотя бы на базовом уровне. Полезная литература: Непейвода Н.Н. «Прикладная логика». Владимиров Д.А. «Булевы алгебры». Статистика ➖Если вы собираетесь заниматься аналитикой, то без статистики никуда. С ее помощью выявляются закономерности, которые помогают в исследованиях. ➖Также с помощью статистики и алгоритмов можно создать искусственный интеллект с машинным обучением — тогда программисту останется лишь подождать, когда ИИ сам найдет закономерности. Полезная литература: Чарльз Уилан. «Голая статистика». Савельев В. «Статистика и котики». #info

На гитхабе разместили документ, детально сравнивающий 3 самых популярных мессенджера: Telegram, Viber, Whatsapp. По ссылке вы найдете огромную таблицу, в которой собрано более 400 параметров для подробного сравнения. Что в целом приятно, телеграм выигрывает по ряду параметров. P.S. Постараюсь на днях выложить статью по api QIWI, поскольку некоторым подписчикам тема создания ботов показалась интересной.

Else в циклах for # Циклы for и while в Python # поддерживают кляузу else # только если цикл завершается # без вызова break
def contains(haystack, needle):
    """
    Бросаем ValueError если needle не
    находится в haystack.
    """
    for item in haystack:
        if item == needle:
            break
    else:
        # else здесь выполнится только
        # если цикл не будет прерван break
        raise ValueError('Needle not found')
Вывод:
>>> contains([23, 'needle', 0xbadc0ffee], 'needle')
None
>>> contains([23, 42, 0xbadc0ffee], 'needle')
ValueError: "Needle not found"
# Хотя использование else в циклах # не запрещается, можно написать так
def better_contains(haystack, needle):
    for item in haystack:
        if item == needle:
            return
    raise ValueError('Needle not found')
# Но если вы хотите писать более # ‘Pythonic’, лучше всего будет сделать так
if needle not in haystack:
    raise ValueError('Needle not found’)

Давно не было новостей. Во-первых, мы создали бота @ninebetbot. Да, это ставки. Нет, это не реклама. Это полностью созданный нами продукт и я ни копейки не получу за такую “рекламу”, увы. Это был очень интересный опыт работы с различными платежными системами, парсерами, веб-хуками и базами данных. В своей разработке мы использовали апи QIWI как наиболее простую платежную систему. Плюс базы данных mongodb и sqlite3. Можете потыкаться, буду вам очень признателен, если вы все перейдете в бота, а мы в свою очередь проверим его стрессоустойчивость. Во-вторых, я помню многие из вас жаловались на отсутствие денег. Python разработка открывает перед вами целое многообразие возможностей, одной из которых является разработка ботов в телеграме, а другой — заработок на трейдинге криптовалют. Для последней нужны хорошие знания data science, умение анализировать, а также некоторые знания из математики и статистики. Да и в принципе это довольно таки интересно. В телеграме полно каналов по крипте и “заработку” на ней, и я не собираюсь превращать свой канал в подобие этого. Однако, я могу разбирать некоторые алгоритмы, относящиеся к торговле, на языке Python. Если вам это интересно, прожмите огонек под постом. В-третьих, для людей, которым торговля не интересна от слова совсем, мы собираемся создать специального бота для обучения написанию собственных ботов и для их монетизации. В планах это давно есть, но пока нет времени. Если вам это интересно, поставьте огонек под постом.

# Ты можешь проверить наследование # в классах с помощью встроенной # функции issubclass()
>>> class BaseClass: pass
>>> class SubClass(BaseClass): pass
>>> issubclass(SubClass, BaseClass)
True
>>> issubclass(SubClass, object)
True
>>> issubclass(BaseClass, SubClass)
False
#tips

Ответ на вопрос “почему именно так?” ниже в статье. На картинку не обращайте внимания, это просто ссылка на книгу в конце статьи. https://telegra.ph/Tonkosti-Python-06-09

In : {True: 'да', 1: 'нет', 1.0: 'возможно'}
Out: ?

Luhn algorithm Алгоритм Луна — алгоритм вычисления контрольной цифры номера пластиковой карты. Не является криптографическим средством, а предназначен в первую очередь для выявления ошибок, вызванных непреднамеренным искажением данных (например, при ручном вводе номера карты). 📎 Алгоритм разработан сотрудником фирмы IBM Гансом Питером Луном. Наиболее распространённые применения для подсчёта контрольной цифры: • Номера всех банковских карт • Номера некоторых дисконтных карт • Коды социального страхования • IMEI-коды. • Расчёт контрольного знака единого 8-значного номера железнодорожного вагона на РЖД. • Расчёт ICCID — уникальный серийный номер SIM-карты. Оригинальный алгоритм, описанный разработчиком: 📌Шаг 1. Цифры проверяемой последовательности нумеруются справа налево. 📌Шаг 2. Цифры, оказавшиеся на нечётных местах, остаются без изменений. 📌Шаг 3. Цифры, стоящие на чётных местах, умножаются на 2. 📌Шаг 4. Если в результате такого умножения возникает число больше 9, оно заменяется суммой цифр получившегося произведения — однозначным числом, то есть цифрой. 📌Шаг 5. Все полученные в результате преобразования цифры складываются. Если сумма кратна 10, то исходные данные верны. Попробуем реализовать его на Python.
for i in range(len(digits) - 1, -1, -1):
        for c in str((double + 1) * int(digits[i])):
            total += int(c)
        double = (double + 1) % 2
Основных циклов два. Первый пробегает по всем цифрам в номере (справа налево), второй отвечает за умножение на 2 цифр, стоящих на четных позициях. Переменная total отвечает за сумму цифр — контрольное число. Вся функция целиком.
def validate_card(card_num):
    """
    Input: Card number, integer or string
    Output: Valid?, boolean
    """
    double = 0
    total = 0

    digits = str(card_num)

    for i in range(len(digits) - 1, -1, -1):
        for c in str((double + 1) * int(digits[i])):
            total += int(c)
        double = (double + 1) % 2

    return (total % 10) == 0
#algorithms #python

Отличная книга по CS, рекомендую к прочтению.

# Python 3 имеет модуль # для работы с ip адресами:
>>> import ipaddress

>>> ipaddress.ip_address('192.168.1.2')
IPv4Address('192.168.1.2')

>>> ipaddress.ip_address('2001:af3::')
IPv6Address('2001:af3::’)
# Подробности здесь: # https://docs.python.org/3/library/ipaddress.html

Целые числа. Пользователей Python зачастую привлекает его простота, важной частью которой является динамическая типизация. В то время как в языках со статической типизацией, таких как С, необъодимо явным образом объявлять все переменные, языки с динамической типизацией этого не требуют. Например, в языке С можно описать операцию так:
int result = 0;
for(int i=0; i<100; ++i){
    result += i;
}
На языке Python это запишется так:
result = 0
for i in range(100):
    result += i
Главное отличие: в языке С типы данных каждой переменной объявлены явным образом. В Python мы можем сделать так:
x = 4
x = “four”
В С это могло бы привести к ошибке компиляции или же неопределенному поведению:
int x = 4;
x = “four” // сбой
Подобная гибкость делает Python таким удобным и простым в использовании. Однако такая гибкость при работе с типами указывает на то, что переменные Python представляют собой нечто большее, чем просто значение, они содержат также информацию о типе значения. Стандартная реализация языка Python написана на С. Это значит, что каждый объект Python — замаскированная структура С. Посмотрев на исходный код Python 3.4, можно узнать что описание целого типа (long), фактически выглядит так:
struct _longobject {
    long ob_refcnt;
    PyTypeObject *ob_type;
    size_t ob_size;
    long ob_digit[1];
Отдельное целое число в языке Python 3.4 состоит из 4 частей: 📌 ob_refcnt - счетчик ссылок, с помощью которого происходит выделение и освобождение памяти 📌 ob_type - тип переменной 📌 ob_size - задает размер следующих элементов данных 📌 ob_digit - содержит фактическое целочисленное значение Это значит, что существует некоторая избыточность при хранении целого числа в языке Python по сравнению с целыми числами в компилируемых языках. 📎 Целое число в Python — указатель на место в памяти, где хранится вся информация об объекте, включая байты, содержащие само целочисленное значение. 📎 Это влечет за собой последствия в виде дополнительных расходов памяти и/или вычислительного времени, что становится заметно в структурах, объединяющих значительное количество таких объектов.

Правильный ответ Строки — это неизменяемый тип данных, поэтому произойдет ошибка в строке 2 (простите за тавтологию). Когда вы пытаетесь сделать например вот это:
a = ‘a’
a += ‘b’
переменная a на второй строчке заменяется уже другой переменной. 📎изменять строки нельзя, можно только заменять их новыми #string