OTUS IT News – Telegram
OTUS IT News
7.21K subscribers
4.33K photos
303 videos
5 files
4.3K links
Экспертный контент по востребованным технологиям 2025 года: от разработки и аналитики до искусственного интеллекта и облачных решений.

Более 170 курсов+

🗓 Расписание бесплатных ОУ: https://otus.pw/24Da/
🦉 Голосуй за канал: https://news.1rj.ru/str/boost/Otusjava
Download Telegram
#deepjava #otus

Рано или поздно Java разработчик задает себе вопрос: Hibernate или MyBatis? MyBatis или Hibernate? От ответа зависит архитектура проекта, а ответ, в свою очередь, зависит от задачи. Давайте сегодня разберемся, что они такое и когда какой лучше.

Итак, Hibernate это ORM framework. Его полное название Hibernate ORM. Он полностью поддерживает JPA и, фактически, является имплементацией JPA. Его основная задача -- понять как размечены ваши классы аннотациями ORM, построить по ним схему и собирать объекты по строкам из базы. Hibernate сам пишет за вас запросы к базе. Для вас работа с базой выглядит как работа с объектами. Сохранить объект, загрузить объект, обновить объект. Как, собственно, и должно быть. Это же Object Relational Mapping.

MyBatis это Java persistence framework. Не ORM. MyBatis связывает методы интерфейса маппера с SQL запросом. MyBatis не умеет создавать схему. И, честно говоря, вообще ничего о схеме не знает. MyBatis превращает вызов метода в запрос к базе, и как результат вызова метода возвращает результат запроса.

Что лучше подходит для вашего проекта? Смотрите сами:
Если у вас много простых объектов без сложных связей друг с другом -- Hibernate.
Если у вас сложные запросы к базе на агрегацию данных -- MyBatis.
Если вы готовы поручить фреймворку создавать и обновлять для вас схему -- Hibernate.
Если у вас работа с хранимыми процедурами -- MyBatis.
Если вы не хотите писать запросы сами, и работать с JPQL -- HIbernate.
Если вы хотите писать свой ORM (а его так или иначе придется писать) -- MyBatis.

Можно попробовать использовать оба фреймворка в одном проекте. Но мы такого на практике не встречали. Поэтому рано или поздно Java разработчик встает перед вопросом: Hibernate или MyBatis?
#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. Проверьте свои знания на вступительном тестировании: http://otus.ru/lessons?course=3?utm_source=telegram&utm_medium=internal&utm_campaign=pythonpost14/06
У нас суперская новость! Нашим новым партнером стала компания Avito. Avito будут рады пригласить на собеседования наших лучших по итогам обучения студентов по курсам Python, мобильной разработки и QA (не мнее трех человек с каждого курса)
#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: http://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? Проверь! http://otus.ru/lessons?course=3?utm_source=telegram&utm_medium=internal&utm_campaign=deeppython19.06
Доброе утро! У нас хорошие новости - наших Java выпускников ждут на собеседование еще в одной компании. Нашим партнером стал Ланит.
Присоединяйтесь!
Сегодня мы с удивлением обнаружили, что до старта новой группы по Python осталось всего 2 недели! (вот как заработались 😱)
А это значит, что совсем скоро наши новые студенты окунутся в многогранный мир Python и будут не только полезно, но и весело проводить время с преподавателем курса (уж мы-то знаем, что Станислав Ступников заскучать не даст).
А еще перед стартом новой группы мы проведем два дня открытых дверей, где не только ответим на все вопросы, но и (уже можно сказать по-традиции) разыграем бесплатные места в Python-группе.
Для участие в розыгрыше необходимо успешное прохождение вступительного теста. Проходите тест и регистрируйтесь на День открытых дверей:
http://otus.ru/dod?utm_source=telegram&utm_medium=internal&utm_campaign=deadlinedod
#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? Проверь! http://otus.ru/lessons?course=3?utm_source=telegram&utm_medium=internal&utm_campaign=deeppython22/06
С радостью приглашаем на Дни открытых дверей по курсу Python 30 июня и 5 июля в 20:00!
Из любой удобной точки мира - приходите к нам - формат проведения онлайн.
Познакомимся с преподавателем курса Станиславом Ступниковым - программистом Mail.ru с более чем 6-ти летним стажем промышленной разработки, в том числе для крупных государственных заказчиков и более 4-х лет преподавания студентам МГТУ им. Баумана.
По сложившейся традиции расскажем почему OTUS больше чем просто образовательный проект и какие возможности получат наши студенты после прохождения обучения. Расскажем о преимуществах программы курса, практических занятиях и профессиональном сообществе разработчиков. Расскажем о карьерных перспективах студентов и возможностях, предложенных компаниями - партнерами. Ответим на все интересующие вопросы, поделимся новостями, просто приятно и с пользой проведем время. Конечно, это еще не всё!
Успешно прошедших вступительный тест на Дне открытых дверей ждет уникальная возможность!
Спешите проверить свои знания Python и регистрируйтесь на День открытых дверей http://otus.ru/dod?utm_source=telegram&utm_medium=internal&utm_campaign=post26.06&utm_content=main&utm_term=dod
Всем известно, что Python - интерпретируемый язык программирования!
Но это не совсем точно, конечно. Чтобы употреблять такие слова нужно говорить о какой-то конкретной имплементации языка.
Всем извстно, что CPython (самая распространенная имплементация) интерпретируемый!
Но это не совсем точно, конечно. Можно сказать, что CPython полукомпилируемый, потому что исходный код компилируется в байткод, который потом исполнется вирутальной машиной (тоже CPython в данном случае). Традиционно же, когда мы говорим о компиляции, то имеем в виду преобразование высокоуровневого языка в конкретный машинный код.
У этой (полу)компиляции в Python есть свои особенности. Исходный код можно скомпилировать в байткод с разными флагами оптимизации: -О, -ОО. В результате у вас появятся *.pyo файлики с байткодом. При этом, в первом случае у вас будут "выключены" assert'ы, а во втором - еще "вырежутся" docstring'и. Оптимизации не особо крутые, чего уж тут говорить, если только в asserta'ах не было какой-то сложной логики.
Как это знание может пригодится? Например, если код разворачивается на CentOS с помощью rpm пакетов, то во время сборки пакета неявно запускается brp-python-bytecompile скрипт, который компилирует Python файлы в *.pyc и *.pyo. Поэтому не стоит потом удивляться, что assert'ы в коде не срабатывают.
Зададимся сегодня провокационным вопросом: что такое сервер? Есть разработчики сервера, есть серверные приложения, есть курсы по серверной разработке. А сам предмет разработки это что? Понятие слишком обширное и интуитивно понятное всем кто с ним сталкивался.

И всетаки, если попробовать дать определение серверу, то должно получиться что-то такое: сервер - это система программ, которая отвечает на запросы. То есть, нет сервера без запросов и ответов. Клиенты посылают серверу запросы, сервер что-то в себе читает, вычисляет или меняет и возвращает клиентам ответы.

Может ли сервер посылать запросы клиенту? В общем случае, может. Нотификация пользователя о событиях на сервере неотъемлемая часть, например, любого игрового сервера. Пользователь должен своевременно узнать о том, что ему в голову пришло… копье противника. И отрисовать красиво это событие. Сервер должен сам уведомить клиента о событии, не дожидаясь запроса от клиента.

Теперь рассмотрим веб сервер. Что это такое? Очевидно это сервер, в определении которое мы уже дали выше. Но что значит приставка “веб”?

К счастью для нас, это понятие уже не такое абстрактное как сервер и у него есть определение на wikipedia. Веб сервер, это сервер который обрабатывает запросы по протоколу HTTP. Ответы, очевидно, тоже отправляет по этому же протоколу.

Если вы пишите клиент-серверное приложение в котором клиент это браузер, а сервер это… веб сервер. То протокол общения между ними определен. Может ли веб сервер уведомить клиента о событии? Нет. Протокол не позволяет это сделать. Веб сервер может только отвечать на запросы. Нет запросов, нет ответов.

Как же быть разработчику браузерных игр? Без уведомления клиента динамические игры невозможны. Обмануть протокол? Да, это можно сделать. Можно продолжать использовать HTTP, но “подписать” клиент на события на сервере. Названия подходов и технологий здесь: ajax, long polling или websockets. WebSockets, правда, уже не HTTP, но это предмет уже следующей заметки.
Кажется, наш канал превращается в канал для суперских новостей :)

У нас появился бомбически классный набор стикеров для Telegram OTUS Coding Owl. Мы уверены, что этот набор просто не может оставить равнодушным причастных к миру IT!
https://news.1rj.ru/str/addstickers/OTUScodingOwl
This media is not supported in your browser
VIEW IN TELEGRAM
Над Москвой и территорией Центрального федерального округа сегодня пройдет грозовой фронт небывалой силы, говорят нас ждет всемирный потоп!!! Так что этот вечер лучше провести дома и с пользой для себя.
Сегодня в 20:00 по московскому времени начинаем День открытых дверей по курсу Разработчик Python. Самое время пройти вступительное тестирование, зарегистрироваться и принять участие в розыгрыше бесплатных мест на курсе!
Присоединяйтесь! http://otus.ru/dod?utm_source=telegram&utm_medium=internal&utm_campaign=post30.06&utm_content=main&utm_term=dod
Сегодня на первом Дне открытых дверей определились победители розыгрыша бесплатных мест на курсе серьезного изучения Python.
Победителями розыгрыша стали: Алексей Демидов и Василий Островский.
Поздравляем!

Как это было можно посмотреть тут: https://www.youtube.com/watch?v=LdSnU5YahkE
#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.