На гитхабе разместили документ, детально сравнивающий 3 самых популярных мессенджера: Telegram, Viber, Whatsapp.
По ссылке вы найдете огромную таблицу, в которой собрано более 400 параметров для подробного сравнения.
Что в целом приятно, телеграм выигрывает по ряду параметров.
P.S. Постараюсь на днях выложить статью по api QIWI, поскольку некоторым подписчикам тема создания ботов показалась интересной.
По ссылке вы найдете огромную таблицу, в которой собрано более 400 параметров для подробного сравнения.
Что в целом приятно, телеграм выигрывает по ряду параметров.
P.S. Постараюсь на днях выложить статью по api QIWI, поскольку некоторым подписчикам тема создания ботов показалась интересной.
Что нужно знать программисту для того, чтобы писать хороший код?
Изучить популярный язык или даже несколько недостаточно, чтобы стать программистом. Чтобы писать отличный код, необходимо разбираться в науках и языках. Хотя их не так уж и много, погружение занимает порядочно времени. Но оно того стоит. Так что приступим.
Английский язык
➖Лучше понимать код.
➖Читать мануалы.
➖Взаимодействовать с иностранными заказчиками.
Полезная литература:
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
Изучить популярный язык или даже несколько недостаточно, чтобы стать программистом. Чтобы писать отличный код, необходимо разбираться в науках и языках. Хотя их не так уж и много, погружение занимает порядочно времени. Но оно того стоит. Так что приступим.
Английский язык
➖Лучше понимать код.
➖Читать мануалы.
➖Взаимодействовать с иностранными заказчиками.
Полезная литература:
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
Twirpx
Скачать Olejniczak Maja. English for Information Technology 1. Student's Book [PDF]
Longman, 2011. 80 p. English for Information Technology combines a strong grammar syllabus with the specialist vocabulary students need to succeed in this area. It contains topics that reflect the latest developments in the field making it immediately relevant…
Градиентный спуск.
Градиентный спуск — самый используемый алгоритм обучения, он применяется почти в каждой модели машинного обучения. Градиентный спуск — это, по сути, и есть то, как обучаются модели. Без ГС машинное обучение не было бы там, где сейчас. Метод градиентного спуска с некоторой модификацией широко используется для обучения персептрона и глубоких нейронных сетей, и известен как метод обратного распространения ошибки.
Что такое градиентный спуск.
Градиентный спуск — метод нахождения минимального значения функции многих переменных. Минимизация любой такой функции означает поиск самой глубокой впадины в этой функции. Поиск минимума в машинном обучении означает получение наименьшей возможной ошибки или повышение точности модели. Мы увеличиваем точность, перебирая набор учебных данных при настройке параметров нашей модели (весов и смещений).
Суть алгоритма – процесс получения наименьшего значения ошибки. Аналогично это можно рассматривать как спуск во впадину в попытке найти золото на дне ущелья (самое низкое значение ошибки).
Перейдем к практике.
Рассмотрим самый простейший случай применения градиентного спуска, а именно, поиск минимума заданной функции.
В одномерном случае, градиент функции (в проекции на выбранную ось) представяет собой обычную одномерную производную.
Возьмем функцию f(x) = x^4 - 3x^3 + 1, с производной f’(x) = 4x^3 - 9x^2.
Выберем начальную точку x0 = 6 (начальная точка может быть практически любой, за исключением концов отрезка, если мы рассматриваем нашу функцию на отрезке). Выберем размер шага gamma = 0.01 (шаг, с которым мы будем “скатываться” в ямку минимума). Если выбрать слишком большой шаг, можно проскочить минимум, а если слишком маленький, то в случае сложной функции с несколькими минимумами, можно оказаться в локальном минимуме вместо глобального.
Попробуйте поиграть с этими двумя параметрами.
Где же код?
А вот он.
#NN #gradient
Градиентный спуск — самый используемый алгоритм обучения, он применяется почти в каждой модели машинного обучения. Градиентный спуск — это, по сути, и есть то, как обучаются модели. Без ГС машинное обучение не было бы там, где сейчас. Метод градиентного спуска с некоторой модификацией широко используется для обучения персептрона и глубоких нейронных сетей, и известен как метод обратного распространения ошибки.
Что такое градиентный спуск.
Градиентный спуск — метод нахождения минимального значения функции многих переменных. Минимизация любой такой функции означает поиск самой глубокой впадины в этой функции. Поиск минимума в машинном обучении означает получение наименьшей возможной ошибки или повышение точности модели. Мы увеличиваем точность, перебирая набор учебных данных при настройке параметров нашей модели (весов и смещений).
Суть алгоритма – процесс получения наименьшего значения ошибки. Аналогично это можно рассматривать как спуск во впадину в попытке найти золото на дне ущелья (самое низкое значение ошибки).
Перейдем к практике.
Рассмотрим самый простейший случай применения градиентного спуска, а именно, поиск минимума заданной функции.
В одномерном случае, градиент функции (в проекции на выбранную ось) представяет собой обычную одномерную производную.
Возьмем функцию 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
# Способы проверки того, что
# все элементы списка одинаковы:
# Способы расположены от “most pythonic”, к “least pythonic”
# и от менее эффективных, до более эффективных.
# Решение с len(set()) сразу приходит на ум, однако
# конструирование множества расходует как память, так и время.
# все элементы списка одинаковы:
>>> 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()) сразу приходит на ум, однако
# конструирование множества расходует как память, так и время.
Bare * asterisk
В Python 3 можно использовать оператор * в списках параметров функции, чтобы наверняка использовать keyword аргументы.
То есть, мы должны прямо указать именованые параметры в виде key=value.
#bareasterisk
В 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
Dict.
Пара коротких заметок по поводу словарей.
📌 Для того, чтобы взять “срез” словаря, можно поступить так:
📌 Для того, чтобы сложить два словаря:
P.S. Если будете копировать, поправьте кавычки. Телеграм их исправляет на нечитаемые python-ом.
#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
Memoization.
➖Это способ оптимизации, при котором сохраняется результат выполнения функции и этот результат используется при следующем вызове.
Возьмем рекурсивную реализацию нахождения числа Фибоначчи и посмотрим на время выполнения.
➖При увеличении числа, время работы алгоритма будет очень быстро расти, плюс возможна ошибка RecursionError.
➖Для оптимизации подобного алгоритма хорошо подходит метод мемоизации, то есть сохранение и повторное использования ранее вычисленных значений.
В следующем посте разберем декоратор
➖Это способ оптимизации, при котором сохраняется результат выполнения функции и этот результат используется при следующем вызове.
Возьмем рекурсивную реализацию нахождения числа Фибоначчи и посмотрим на время выполнения.
@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, а также декорирование самой мемоизации.Memoization part 2.
Декоратор clock выглядит так:
Засекаем время выполнения нашей функции, а дальше просто выводим это в красивый принт. Не забудьте импортировать модуль time.
Для memoize напишем следующую функцию:
Или через лямбду:
Таким образом:
Декоратор 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 part 3.
И напоследок, в стандартной библиотеке functools уже отлично реализован подобный декоратор, который называется lru_cache.
LRU расшифровывается как Least Recently Used.
lru_cache имеет два необязательных аргумента:
📌 maxsize — это количество хранимых результатов.
📌 typed — при равном true, например, значения 1 и 1.0 будут считаться разными (поскольку это разные типы).
📎 Мемоизация довольно простая и эффективная практика. А благодаря functools.lru_cache, ей удобно пользоваться в Python.
#lru #memoization
И напоследок, в стандартной библиотеке 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
Currying.
Теперь о каррировании. Каррирование (от англ. currying, иногда — карринг) — преобразование функции от многих аргументов в набор функций, каждая из которых является функцией от одного аргумента
Зачем нужно каррирование
📌С каррированием можно создавать краткие и лаконичные функции, подходящие для многоразового использования.
📌Эти функции используются в качестве чистых и пригодных для тестирования логических единиц при создании сложных с точки зрения логики частей программ.
В самом простейшем случае можно реализовать каррирование с помощью лямбда-функций.
Создадим простую функцию greet, которая принимает в виде аргументов приветствие и имя.
Небольшое улучшение позволит нам создать новую функцию для любого приветствия и передать этой функции имя.
Сделать это можно с любым числом аргументов.
#currying
Теперь о каррировании. Каррирование (от англ. currying, иногда — карринг) — преобразование функции от многих аргументов в набор функций, каждая из которых является функцией от одного аргумента
Зачем нужно каррирование
📌С каррированием можно создавать краткие и лаконичные функции, подходящие для многоразового использования.
📌Эти функции используются в качестве чистых и пригодных для тестирования логических единиц при создании сложных с точки зрения логики частей программ.
В самом простейшем случае можно реализовать каррирование с помощью лямбда-функций.
f = lambda y: lambda x: x + y
print(f(2)(2))
Out [0]: 4
Создадим простую функцию greet, которая принимает в виде аргументов приветствие и имя.
def greet(greeting, name):
print(greeting + ', ' + name)
greet('Hello', 'Nameless')
Небольшое улучшение позволит нам создать новую функцию для любого приветствия и передать этой функции имя.
def greet_curried(greeting):
def greet(name):
print(greeting + ', ' + name)
return greet
greet_hello = greet_curried('Hello')
greet_hello('German')
greet_hello('Ivan')
# или напрямую greet_curried
greet_curried('Hi')('Roma')
Сделать это можно с любым числом аргументов.
def greet_deeply_curried(greeting):
def w_separator(separator):
def w_emphasis(emphasis):
def w_name(name):
print(greeting + separator + name + emphasis)
return w_name
return w_emphasis
return w_separator
greet = greet_deeply_curried("Hello")("...")(".")
greet('German')
greet('Ivan')
#currying
Частичное применение (partial application).
Предоставление функции с меньшим количеством аргументов, чем она ожидает, называется частичным применением функций.
📎Другими словами, это функция, которая принимает функцию с несколькими параметрами и возвращает функцию с меньшим количеством параметров.
📎Частичное применение преобразует функцию от n аргументов в (n-m), а карринг, в свою очередь, создает n функций с одним аргументом.
Такая возможность есть у Python в стандартной библиотеке functools, функция называется partial.
#partial
Предоставление функции с меньшим количеством аргументов, чем она ожидает, называется частичным применением функций.
📎Другими словами, это функция, которая принимает функцию с несколькими параметрами и возвращает функцию с меньшим количеством параметров.
📎Частичное применение преобразует функцию от n аргументов в (n-m), а карринг, в свою очередь, создает n функций с одним аргументом.
Такая возможность есть у Python в стандартной библиотеке functools, функция называется partial.
from functools import partial
def greet(greeting, separator, emphasis, name):
print(greeting + separator + name + emphasis)
newfunc = partial(greet, greeting='Hello', separator=',', emphasis='.')
newfunc(name='German')
newfunc(name='Ivan')
newfunc2 = partial(greet, greeting='Hello', emphasis='.')
newfunc2(name='German', separator='...')
newfunc2(name='Ivan', separator='..')
#partial
Для тех, кто еще не видел, я написал статью о pandas для новичков. Тут все что нужно, для того чтобы начать работать с Series и DataFrame.
https://telegra.ph/Pandas-for-pussies-08-05
https://telegra.ph/Pandas-for-pussies-08-05
Telegraph
Pandas for beginners.
На сегодняшний день, пакет Pandas это самый важный инструмент во всем, что касается анализа данных. Многие аналитики и data scientis'ы пользуются этим пакетом. Первые шаги в Pandas
Первый шаг к тому, чтобы заниматься анализом данных - изучить библиотеку Pandas для Python. Вот небольшая статья, которая поможет начать изучение. В ней рассказывается о различных способах создания датафреймов в Pandas.
Автор статьи также ведет канал @datalytx, в котором регулярно размещаются полезные ссылки по анализу данных и автоматизации обработки данных с помощью Python.
http://bit.ly/2KutV0B
Автор статьи также ведет канал @datalytx, в котором регулярно размещаются полезные ссылки по анализу данных и автоматизации обработки данных с помощью Python.
http://bit.ly/2KutV0B
Medium
Миллион способов создать датафрейм
Всем привет, я Алексей Макаров, и я аналитик. Ещё я веду блог Datalytcs и одноименный канал @datalytx в Телеграме. Там я делюсь всякими…
Чай из itertools
Если вы читали предыдущие посты про итераторы, то примерно представляете как они работают (если нет, ищите по тегу #generators). Итератор обычно выдает значения по одному (с помощью метода
📌tee принимает два аргумента: исходный итератор и количество новых итераторов, на которые разделится исходный. А возвращает он кортеж из новых итераторов.
Вывод:
Видно, что каждый из полученных итераторов по сути является независимой копией исходного get_iter.
Несколько замечаний:
📌Не следует пытаться итерировать исходный get_iter, иначе производные итераторы могут потерять некоторые значения.
📌tee хранит в памяти извлеченные элементы, чтобы остальные потребители могли их получить, даже если исходный итератор уже сместился. Поэтому, если элементов много либо они большие, это может серьезно повлиять на расход памяти.
#tee #iterators
Если вы читали предыдущие посты про итераторы, то примерно представляете как они работают (если нет, ищите по тегу #generators). Итератор обычно выдает значения по одному (с помощью метода
__next__, например). Это означает, что получать значения из итератора может только один потребитель. Однако, это можно исправить.📌tee принимает два аргумента: исходный итератор и количество новых итераторов, на которые разделится исходный. А возвращает он кортеж из новых итераторов.
from itertools import tee
def get_iter():
for i in range(5):
yield i
one, two, three = tee(get_iter(), 3)
print(f'next is {next(one)}')
print(f'next is {next(two)}')
for item in three:
print(f'next is {item}')
Вывод:
next is 0
next is 0
next is 0
next is 1
next is 2
next is 3
next is 4
Видно, что каждый из полученных итераторов по сути является независимой копией исходного get_iter.
Несколько замечаний:
📌Не следует пытаться итерировать исходный get_iter, иначе производные итераторы могут потерять некоторые значения.
📌tee хранит в памяти извлеченные элементы, чтобы остальные потребители могли их получить, даже если исходный итератор уже сместился. Поэтому, если элементов много либо они большие, это может серьезно повлиять на расход памяти.
#tee #iterators
Немного новостей 🗒
📌Сейчас мы плотно заняты разработкой обучающего курса о создании ботов в телеграме. Что там вообще будет? А будет там много информации о самой библиотеке pyTelegramBotAPI, об обработчиках, о клавиатурах, о базах данных конечно и о веб хуках. Лично от меня — базы данных, платежки, встраивание платежек в бота.
📌Мы планируем продавать данный курс всем заинтересованным в этом людям. Вырученные деньги пойдут на развитие канала и закупы рекламы, поскольку я уже давно этим не занимался, а надо бы. Цена не будет слишком высокой. Это будет самое оно для тех, у кого давно есть идея создания собственного бота, но с реализацией напряг.
📌Кроме того, потихоньку осваиваю data science дальше, и изучаю нейросети. Нашел для вас отличную статью (не реклама, статья правда отличная) по машинному обучению. В планах сейчас освоение нейронок на хорошем уровне + создание своего приложения.
#news
📌Сейчас мы плотно заняты разработкой обучающего курса о создании ботов в телеграме. Что там вообще будет? А будет там много информации о самой библиотеке pyTelegramBotAPI, об обработчиках, о клавиатурах, о базах данных конечно и о веб хуках. Лично от меня — базы данных, платежки, встраивание платежек в бота.
📌Мы планируем продавать данный курс всем заинтересованным в этом людям. Вырученные деньги пойдут на развитие канала и закупы рекламы, поскольку я уже давно этим не занимался, а надо бы. Цена не будет слишком высокой. Это будет самое оно для тех, у кого давно есть идея создания собственного бота, но с реализацией напряг.
📌Кроме того, потихоньку осваиваю data science дальше, и изучаю нейросети. Нашел для вас отличную статью (не реклама, статья правда отличная) по машинному обучению. В планах сейчас освоение нейронок на хорошем уровне + создание своего приложения.
#news
Замыкания с поздним связыванием.
Один из распространенных источников путаницы в Python — способ связывания переменных в замыканиях (closures).
Например, вы пишите:
Что вы ожидаете:
Что происходит на самом деле:
Создаются пять функций, и все они умножают x на 4. Почему?
📌В языке Python замыкания имеют позднее связывание
📌Значения переменных, использованных в замыканиях, определяются в момент вызова внутренней функции
🔎В нашем примере, когда вызывается любая из возвращаемых функций, значение переменной i определяется с помощью окружающей области видимости в момент вызова. К этому моменту цикл завершает свою работу и i получает итоговое значение равное четырем.
#closures
Один из распространенных источников путаницы в Python — способ связывания переменных в замыканиях (closures).
Например, вы пишите:
def create_multipliers():
return [lambda x: i * x for i in range(5)]
for multiplier in create_multipliers():
print(multiplier(2), end=" ... ")
print()
Что вы ожидаете:
Out [0]: 0 … 2 … 4 … 6 … 8 …
Что происходит на самом деле:
Out [0]: 8 … 8 … 8 … 8 … 8 …
Создаются пять функций, и все они умножают x на 4. Почему?
📌В языке Python замыкания имеют позднее связывание
📌Значения переменных, использованных в замыканиях, определяются в момент вызова внутренней функции
🔎В нашем примере, когда вызывается любая из возвращаемых функций, значение переменной i определяется с помощью окружающей области видимости в момент вызова. К этому моменту цикл завершает свою работу и i получает итоговое значение равное четырем.
#closures
Как же тогда написать правильно? А вот об этом уже в следующий раз.
Если вас не тянет сейчас изучать все эти хитрости языка Python, а грядущая учеба кажется дерьмом, то напоминаю что у нас есть отличный авторский курс по ботам, который создал я и мой коллега.
Мы в теме ботов уже давно, если кто-то помнит наш бот по ставкам на футбольные матчи (сейчас бот в стадии обновления, парсеры переписаны с нуля и без использования splinter, который дико тормозил и нагружал систему).
Курс по ботам включает в себя работу с базами данных, с веб хуками и платежной системой QIWI. Он не требует каких-то особенных знаний Python и рассчитан преимущественно на новичков. Для записи пишите в бота @bots_course_bot
P.S. На следующей неделе запланировано поднятие цен, так что поспешите.
Если вас не тянет сейчас изучать все эти хитрости языка Python, а грядущая учеба кажется дерьмом, то напоминаю что у нас есть отличный авторский курс по ботам, который создал я и мой коллега.
Мы в теме ботов уже давно, если кто-то помнит наш бот по ставкам на футбольные матчи (сейчас бот в стадии обновления, парсеры переписаны с нуля и без использования splinter, который дико тормозил и нагружал систему).
Курс по ботам включает в себя работу с базами данных, с веб хуками и платежной системой QIWI. Он не требует каких-то особенных знаний Python и рассчитан преимущественно на новичков. Для записи пишите в бота @bots_course_bot
P.S. На следующей неделе запланировано поднятие цен, так что поспешите.
For masochists only.
А как вы относитесь к математике? Знакомы ли с векторным-тензорным анализом? Удовлетворяет ли вас институтский/школьный курс, или ничего вообще непонятно? Хотелось бы вам видеть больше математики на канале, даже не применительно только к языку Python?
Я считаю что роль математики в нашей жизни очень сильно недооценена. Напишите ваше мнение в комментарии, давайте обсудим это.
А как вы относитесь к математике? Знакомы ли с векторным-тензорным анализом? Удовлетворяет ли вас институтский/школьный курс, или ничего вообще непонятно? Хотелось бы вам видеть больше математики на канале, даже не применительно только к языку Python?
Я считаю что роль математики в нашей жизни очень сильно недооценена. Напишите ваше мнение в комментарии, давайте обсудим это.