Вам нравились наши посты с хэштегом #deepjava? Очень надеемся, что да, потому что нам очень нравится делиться полезной информацией :)
В этом месяце (до начала обучения новой группы по Python) мы хотим погружать вас в тонкости мира Python. Поэтому совсем скоро мы начнем серию постов про #deeppython!
Любителей Java обижать не будем - посты про #deepjava мы все равно будем публиковать, правда, реже.
Знание - само по себе сила!
В этом месяце (до начала обучения новой группы по Python) мы хотим погружать вас в тонкости мира Python. Поэтому совсем скоро мы начнем серию постов про #deeppython!
Любителей Java обижать не будем - посты про #deepjava мы все равно будем публиковать, правда, реже.
Знание - само по себе сила!
#deeppython
Сортировка массива - базовая операция. Каждый программист может написать несколько, а назвать - еще больше, алгоритмов сортировки. “Естественная” необходимость и любовь к красивым решениям дала нам MergeSort, QuickSort, HeapSort и т.д. Самоирония, видимо, породила такие алгоритмы как StupidSort, SleepSort и (мой любимый) TwitterSort. Что же использует Python? TimSort! Автором является широко известный в узких кругах Тим Питерс, а сам алгоритм был с портирован в Java и Android.
Это гибридный адаптивный алгоритм, который совмещает под капотом MergeSort, InsertionSort и хитрые эвристики. Алгоритм ищет в сортируемой последовательности длины N уже отсортированные подпоследовательности (run). Если такая подпоследовательность меньше определенного порогового значения (min_run) то идущие за ней дальше элементы досортировываются с помощью InsertionSort, пока критерий не будет удовлетворен. В итоге, исходная последовательность превращается в N/min_run отсортированных run’ов. run’ы сливаются последовательно и попарно, память выделяется только на элементы, которые действительно нужно перемещать. Допустим есть две подпоследовательности: A = [1, 2, 8, 9] и B = [4, 5,10, 21, 42]. В них 1, 2, 10, 21 и 42 уже находятся на своих финальных местах, что можно определить бинарным поиском B[0] в A и A[-1] в B. Память выделяется (и туда копируются) только на элементы из меньшей подпоследовательности, которые не стоят на своих финальных местах: 8 и 9. Дальше происходит слияние временной выделенного участка памяти и B с переносом элементов в A.
И, конечно, нельзя не упомянуть про режим галопа (galloping). В нем во время слияния элементы перемещаются не попарным сравнением, а сразу целой “пачкой”. Если сливаются temp = [8, 9] и B = [4, 5, 10, 21, 42] в A = [1, 2, _, _], то поиском temp[0] в B, можно определить, что элементы 4 и 5 нужно сразу перенести в A, после чего останется только дописать 8 и 9 в B. И это еще не все тонкости! Как выбирать min_run? Как искать элемент в массиве в режиме галопа? Для каких последовательностей сразу использовать InsertionSort без всей описанной “мишуры”?
Есть в чем покопаться! Приходите к нам на занятия: https://otus.ru/lessons?course=3?utm_source=telegram&utm_medium=internal&utm_campaign=post9.06
Набор в новую группу открыт. Будет много всего интересного!
Сортировка массива - базовая операция. Каждый программист может написать несколько, а назвать - еще больше, алгоритмов сортировки. “Естественная” необходимость и любовь к красивым решениям дала нам MergeSort, QuickSort, HeapSort и т.д. Самоирония, видимо, породила такие алгоритмы как StupidSort, SleepSort и (мой любимый) TwitterSort. Что же использует Python? TimSort! Автором является широко известный в узких кругах Тим Питерс, а сам алгоритм был с портирован в Java и Android.
Это гибридный адаптивный алгоритм, который совмещает под капотом MergeSort, InsertionSort и хитрые эвристики. Алгоритм ищет в сортируемой последовательности длины N уже отсортированные подпоследовательности (run). Если такая подпоследовательность меньше определенного порогового значения (min_run) то идущие за ней дальше элементы досортировываются с помощью InsertionSort, пока критерий не будет удовлетворен. В итоге, исходная последовательность превращается в N/min_run отсортированных run’ов. run’ы сливаются последовательно и попарно, память выделяется только на элементы, которые действительно нужно перемещать. Допустим есть две подпоследовательности: A = [1, 2, 8, 9] и B = [4, 5,10, 21, 42]. В них 1, 2, 10, 21 и 42 уже находятся на своих финальных местах, что можно определить бинарным поиском B[0] в A и A[-1] в B. Память выделяется (и туда копируются) только на элементы из меньшей подпоследовательности, которые не стоят на своих финальных местах: 8 и 9. Дальше происходит слияние временной выделенного участка памяти и B с переносом элементов в A.
И, конечно, нельзя не упомянуть про режим галопа (galloping). В нем во время слияния элементы перемещаются не попарным сравнением, а сразу целой “пачкой”. Если сливаются temp = [8, 9] и B = [4, 5, 10, 21, 42] в A = [1, 2, _, _], то поиском temp[0] в B, можно определить, что элементы 4 и 5 нужно сразу перенести в A, после чего останется только дописать 8 и 9 в B. И это еще не все тонкости! Как выбирать min_run? Как искать элемент в массиве в режиме галопа? Для каких последовательностей сразу использовать InsertionSort без всей описанной “мишуры”?
Есть в чем покопаться! Приходите к нам на занятия: https://otus.ru/lessons?course=3?utm_source=telegram&utm_medium=internal&utm_campaign=post9.06
Набор в новую группу открыт. Будет много всего интересного!
#deeppython #otus
Все мы рано или поздно сталкиваемся с необходимостью сохранить какую-то информацию, да так чтобы намертво, чтобы внуки потом еще прочитать смогли. Ежели еще нужно делать хитрые выборки по сохраненному, то обычно мы приходим к использованию реляционных СУБД. Чаще все, если посмотреть рейтинги популярности, это MySQL. Что может быть проще? Качаем последний MySQL и запускаем.
И вот уже где-то в коде устанавливается соединение с БД, выполняется простой запрос:
import MySQLdb
….
cursor.execute("UPDATE User SET likes=likes+1 WHERE Id=%s", (user_id,))
Кажется, все хорошо. Даже если тут же сделать SELECT, то можно убедиться, что у пользователя увеличилось число like’ов. Но есть нюанс, если тот же SELECT сделать из консольного клиента, то пользователь как будто и не обновлялся. А если посмотреть SHOW PROCESSLIST, то видно, что запрос в состоянии “Waiting for table metadata lock”.
А все штука в настройках по умолчанию, о которых часто забывают. В частности, в MySQL последних версий по умолчанию движок таблицы InnoDB, транзакционный, все дела. А питонячьем MySQLdb с версии 1.2.0 опция autocommit выставлена в False. Что же получается? Получается, что все ваши запросы в таком случае выполняются в рамках одной транзакции и не видны другим транзакциям до явного вызова commit (или rollback). Плюс, лочатся метаданные используемой таблицы, что отображается в processlist’е.
Что делать? Можно явно вызывать conn.commit() в конце транзакции, а можно сразу после установления соединения выставить conn.autocommit(True), тогда каждый запрос будет завершаться коммитом прозрачно для вас. Ну и конечно, нужно внимательно читать документацию и changelog’и.
Решение показалось очевидным? Тогда, возможно, вы хорошо знаете Python. Проверьте свои знания на вступительном тестировании: https://otus.ru/lessons?course=3?utm_source=telegram&utm_medium=internal&utm_campaign=pythonpost14/06
Все мы рано или поздно сталкиваемся с необходимостью сохранить какую-то информацию, да так чтобы намертво, чтобы внуки потом еще прочитать смогли. Ежели еще нужно делать хитрые выборки по сохраненному, то обычно мы приходим к использованию реляционных СУБД. Чаще все, если посмотреть рейтинги популярности, это MySQL. Что может быть проще? Качаем последний MySQL и запускаем.
И вот уже где-то в коде устанавливается соединение с БД, выполняется простой запрос:
import MySQLdb
….
cursor.execute("UPDATE User SET likes=likes+1 WHERE Id=%s", (user_id,))
Кажется, все хорошо. Даже если тут же сделать SELECT, то можно убедиться, что у пользователя увеличилось число like’ов. Но есть нюанс, если тот же SELECT сделать из консольного клиента, то пользователь как будто и не обновлялся. А если посмотреть SHOW PROCESSLIST, то видно, что запрос в состоянии “Waiting for table metadata lock”.
А все штука в настройках по умолчанию, о которых часто забывают. В частности, в MySQL последних версий по умолчанию движок таблицы InnoDB, транзакционный, все дела. А питонячьем MySQLdb с версии 1.2.0 опция autocommit выставлена в False. Что же получается? Получается, что все ваши запросы в таком случае выполняются в рамках одной транзакции и не видны другим транзакциям до явного вызова commit (или rollback). Плюс, лочатся метаданные используемой таблицы, что отображается в processlist’е.
Что делать? Можно явно вызывать conn.commit() в конце транзакции, а можно сразу после установления соединения выставить conn.autocommit(True), тогда каждый запрос будет завершаться коммитом прозрачно для вас. Ну и конечно, нужно внимательно читать документацию и changelog’и.
Решение показалось очевидным? Тогда, возможно, вы хорошо знаете Python. Проверьте свои знания на вступительном тестировании: https://otus.ru/lessons?course=3?utm_source=telegram&utm_medium=internal&utm_campaign=pythonpost14/06
#deeppython #otus
Допустим, есть следующая иерархия классов:
class X(object): pass
class Y(object): pass
class A(X, Y): pass
class B(Y, X): pass
И в ней, вообще говоря, ничего криминального нет. Но если вы захотите отнаследоваться от A и B, то вас ждет разочарование. Выражение:
class C(A, B): pass
выдаст весьма интересную ошибку. В чем же дело?
Всему причиный алгоритм MRO (method resolution order), который используется в Python с версии 2.3. Он актуален только для new-style классов (наследуются от object), для classic классы никаких ошибок не будет в данном случае.
Под MRO некого класса C понимается его линеаризация - список предков класса, включая сам класс, отсортированный в порядке “удаленности”. Так, линеаризацией класса B из примера выше будет [B, Y, X, object]. MRO, таким образом например, определяет как, в случае множественного наследования, будет осуществляться поиск вызванного метода в данной иерархии классов.
Для конструирования линеаризации класса в Python используется C3 linearization алгоритм. Сам алгоритм разрабатывался в свое время для языка Dylan, но с тех пор был принят в Python и еще, например, в Perl 6. Линеаризацией данного класса называется слияние линеаризацией его родителей. Финальный список формируется так: сначала добавляется данный класс, потом рассматривается первый класс из линеаризации первого родителя, если он не встречаются в других списка, то добавляется в финальный и так далее, если участвует, то переходим к рассмотрению следующего родителя. Как мы видели, не все классы поддаются линеаризации данным алгоритмом.
Для classic классов MRO реализуется через поиску в глубину, слева-направо.
Кстати, эту тему мы решили осветить не просто так. Теперь у вас будет больше шансов пройти вступительное тестирование на курс Python: https://otus.ru/lessons?course=3?utm_source=telegram&utm_medium=internal&utm_campaign=deeppython
Допустим, есть следующая иерархия классов:
class X(object): pass
class Y(object): pass
class A(X, Y): pass
class B(Y, X): pass
И в ней, вообще говоря, ничего криминального нет. Но если вы захотите отнаследоваться от A и B, то вас ждет разочарование. Выражение:
class C(A, B): pass
выдаст весьма интересную ошибку. В чем же дело?
Всему причиный алгоритм MRO (method resolution order), который используется в Python с версии 2.3. Он актуален только для new-style классов (наследуются от object), для classic классы никаких ошибок не будет в данном случае.
Под MRO некого класса C понимается его линеаризация - список предков класса, включая сам класс, отсортированный в порядке “удаленности”. Так, линеаризацией класса B из примера выше будет [B, Y, X, object]. MRO, таким образом например, определяет как, в случае множественного наследования, будет осуществляться поиск вызванного метода в данной иерархии классов.
Для конструирования линеаризации класса в Python используется C3 linearization алгоритм. Сам алгоритм разрабатывался в свое время для языка Dylan, но с тех пор был принят в Python и еще, например, в Perl 6. Линеаризацией данного класса называется слияние линеаризацией его родителей. Финальный список формируется так: сначала добавляется данный класс, потом рассматривается первый класс из линеаризации первого родителя, если он не встречаются в других списка, то добавляется в финальный и так далее, если участвует, то переходим к рассмотрению следующего родителя. Как мы видели, не все классы поддаются линеаризации данным алгоритмом.
Для classic классов MRO реализуется через поиску в глубину, слева-направо.
Кстати, эту тему мы решили осветить не просто так. Теперь у вас будет больше шансов пройти вступительное тестирование на курс Python: https://otus.ru/lessons?course=3?utm_source=telegram&utm_medium=internal&utm_campaign=deeppython
#deeppython #otus
Чаще всего микрооптимизации производительности только ухудшают качество кода,
его становится сложнее читать. Но их полезно знать и разбираться, потому что сам процесс исследования позволяет глубже понять язык. Вот например, что быстрее: {} или dict()? Ну или, [] или list()?
На поставленный вопрос легко ответить, воспользовавшись timeit. [] и {} в несколько раз быстрее их оппонентов. Более интересный вопрос: почему?
В данном случае ответить нам поможет модуль dis:
>>> dis.dis(compile('[]', '', 'eval'))
1 0 BUILD_LIST 0
3 RETURN_VALUE
>>> dis.dis(compile('list()', '', 'eval'))
1 0 LOAD_NAME 0 (list)
3 CALL_FUNCTION 0
6 RETURN_VALUE
Как можно видеть, в случае [] Python сразу создает байткод инструкцию построения списка, потому что [], как и {}, являются токенами языка, которые, грубо говоря, сразу можно интерпретировать. list() и dict() же представляют из себя вызов функции, для которого нужно сначала отрезолвить их имя (поискать в globals и builtin), создать новый фрейм на стеке. Поиска в глобальной namespace’е еще можно избежать, сохранив имя в локально, т.е. Сделав, например, _list = list, но от CALL_FUNCTION избавиться не выйдет никак.
А хорошо ли ты знаешь Python? Проверь! https://otus.ru/lessons?course=3?utm_source=telegram&utm_medium=internal&utm_campaign=deeppython19.06
Чаще всего микрооптимизации производительности только ухудшают качество кода,
его становится сложнее читать. Но их полезно знать и разбираться, потому что сам процесс исследования позволяет глубже понять язык. Вот например, что быстрее: {} или dict()? Ну или, [] или list()?
На поставленный вопрос легко ответить, воспользовавшись timeit. [] и {} в несколько раз быстрее их оппонентов. Более интересный вопрос: почему?
В данном случае ответить нам поможет модуль dis:
>>> dis.dis(compile('[]', '', 'eval'))
1 0 BUILD_LIST 0
3 RETURN_VALUE
>>> dis.dis(compile('list()', '', 'eval'))
1 0 LOAD_NAME 0 (list)
3 CALL_FUNCTION 0
6 RETURN_VALUE
Как можно видеть, в случае [] Python сразу создает байткод инструкцию построения списка, потому что [], как и {}, являются токенами языка, которые, грубо говоря, сразу можно интерпретировать. list() и dict() же представляют из себя вызов функции, для которого нужно сначала отрезолвить их имя (поискать в globals и builtin), создать новый фрейм на стеке. Поиска в глобальной namespace’е еще можно избежать, сохранив имя в локально, т.е. Сделав, например, _list = list, но от CALL_FUNCTION избавиться не выйдет никак.
А хорошо ли ты знаешь Python? Проверь! https://otus.ru/lessons?course=3?utm_source=telegram&utm_medium=internal&utm_campaign=deeppython19.06
#deeppython #otus
ООП в Python - это вам не Java. Никаких вам фабрик абстрактных классов, интерфейсов и вот этого всего. Есть, конечно, ABC и очумелые ручки, но это совсем другая история. Но классы и наследование есть, конечно. Не смотря на это, нет строгого разделения на public/private/protected. На фоне этой правды жизни возникло соглашение о том, что одно нижнее подчеркивание (_) перед именем означает пометку “только для внутреннего пользования” и даже в случае from M import * такие имена не будут импортироваться. Но это все же лишь соглашение, и если очень хочется, то ничто особо не мешает получить, например, доступ к полю, начинающемуся с нижнего подчеркивания.
Самое близкое, в некотором смысле, к private полю в Python можно получить, написав не одно, а два нижних подчеркивания перед именем. При попытке прямого доступа в таком случается получается ошибка, например:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: CachedResponse instance has no attribute ‘__intermediate_result’
Но даже такой механизм обеспечения приватности не особо сильнее предыдущего, так как на самом деле, значение поля из примера выше можно получить, обратившись к атрибуту _CachedResponse__intermediate_result. Это так называемый name mangling. Но, в основном, он все же предназначен для избежания инцидентов с одинаковыми именами полей в дочерних классах и тому подобным.
Хорошо ли ты знаешь Python? Проверь! https://otus.ru/lessons?course=3?utm_source=telegram&utm_medium=internal&utm_campaign=deeppython22/06
ООП в Python - это вам не Java. Никаких вам фабрик абстрактных классов, интерфейсов и вот этого всего. Есть, конечно, ABC и очумелые ручки, но это совсем другая история. Но классы и наследование есть, конечно. Не смотря на это, нет строгого разделения на public/private/protected. На фоне этой правды жизни возникло соглашение о том, что одно нижнее подчеркивание (_) перед именем означает пометку “только для внутреннего пользования” и даже в случае from M import * такие имена не будут импортироваться. Но это все же лишь соглашение, и если очень хочется, то ничто особо не мешает получить, например, доступ к полю, начинающемуся с нижнего подчеркивания.
Самое близкое, в некотором смысле, к private полю в Python можно получить, написав не одно, а два нижних подчеркивания перед именем. При попытке прямого доступа в таком случается получается ошибка, например:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: CachedResponse instance has no attribute ‘__intermediate_result’
Но даже такой механизм обеспечения приватности не особо сильнее предыдущего, так как на самом деле, значение поля из примера выше можно получить, обратившись к атрибуту _CachedResponse__intermediate_result. Это так называемый name mangling. Но, в основном, он все же предназначен для избежания инцидентов с одинаковыми именами полей в дочерних классах и тому подобным.
Хорошо ли ты знаешь Python? Проверь! https://otus.ru/lessons?course=3?utm_source=telegram&utm_medium=internal&utm_campaign=deeppython22/06
#deeppython #otus
Все мы знаем и любим генераторы в Python. По сути, генератор - это итератор, который можно использовать в цикле, как обычно, но генератор дополнительно содержит внутри ключевое слово yield. После каждого yield генератор временно прекращает исполнение и возвращает управление, при следующем вызове стартуя с того места, где закончил в прошлый раз, при этом сохраняя состояние и значения переменных между вызовами. Но, черт побери, как он это делает?
Объект генератор, помимо всего прочего, содержит в себе указатель на текущий execution frame, который в свою очередь содержит стек вызова для данного генератора. Во время вызова next(gen_object) вызывается PyEval_EvalFrame для текущего execution frame’а. Это одна из самых главных функций интерпретатора, внутри, она, в том числе, знает про ключевое слово yield
TARGET(YIELD_VALUE) {
retval = POP();
f->f_stacktop = stack_pointer;
why = WHY_YIELD;
goto fast_yield;
}
В данном случае возвращается значение, а текущий фрейм сохраняется (f->f_stacktop = stack_pointer), так что после следующего next’а можно продолжить там, где остановились, ведь PyEval_EvalFrame будет вызван на том же фрейме, что и раньше, с тем же стеком и состоянием. В обычных функциях f_stacktop приравнивается к NULL.
Все мы знаем и любим генераторы в Python. По сути, генератор - это итератор, который можно использовать в цикле, как обычно, но генератор дополнительно содержит внутри ключевое слово yield. После каждого yield генератор временно прекращает исполнение и возвращает управление, при следующем вызове стартуя с того места, где закончил в прошлый раз, при этом сохраняя состояние и значения переменных между вызовами. Но, черт побери, как он это делает?
Объект генератор, помимо всего прочего, содержит в себе указатель на текущий execution frame, который в свою очередь содержит стек вызова для данного генератора. Во время вызова next(gen_object) вызывается PyEval_EvalFrame для текущего execution frame’а. Это одна из самых главных функций интерпретатора, внутри, она, в том числе, знает про ключевое слово yield
TARGET(YIELD_VALUE) {
retval = POP();
f->f_stacktop = stack_pointer;
why = WHY_YIELD;
goto fast_yield;
}
В данном случае возвращается значение, а текущий фрейм сохраняется (f->f_stacktop = stack_pointer), так что после следующего next’а можно продолжить там, где остановились, ведь PyEval_EvalFrame будет вызван на том же фрейме, что и раньше, с тем же стеком и состоянием. В обычных функциях f_stacktop приравнивается к NULL.
Уже сегодня группа курса "Серьезное изучение Python" начнет свое обучение. Мы провели Два дня открытых дверей, разыграли 4 бесплатных места в новой Python группе, рассказывали о "фишках" Python в постах #deeppython, создали профессиональное сообщество для успешно прошедших вступительное тестирование, где можно общаться на профессиональные темы, запустили пак классных стикеров с кодирующей совой для Telegram. Мы активно знакомили пользователей с нашим продуктом и рассказывали, почему мы больше, чем просто обучающие курсы, отвечали на вопросы и делали много-много всего (в том числе подписали большое количество новых соглашений с партнерами), чтобы наши студенты получили хорошие знания и возможности профессионального и карьерного роста. Время летит так быстро! Новая Python группа начинает занятия уже сегодня! Это значит, что ближе к вечеру мы закроем возможность оплаты и присоединения к группе. В группе остались последние места - еще есть совсем немного времени, чтобы успеть присоединиться: https://otus.ru/lessons/3/?utm_source=telegram&utm_medium=internal&utm_campaign=lastcall У нас очень классный преподаватель на курсе Python, поэтому мы искренне рады за наших новых студентов - им точно не будет скучно + у них есть возможность личной профессиональной дискуссии и преподавателем, что очень классно - ведь есть масса рабочих вопросов, в которых мудрый совет бы не помешал! Мы желаем ребятам успеха и уверены, что курс им понравится! За короткое время набора в группу Python мы сделали большой скачок в развитии: мы выкатили новую очень классную версию сайта, начали подготовку новых таких же классных курсов, как Java и Python. Поэтому в наших ближайших планах запуски курсов по веб-разработке и DevOps. А значит, мы будем публиковать много новых интересных материалов по теме новых курсов :) Осенью мы планируем запуски курсов по другим дисциплинам и новый долгожданный набор на Java. Ориентируемся что следующий набор на курс Python будет в конце осени или зимой. Совсем скоро - в августе и сентябре наши первые выпускники курса Java пойдут на собеседования. Мы с нетерпением ожидаем этого события - ведь мы уверены в своих выпускниках и знаем, что их ждут отличные карьерные перспективы! Спасибо, что вы с нами и следите за нашими обновлениями! ❤️
otus.ru
Курс Python, обучение Python course онлайн, курсы Python, программист Python — курсы | OTUS
Как стать программистом на python? Пройдя курсы в Otus ты научишься делать классные вещи на Пайтоне
Доброе утро, друзья!
Рады сообщить о продолжении набора на курс Python для web разработки!
Старт намечен на 16 сентября - вас ждет 4 месяца обучения, за это время прокачаем и подтянем самые необходимые скилы, структурируем уже полученные знания и потренируемся выполнять боевые задачи под руководством Ильи Лебедева, разработчика с более чем шестилетним стажем в области.
И, в связи с продолжением набора, ловите еще одну заметку #deeppython #deepwebdev #otus
Слышали о GraphQL? Если нет, то давайте вкратце разберем, что это такое и зачем оно нужно.
GraphQL – спецификация протокола для общения фронтенда и бекенда. Чтобы получить данные, нужно отправить запрос на сервер, указав, какие именно данные в каком формате нужны. Например, чтобы получить посты указанного пользователя, можно сделать такой запрос:
posts(user_id=42, is_draft=False) {
title,
published_at,
text,
tags {
title,
url
}
}
GraphQL обладает плюсами для всех участников.
Для фронтендеров есть много оберток вокруг этого протокола, которые существенно упрощают создание различных компонентов. Это радикально снижает количество кода, который нужно написать и упрощает время реализации интерфейса.
Для бекендеров плюс в том, что благодаря единой точке входа, можно гибко и просто управлять кешированием, удобно собирать данные из разных источников и собирать разные части данных на разным машинах.
И тем и другим удобно то, что вместо большого количества ручек API с разными параметрами, отражающими предметную область, теперь есть только одна, которая позволяет гибко указывать, какие данные нужны, а какие – нет.
Graphene – реализация этой спецификации на Python - подробности которой будем разбирать в программе курса - проходите вступительное тестирование и присоединяйтесь! https://otus.ru/lessons/9?utm_source=telegram&utm_medium=internal&utm_campaign=webdev&utm_term=deeppost21.08
Рады сообщить о продолжении набора на курс Python для web разработки!
Старт намечен на 16 сентября - вас ждет 4 месяца обучения, за это время прокачаем и подтянем самые необходимые скилы, структурируем уже полученные знания и потренируемся выполнять боевые задачи под руководством Ильи Лебедева, разработчика с более чем шестилетним стажем в области.
И, в связи с продолжением набора, ловите еще одну заметку #deeppython #deepwebdev #otus
Слышали о GraphQL? Если нет, то давайте вкратце разберем, что это такое и зачем оно нужно.
GraphQL – спецификация протокола для общения фронтенда и бекенда. Чтобы получить данные, нужно отправить запрос на сервер, указав, какие именно данные в каком формате нужны. Например, чтобы получить посты указанного пользователя, можно сделать такой запрос:
posts(user_id=42, is_draft=False) {
title,
published_at,
text,
tags {
title,
url
}
}
GraphQL обладает плюсами для всех участников.
Для фронтендеров есть много оберток вокруг этого протокола, которые существенно упрощают создание различных компонентов. Это радикально снижает количество кода, который нужно написать и упрощает время реализации интерфейса.
Для бекендеров плюс в том, что благодаря единой точке входа, можно гибко и просто управлять кешированием, удобно собирать данные из разных источников и собирать разные части данных на разным машинах.
И тем и другим удобно то, что вместо большого количества ручек API с разными параметрами, отражающими предметную область, теперь есть только одна, которая позволяет гибко указывать, какие данные нужны, а какие – нет.
Graphene – реализация этой спецификации на Python - подробности которой будем разбирать в программе курса - проходите вступительное тестирование и присоединяйтесь! https://otus.ru/lessons/9?utm_source=telegram&utm_medium=internal&utm_campaign=webdev&utm_term=deeppost21.08
🖖🏻 Полезная заметка для системных администраторов, которая поможет автоматизировать выполнение повседневных задач: #deeppython
Читаем вместе:
Читаем вместе: