Продолжая тему ошибок, начатую в задаче №12, вчера мы опубликовали задачу №13, суть которой заключалась в обработке исключений, а именно в работе блока
Код задачи:
Разберём задачу.
Создаём функцию
В теле функции создаём
Внутри блока
В блоке
Вызываем функцию
Hello World!
Именно так, в ответ на роботу программы, мы получили "Hello World", но как так получилось, если мы использовали
Ответ прост: блок
Давайте поподробнее разберёмся в структуре
Обработка исключений
1.
2.
3.
4.
Пример
В блоке
В блоке
В блоке
Пример
В блоке
В блоке
В блоке
Заключение.
Правильная обработка исключений – залог отсутствия ошибок, хорошей читаемости и надёжной работы кода.
Python предлагает гибкую систему обработки исключений. Благодаря тому, что блоки
try-ecxept-else-finally. Задачу решило 30 человек, это 58% из 52 человек.Код задачи:
def func():
try:
print("Hello", end=' ')
return
finally:
print("World")
func()
Разберём задачу.
Создаём функцию
func.В теле функции создаём
try-finally конструкцию.Внутри блока
try выводим в терминал слово "Hello", заменив перенос строки на пробел. Затем производим "выход" из функции вызвав return.В блоке
finally выводим в терминал слово "World".Вызываем функцию
func.Hello World!
Именно так, в ответ на роботу программы, мы получили "Hello World", но как так получилось, если мы использовали
return, спросите вы?Ответ прост: блок
finally срабатывает всегда, независимо от того, выпала ли ошибка и был ли сделан выход из функции. Исключение – разве что остановка программы, но это уже совершенно другой класс ошибок.Давайте поподробнее разберёмся в структуре
try-except и в том, как всё работает.Обработка исключений
try в Python состоит из четырёх блоков:1.
try – в этот блок записывается выражение или действие, которое может вызвать исключение.2.
except – в этом блоке располагаются "отлавливаемые" исключения. Он срабатывает, если в блоке try было поднято исключение. 3.
else – в этот блок записываются действия, выполняемые в случае, если в блоке try не произошло исключения.4.
finally – этот блок выполняется при любом исходе. Выполнится ли try без ошибок, или будет поднято исключение, – неважно. Блок выполняется всегда.Пример
try-except-else без ошибки:try:
result = 3 / 2
except ZeroDivisionError:
print("Сработало исключение!")
else:
print(f"Результат: {result}")
>>> Результат 1.5
В блоке
try делим одно число на другое.В блоке
except пытаемся поймать ошибку деления на ноль, если она будет вызвана.В блоке
else выводим результат. Пример
try-except-finally с ошибкой:try:
result = 3 / 0
except ZeroDivisionError:
return 0
finally:
print(f"Звоните в поддержку! У нас ошибка!")
>>> Звоните в поддержку! У нас ошибка!
В блоке
try делим одно число на другое. Намеренно вызываем ошибку деления на ноль.В блоке
except ловим ошибку деления на ноль и делаем возврат 0.В блоке
finally выводим в терминал сообщение о том, что сработала ошибка. Заключение.
Правильная обработка исключений – залог отсутствия ошибок, хорошей читаемости и надёжной работы кода.
Python предлагает гибкую систему обработки исключений. Благодаря тому, что блоки
else-finally не являются обязательными, их можно добавлять по ситуации. Один из ярких примеров – запуск Telegram-бота в блоке try-finally. В блоке try запускается обработчик сообщений с сервера, но если по какой-то причине бот будет остановлен, сработает блок finally, который, например, оповестит администратора об остановке бота.🔥7👍1🗿1
Forwarded from Заметки на салфетке
Всем привет!
Сегодня в 18 часов (по МСК) на YouTube-канале будет стрим.
На стриме продолжим разрабатывать бота. Что-то починим, что до добавим.
Приходите, задавайте вопросы в чате, общайтесь 🙂
Ссылка на канал: https://www.youtube.com/@codeonanapkin
Сегодня в 18 часов (по МСК) на YouTube-канале будет стрим.
На стриме продолжим разрабатывать бота. Что-то починим, что до добавим.
Приходите, задавайте вопросы в чате, общайтесь 🙂
Ссылка на канал: https://www.youtube.com/@codeonanapkin
🔥3
Forwarded from Заметки на салфетке
Всем доброго утра)
Вчера прошёл стрим, в этот раз больше старался говорить, только вот говорить было не для кого( В связи с этим опрос по удобному времени стрима.
Ещё одной неприятностью стало то, что на стриме играла музыка с ютуба и я всё равно словил страйк за авторские права, пришлось удалить 2 минуты из видео, думаю не страшно)
Запись стрима: https://www.youtube.com/watch?v=Bwr_aNfU1Qg&t=401s
Также залил все изменения в репозиторий.
Вчера прошёл стрим, в этот раз больше старался говорить, только вот говорить было не для кого( В связи с этим опрос по удобному времени стрима.
Ещё одной неприятностью стало то, что на стриме играла музыка с ютуба и я всё равно словил страйк за авторские права, пришлось удалить 2 минуты из видео, думаю не страшно)
Запись стрима: https://www.youtube.com/watch?v=Bwr_aNfU1Qg&t=401s
Также залил все изменения в репозиторий.
🔥2👍1
Forwarded from Заметки на салфетке
🔥1😁1
ООП на Python. ч. 2. Статические методы
Автор: Андрей Лебедев
Продолжаем цикл постов об ООП на Python. В прошлый раз мы говорили об ООП как таковом, об объекте
Что такое статический метод?
Если выражаться просто, статический метод – это такой метод, который может выполнять свою работу, не имея доступа к информации, хранящейся в атрибутах экземпляра класса. То есть по сути статический метод не привязан к экземплярам класса. Данные, которые имеют отношение к конкретному объекту, никак не влияют на работу статического метода этого объекта.
Всем ли методам класса нужен объект self?
Автор: Андрей Лебедев
Продолжаем цикл постов об ООП на Python. В прошлый раз мы говорили об ООП как таковом, об объекте
self и о методе __init__. На сей раз мы поведем речь о методах классов. И начнём мы со статических и классовых методов.Что такое статический метод?
Если выражаться просто, статический метод – это такой метод, который может выполнять свою работу, не имея доступа к информации, хранящейся в атрибутах экземпляра класса. То есть по сути статический метод не привязан к экземплярам класса. Данные, которые имеют отношение к конкретному объекту, никак не влияют на работу статического метода этого объекта.
Всем ли методам класса нужен объект self?
🔥5👍3
После нашего первого поста вы могли подумать, что объект
Представим, что у нас есть класс, описывающий марку сигарет:
Мы описали класс, объект которого – марка сигарет. При инициализации объекта указывается название марки и содержание никотина в миллиграммах на сигарету. Единственный метод этого класса, не считая
Теперь давайте представим, что мы хотим демонстрировать пользователю стандартное предупреждение о вреде курения. Для этого создадим отдельный метод в том же самом классе:
В результате работы нашего кода одно за другим выведутся два сообщения: о содержании никотина в сигаретах марки “Ява” и о вреде курения.
Как и всегда, мы добавили объект
Избавимся от self
Если мы просто возьмём и выбросим из кода ненужный нам аргумент
Суть ошибки в том, что наш метод теперь не принимает никаких аргументов, но Python автоматически передает
Статические методы
Методы, которые не используют данные конкретного объекта (то есть его атрибуты), встречаются довольно часто. И когда это происходит, нет никакой необходимости передавать в них лишнюю ссылку на объект
Вывод у этого кода будет точно таким же, как в предыдущем случае с
self необходимо передавать в качестве аргумента всем без исключения методам класса. Но если в методе никак не используется ни сам этот объект, ни какой-либо из его атрибутов, зачем тогда этот объект туда передавать? Метод прекрасно справится со своей задачей и без self.Представим, что у нас есть класс, описывающий марку сигарет:
class Cigarette:
def __init__(self, name="", nicotine_amount=0.0):
self.name = name
self.nicotine_amount = nicotine_amount
def describe_cigarette(self):
message = f'В сигаретах марки "{self.name}" содержится {self.nicotine_amount:} мг никотина.'
print(message)
my_cigarette = Cigarette("Ява", 0.8)
my_cigarette.describe_cigarette()
Мы описали класс, объект которого – марка сигарет. При инициализации объекта указывается название марки и содержание никотина в миллиграммах на сигарету. Единственный метод этого класса, не считая
__init__, – describe_cigarette выводит в консоль сообщение о содержании никотина в сигаретах данной марки.Теперь давайте представим, что мы хотим демонстрировать пользователю стандартное предупреждение о вреде курения. Для этого создадим отдельный метод в том же самом классе:
class Cigarette:
def __init__(self, name="", nicotine_amount=0.0):
self.name = name
self.nicotine_amount = nicotine_amount
def describe_cigarette(self):
message = f'В сигаретах марки "{self.name}" содержится {self.nicotine_amount:} мг никотина.'
print(message)
def show_disclaimer(self):
message = 'Курение вредит вашему здоровью.'
print(message)
my_cigarette = Cigarette("Ява", 0.8)
my_cigarette.describe_cigarette()
my_cigarette.show_disclaimer()
В результате работы нашего кода одно за другим выведутся два сообщения: о содержании никотина в сигаретах марки “Ява” и о вреде курения.
Как и всегда, мы добавили объект
self в качестве аргумента во вновь созданный нами метод show_disclaimer. При этом важно заметить, что ни сам этот объект self, ни его атрибуты никак в методе не задействованы. И это диктуется самим смыслом выводимого предупреждения о вреде курения: оно одинаково для любой марки сигарет.Избавимся от self
Если мы просто возьмём и выбросим из кода ненужный нам аргумент
self из метода show_disclaimer, выполнение кода завершится следующим исключением:
TypeError: Cigarette.show_disclaimer() takes 0 positional arguments but 1 was given
Суть ошибки в том, что наш метод теперь не принимает никаких аргументов, но Python автоматически передает
self в каждый метод класса Cigarette. Статические методы
Методы, которые не используют данные конкретного объекта (то есть его атрибуты), встречаются довольно часто. И когда это происходит, нет никакой необходимости передавать в них лишнюю ссылку на объект
self. Чтобы этого не делать, необходимо перед методом вставить декоратор @staticmethod:
class Cigarette:
def __init__(self, name="", nicotine_amount=0.0):
self.name = name
self.nicotine_amount = nicotine_amount
def describe_cigarette(self):
message = f'В сигаретах марки "{self.name}" содержится {self.nicotine_amount:} мг никотина.'
print(message)
@staticmethod
def show_disclaimer():
message = 'Курение вредит вашему здоровью.'
print(message)
my_cigarette = Cigarette("Ява", 0.8)
my_cigarette.describe_cigarette()
my_cigarette.show_disclaimer()
Вывод у этого кода будет точно таким же, как в предыдущем случае с
self.🔥4👍3
Благодаря тому, что работа статических методов никак не связана с информацией о конкретном объекте, вызывать их можно прямо из класса, не создавая при этом объект. Для этого достаточно указать название класса и сам статический метод через точечную нотацию:
В такой версии код выведет на печать только само предупреждение о вреде курения.
Для чего использовать статические методы?
А в чем вообще смысл этого действия? Почему нельзя просто вставлять ссылку на
Классы, в которых статические методы выделены надлежащим образом, понятнее для восприятия. Когда вы выделяете тот или иной метод декоратором
Классы, в которых используются статические методы, делают код более эффективным. Представьте себе огромный класс с большим количеством атрибутов и код, в котором создано множество экземпляров данного класса. И все эти объекты по много раз вызывают один и тот же метод. Добавление простого декоратора
Футбольный клуб
Напишем класс для футбольного клуба:
Создавая экземпляр этого класса, мы задаем название футбольного клуба и описание. Вывод у нашего кода будет следующий:
Получился довольно типичный для ООП код: у нас есть класс, при помощи которого мы создаем объекты. Каждый из них обладает своими атрибутами, а также методом, который работает с информацией из этих атрибутов. Но что, если мы хотим иметь доступ к информацим о классе, которая связана более, чем с одним объектом?
Футбольная лига
Допустим, нам нужно создать футбольную лигу. Добавим в неё ещё пару клубов, используя тот же класс:
Мы создали три футбольных клуба и добавили их в список, после чего для каждого из них поочередно вызвали метод
Допустим, нам нужно отслеживать количество клубов в нашей футбольной лиге. Это число будет иметь отношение ко всему классу в целом, а не к какому-то конкретному его экземпляру. Соответственно, подобная информация должна храниться в атрибуте класса, а не его экземпляра. Вот как мы поступим:
Cigarette.show_disclaimer()
В такой версии код выведет на печать только само предупреждение о вреде курения.
Для чего использовать статические методы?
А в чем вообще смысл этого действия? Почему нельзя просто вставлять ссылку на
self в качестве аргумента во все методы, даже если сам объект не будет в итоге использован? Здесь можно выделить два важных для понимания момента:Классы, в которых статические методы выделены надлежащим образом, понятнее для восприятия. Когда вы выделяете тот или иной метод декоратором
@staticmethod, вы не только подсказываете Python’у, как ему работать с этим методом. Вы также посылаете сигнал другим разработчикам о том, что этот метод не меняет ничего в самом объекте, а доступ к нему можно получить, не создавая объектов класса вообще.Классы, в которых используются статические методы, делают код более эффективным. Представьте себе огромный класс с большим количеством атрибутов и код, в котором создано множество экземпляров данного класса. И все эти объекты по много раз вызывают один и тот же метод. Добавление простого декоратора
@staticmethod позволит значительно сократить объем необязательной работы, которую будет совершать Python.Футбольный клуб
Напишем класс для футбольного клуба:
class FootballClub:
def __init__(self, name, description=""):
self.name = name
self.description = description
def describe_club(self):
msg = f"{self.name}: {self.description}"
print(msg)
tree = FootballClub("Манчестер Юнайтед")
tree.description = "Манчестер, Англия"
tree.describe_tree()
Создавая экземпляр этого класса, мы задаем название футбольного клуба и описание. Вывод у нашего кода будет следующий:
Манчестер Юнайтед: Манчестер, Англия
Получился довольно типичный для ООП код: у нас есть класс, при помощи которого мы создаем объекты. Каждый из них обладает своими атрибутами, а также методом, который работает с информацией из этих атрибутов. Но что, если мы хотим иметь доступ к информацим о классе, которая связана более, чем с одним объектом?
Футбольная лига
Допустим, нам нужно создать футбольную лигу. Добавим в неё ещё пару клубов, используя тот же класс:
clubs = []
club = FootballClub("Манчестер Юнайтед")
club.description = "Манчестер, Англия"
clubs.append(club)
club = FootballClub("Реал")
club.description = "Мадрид, Испания"
clubs.append(club)
club = FootballClub("Ювентус")
club.description = "Турин, Италия"
clubs.append(club)
for club in clubs:
club.describe_club()
Мы создали три футбольных клуба и добавили их в список, после чего для каждого из них поочередно вызвали метод
describe_club. Вывод будет таким:
Манчестер Юнайтед: Манчестер, Англия
Реал: Мадрид, Испания
Ювентус: Турин, Италия
Допустим, нам нужно отслеживать количество клубов в нашей футбольной лиге. Это число будет иметь отношение ко всему классу в целом, а не к какому-то конкретному его экземпляру. Соответственно, подобная информация должна храниться в атрибуте класса, а не его экземпляра. Вот как мы поступим:
🔥4
class FootballClub:
num_clubs = 0
@classmethod
def count_clubs(cls):
msg = f"Клубов в нашей лиге: {cls.num_clubs}."
print(msg)
def __init__(self, name, description=""):
self.name = name
self.description = description
FootballClub.num_clubs += 1
def describe_club(self):
msg = f"{self.name}: {self.description}"
print(msg)
clubs = []
club = FootballClub("Манчестер Юнайтед")
club.description = "Манчестер, Англия"
clubs.append(club)
club = FootballClub("Реал")
club.description = "Мадрид, Испания"
clubs.append(club)
club = FootballClub("Ювентус")
club.description = "Турин, Италия"
clubs.append(club)
for club in clubs:
club.describe_club()
FootballClub.count_clubs()
Сначала вне метода
__init__ создадим атрибут класса num_clubs. Обратим внимание, что никакой приставки в виде self перед этим атрибутом у нас нет, потому что он связан не с экземпляром класса, а с классом в целом.Далее пишем классовый метод, предварив его декоратором
@classmethod. При помощи этого декоратора в метод передается весь класс. По умолчанию в классовых методах сам класс обозначается параметром cls. Внутри самого метода доступ к атрибуту класса можно получить через точечную нотацию. Так, к числу клубов в нашей лиги мы получаем доступ следующим образом: cls.num_clubs.Чтобы количество клубов всегда было актуальным, при создании каждого нового экземпляра класса нам нужно увеличивать число, записанное в
num_clubs, на единицу. Мы сделали это в методе __init__:
def __init__(self, name, description=""):
self.name = name
self.description = description
FootballClub.num_clubs += 1
Так как метод
__init__ не принимает cls в качестве аргумента, доступ к атрибуту num_clubs мы получаем через название класса. В конце мы вызываем метод класса, снова обратившись к нему по названию:
FootballClub.count_clubs()
Вывод будем следующим:
Манчестер Юнайтед: Манчестер, Англия
Реал: Мадрид, Испания
Ювентус: Турин, Италия
Клубов в нашей лиге: 3.
Обращаться к атрибутам класса и классовым методам можно несколькими способами, не только так, как мы показали выше.
Доступ к атрибуту класса по названию класса
Несмотря на то, что класс передается в классовый метод автоматически, получить доступ к атрибутам класса можно и через его название:
@classmethod
def count_clubs(cls):
msg = f"Клубов в нашей лиге: {FootballClub.num_clubs}."
print(msg)
Делать так не имеет никакого смысла, ведь можно использовать
cls, но ошибки при таком подходе не случится.Вызов классового метода из экземпляра класса
Вызвать классовый метод можно и из экземпляра класса. Следующий код вполне рабочий:
club = FootballClub("Манчестер Юнайтед")
club.description = "Манчестер, Англия"
club.count_clubs()
Результат будет таким же, как и в случае с
FootballClub.count_clubs().Вызов классового метода через экземпляр класса может пригодиться, если вы работаете с объектом класса в модуле, который не имеет прямого доступа к самому классу. В таком случае можно не импортировать класс в модуль целиком, а обойтись вызовом метода напрямую из объекта, который у вас уже есть.
Подобная гибкость облегчает работу, поскольку разработчику необязательно думать о том, что происходит под капотом в том или ином классе. Можно просто пользоваться результатами труда тех, кто разработал и поддерживает саму библиотеку.
Доступ к атрибуту класса из обычного метода класса
🔥5
Атрибутами класса можно пользоваться и в обычных методах класса. Например, если нам нужно расширить описание футбольного клуба, включив в него информацию о количестве команд в его лиге:
Это самый обычный метод, связанный с конкретным экземпляром класса, поэтому в него передается объект
Можно ли получить доступ к атрибутам класса через
Ответ: да, можно. Если во всём классе у нас есть только один атрибут с данным именем, то ошибки не будет:
Этот код будет работать так же, как и код из примера выше.
На что обращать внимание?
Сложности начинаются при попытке записать новое значение в атрибут класса с помощью объекта
Мы, как и раньше, увеличиваем число клубов на единицу, когда инициализируем новый объект класса. Но так как теперь мы делаем это через объект
В атрибуте
В следующий раз поговорим о методах
Пост на сайте
Поддержать проект
#Python #ООП #код_в_мешке #объект #атрибут #класс #init #self #метод
def describe_club(self):
msg = (f"{self.name}: {self.description}\n"
f"Клубов в лиге: {FootballClub.num_clubs}")
print(msg)
Это самый обычный метод, связанный с конкретным экземпляром класса, поэтому в него передается объект
self. Но и в нём можно получить доступ к атрибутам всего класса, используя название класса.Можно ли получить доступ к атрибутам класса через
self?Ответ: да, можно. Если во всём классе у нас есть только один атрибут с данным именем, то ошибки не будет:
def describe_club(self):
msg = (f"{self.name}: {self.description}\n"
f"Клубов в лиге: {self.num_clubs}")
print(msg)
Этот код будет работать так же, как и код из примера выше.
На что обращать внимание?
Сложности начинаются при попытке записать новое значение в атрибут класса с помощью объекта
self. Дело в том, что, используя self, вы создаете новый атрибут именно экземпляра, если такой атрибут не был создан ранее. В такой редакции код не будет давать нам искомый результат:
class FootballClub:
num_clubs = 0
@classmethod
def count_clubs(cls):
msg = f"Клубов в нашей лиге: {cls.num_clubs}."
print(msg)
def __init__(self, name, description=""):
self.name = name
self.description = description
self.num_clubs += 1
def describe_club(self):
msg = (f"{self.name}: {self.description}\n"
f"Клубов в лиге: {self.num_clubs}")
print(msg)
Мы, как и раньше, увеличиваем число клубов на единицу, когда инициализируем новый объект класса. Но так как теперь мы делаем это через объект
self, а не через название класса, мы не меняем атрибут класса num_clubs, а создаём новый атрибут экземпляра с таким же точно названием. И теперь у нас два атрибута с одинаковым названием num_clubs: один относится к классу, а другой - к конкретному его экземпляру. И вывод у кода будет следующий:
Манчестер Юнайтед: Манчестер, Англия
Клубов в лиге: 1
Реал: Мадрид, Испания
Клубов в лиге: 1
Ювентус: Турин, Италия
Клубов в лиге: 1
Клубов в нашей лиге: 0.
В атрибуте
num_clubs каждого экземпляра класса теперь записано по единице, но атрибут num_clubs класса так и не изменился: это по-прежнему ноль. Если логика в этом случае не очень понятно, можно просто запомнить важный вывод. Работая с атрибутом класса внутри самого класса, всегда используйте cls, если речь о классовом методе, и название класса, если речь об обычном методе. И постарайтесь не создавать атрибутов класса и атрибутов экземпляра с одинаковым названием. В следующий раз поговорим о методах
__str__ и __repr__.Пост на сайте
Поддержать проект
#Python #ООП #код_в_мешке #объект #атрибут #класс #init #self #метод
🔥9
Forwarded from Заметки на салфетке
В воскресенье в 18:00 состоится третий стрим.
Продолжаем делать Telegram-бота для управления VPSкой.
Что мы уже сделали:
- Выполнение произвольной команды с выводом результата.
- Выполнение последовательности команд с запоминанием изменения пути при использовании команды
- Оповещение администратора о запуске-остановке бота и меню.
- Меню управления Docker-контейнерами.
Что ещё в планах:
- Сделать вывод используемых сервером ресурсов (ОЗУ, ЦПУ).
- Сделать меню с избранными командами. Для реализации необходимо подключить БД используя SQLAlchemy.
- Сделать обработку сообщений только от администратора.
Если у вас есть ещё идеи - пишите в комментариях!
Всех жду Воскресенье 18:00: https://www.youtube.com/@codeonanapkin
P.S. Всем, кто поддерживает канал на Boosty доступен репозиторий с исходным кодом проекта.
Продолжаем делать Telegram-бота для управления VPSкой.
Что мы уже сделали:
- Выполнение произвольной команды с выводом результата.
- Выполнение последовательности команд с запоминанием изменения пути при использовании команды
cd.- Оповещение администратора о запуске-остановке бота и меню.
- Меню управления Docker-контейнерами.
Что ещё в планах:
- Сделать вывод используемых сервером ресурсов (ОЗУ, ЦПУ).
- Сделать меню с избранными командами. Для реализации необходимо подключить БД используя SQLAlchemy.
- Сделать обработку сообщений только от администратора.
Если у вас есть ещё идеи - пишите в комментариях!
Всех жду Воскресенье 18:00: https://www.youtube.com/@codeonanapkin
P.S. Всем, кто поддерживает канал на Boosty доступен репозиторий с исходным кодом проекта.
👍3🔥1
Доброго пятничного вечера, Друзья!
Пришло время для отдыха и развлечений. Закройте дверь за повседневными заботами и погрузитесь в мир киноискусства, который заставит вас забыть о всех проблемах. Приготовьте вкусные угощения, уютно устроившись на диване, и позвольте себе погрузиться в захватывающий мир кино. Пусть каждый кадр наполнит вас эмоциями и заставит забыть о повседневной суете. Наслаждайтесь просмотром фильма и наслаждайтесь вечером пятницы в полной мере!
Фильм: Оппенгеймер
Год: 2023
История физика-теоретика Джулиуса Роберта Оппенгеймера, считающегося «отцом атомной бомбы». В 1940-х годах в рамках «Манхэттенского проекта» он руководил разработкой первого ядерного оружия в Лос-Аламосской национальной лаборатории. «Оппенгеймер» (2023) — биографическая драма Кристофера Нолана с Киллианом Мерфи в главной роли, основанная на книге «Американский Прометей: Триумф и трагедия Дж. Роберта Оппенгеймера» Кая Берда и Мартина Дж. Шервина.
https://www.sspoisk.ru/film/4664634/
Приятного просмотра
Пришло время для отдыха и развлечений. Закройте дверь за повседневными заботами и погрузитесь в мир киноискусства, который заставит вас забыть о всех проблемах. Приготовьте вкусные угощения, уютно устроившись на диване, и позвольте себе погрузиться в захватывающий мир кино. Пусть каждый кадр наполнит вас эмоциями и заставит забыть о повседневной суете. Наслаждайтесь просмотром фильма и наслаждайтесь вечером пятницы в полной мере!
Фильм: Оппенгеймер
Год: 2023
История физика-теоретика Джулиуса Роберта Оппенгеймера, считающегося «отцом атомной бомбы». В 1940-х годах в рамках «Манхэттенского проекта» он руководил разработкой первого ядерного оружия в Лос-Аламосской национальной лаборатории. «Оппенгеймер» (2023) — биографическая драма Кристофера Нолана с Киллианом Мерфи в главной роли, основанная на книге «Американский Прометей: Триумф и трагедия Дж. Роберта Оппенгеймера» Кая Берда и Мартина Дж. Шервина.
https://www.sspoisk.ru/film/4664634/
Приятного просмотра
🔥5👍1
🔥3
Код на салфетке
ООП на Python. ч. 2. Статические методы Автор: Андрей Лебедев Продолжаем цикл постов об ООП на Python. В прошлый раз мы говорили об ООП как таковом, об объекте self и о методе __init__. На сей раз мы поведем речь о методах классов. И начнём мы со статических…
Вчера мы опубликовали задачу №14, которая является закреплением темы, начатой в посте "ООП на Python. ч. 2. Статические методы". С задачей справилось всего 7 человек из 26...
Код задачи:
Разбор задачи.
Привычного разбора задачи не будет, поскольку задача повторяет описанное в посте. Если вы не читали пост "ООП на Python. ч. 2. Статические методы", то настоятельно рекомендую это сделать, как минимум чтобы закрыть пробел в понимании работы методов класса.
Код задачи:
class PopSinger:
num_singers = 0
@classmethod
def count_singers(cls):
msg = f"Певцов на нашем концерте: {cls.num_singers}."
print(msg)
def __init__(self, name, description=""):
self.name = name
self.description = description
self.num_singers += 1
klava = PopSinger("Клава Кока", "27 лет, женщина")
insta = PopSinger("Инстасамка", "23 года, женщина")
feduk = PopSinger("Федук", "32 года, мужчина")
PopSinger.count_singers()
Разбор задачи.
Привычного разбора задачи не будет, поскольку задача повторяет описанное в посте. Если вы не читали пост "ООП на Python. ч. 2. Статические методы", то настоятельно рекомендую это сделать, как минимум чтобы закрыть пробел в понимании работы методов класса.
🔥4
Forwarded from Заметки на салфетке
🤯Два с половиной часа! Можно считать, что бот готов. По мелочи пройтись напильником, привести к одному виду, но он работает как задумывалось изначально.
Запись: https://www.youtube.com/watch?v=ZmSrlHJQikw
Исходный код доступен для подписчиков на Boosty.
Дальше если и буду дорабатывать бота, то самостоятельно, обновляя его в репозитории.
Идей на следующее воскресенье у меня нет. Что посоветуете? Что было бы вам интересно увидеть?
Запись: https://www.youtube.com/watch?v=ZmSrlHJQikw
Исходный код доступен для подписчиков на Boosty.
Дальше если и буду дорабатывать бота, то самостоятельно, обновляя его в репозитории.
Идей на следующее воскресенье у меня нет. Что посоветуете? Что было бы вам интересно увидеть?
🔥8❤3
Сравнение интерпретатора Python и компилятора C
Автор: Arduinum628
Всем доброго дня! Сегодня я продолжу свою рубрику о сравнении работы двух языков программирования Python и C. В предыдущей статье я сравнивал типизацию Python и C и показал процесс компилирования программы на C. Компиляция проводилась чтобы посмотреть на результат работы программы C. Тут сразу у читателя могли появиться вопросы: "В Python нет компиляции, что же происходит там?" или "Где сравнение того, что происходит под капотом у этих двух языков?". Конечно, я не могу обойти эту интересную и сложную тему без освещения в своей рубрике. Сегодня я сравню интерпретатор Python и компилятор C. Поэтому возьмите себе вкусняшек пожевать и чаю - мы погружаемся ещё глубже в сравнение Python и C.
Сравнение компилятора и интерпретатора
Автор: Arduinum628
Всем доброго дня! Сегодня я продолжу свою рубрику о сравнении работы двух языков программирования Python и C. В предыдущей статье я сравнивал типизацию Python и C и показал процесс компилирования программы на C. Компиляция проводилась чтобы посмотреть на результат работы программы C. Тут сразу у читателя могли появиться вопросы: "В Python нет компиляции, что же происходит там?" или "Где сравнение того, что происходит под капотом у этих двух языков?". Конечно, я не могу обойти эту интересную и сложную тему без освещения в своей рубрике. Сегодня я сравню интерпретатор Python и компилятор C. Поэтому возьмите себе вкусняшек пожевать и чаю - мы погружаемся ещё глубже в сравнение Python и C.
Сравнение компилятора и интерпретатора
🔥5
Для того чтобы увидеть полную картину, в этой статье я сравню все фазы от написания кода в IDE до выполнения работы программы. Так вы увидите весь процесс более глубоко и вам будет проще понять какие процессы прячутся во время выполнения программ на C и Python. Я люблю показывать работу программы на конкретных примерах, а не абстрактно, и в этом нам помогут циклы
Фаза 1: написание программы в IDE
Данная фаза довольно банальна, но без неё не обходится написание ни одной программы. Начнём с идеи того, что мы реализуем в коде. Думаю, для примера нам не нужно писать что-то сложное. Давайте напишем цикл, который будет проходить по списку чисел, запишет в переменную сумму этих чисел и выдаст на экран результат суммы чисел из списка. Начнём с реализации данной программы на языке Python.
Пример выше на Python довольно простой. У нас есть список чисел
Я буду пропускать то, что вы уже знаете из предыдущих глав, и сосредоточусь на новом для вас синтаксисе. Давайте посмотрим на пример выше внимательнее. Начнём со строки
for. Заодно я наглядно покажу в чём схожесть и различия по синтаксису при написании этого цикла на Python и C.Фаза 1: написание программы в IDE
Данная фаза довольно банальна, но без неё не обходится написание ни одной программы. Начнём с идеи того, что мы реализуем в коде. Думаю, для примера нам не нужно писать что-то сложное. Давайте напишем цикл, который будет проходить по списку чисел, запишет в переменную сумму этих чисел и выдаст на экран результат суммы чисел из списка. Начнём с реализации данной программы на языке Python.
nums_list = [1, 3, 4, 50, 20]
sum_nums = 0
for num in nums_list:
sum_nums += num
print(f'Сумма чисел списка = {sum_nums}')
Пример выше на Python довольно простой. У нас есть список чисел
nums_list, который мы обходим циклом for. В цикле for мы проходим по списку чисел и складываем каждое число из списка с числом из переменной sum_nums, где хранится результат суммы чисел из списка. В конце функция print выдаст нам результат в виде отформатированной строки при помощи f строки, в которую мы вставляем результат суммы чисел из переменной sum_nums. Давайте теперь напишем реализацию подобного кода на языке C.#include <stdio.h>
int main(){
int arr_nums[] = {1, 3, 4, 50, 20};
int size = sizeof(arr_nums) / sizeof(arr_nums[0]);
int sum_nums = 0;
for (int i=0; i < size; i++) {
sum_nums += arr_nums[i];
}
printf("Сумма чисел массива = %d\n", sum_nums);
return 0;
}
Я буду пропускать то, что вы уже знаете из предыдущих глав, и сосредоточусь на новом для вас синтаксисе. Давайте посмотрим на пример выше внимательнее. Начнём со строки
int arr_nums[] = {1, 3, 4, 50, 20}; слева направо. Начало int arr_nums[] - это массив целых чисел, а далее ему присваивается его содержимое = {1, 3, 4, 50, 20};, то есть числа для массива. Читатель может задаться вопросом, а что такое массив и чем он отличается от списка? Могу сказать, что тема коллекций достаточно обширна и предлагаю её раскрыть в следующей моей статье. Пока ограничусь тем что массив, или array, в языке С имеет фиксированную длину в отличие от списка, или list, в Python, который является динамическим. Это означает что в array C нельзя добавить новый элемент после его создания (если превышен размер массива), в то время как в list Python нет фиксированного размера и можно добавить сколько угодно новых элементов в список. Компилятор в C будет автоматически определять размер массива на основе количества его элементов. Также размер массива можно указать явно int arr_nums[5] = {1, 3, 4, 50, 20};, где цифра в квадратных скобках это количество элементов массива. В следующей главе я покажу вам, что будет если указать число меньше или больше количества чисел в массиве :) Перейдём к следующей строке кода int size = sizeof(arr_nums) / sizeof(arr_nums[0]);. Первая часть строки нам уже проста для понимания - это целочисленная переменная int size, которая, как мы видим из названия, переводится на русский как размер. Идём по строке кода далее и видим, что ей присваивается результат следующего математического выражения = sizeof(arr_nums) / sizeof(arr_nums[0]);.🔥3👍1
Давайте рассмотрим левый операнд
Фаза 2: препроцессинг
После того как мы написали программный код, мы обязательно захотим его выполнить и посмотреть как работает наша программа. Для этого мы запускаем процесс компиляции в C.
В terminal
Как же с этим связан препроцессинг? Давайте разберёмся, что такое препроцессинг и для чего он нужен. В языке C есть программа-препроцессор, которая запускается автоматически перед компиляцией. Препроцессор языка C нужен для выполнения специальных команд, которые называются директивами препроцессора, которые определяют операции для выполнения, которые должны быть выполнены до компиляции. В нашем коде, написанном на языке C, есть директива
Фаза 3: компиляция
sizeof(arr_nums). Оператор sizeof принимает array и возвращает размер списка в байтах. Размер одного элемента на большинстве операционных систем составляет 4 байта, а так как в массиве 5 элементов, то 4 * 5 = 20 в итоге получим 20 байт. Мы получили размер списка 20 байт в левом операнде. Как вы можете догадаться, далее мы делим размер списка на размер первого элемента, взяв его по индексу 0. В итоге получается математическая операция 20 / 4 = 5 , результатом которой будет количество элементов в списке - 5. Для чего это нужно нам объяснит цикл for. Рассмотрим первую строку цикла for (int i=0; i < size; i++) {. Читателю должно быть сразу бросается в глаза, что мы для использования переменной индекса объявляем целочисленную переменную и присваиваем ей число 0 в int i=0;. Она нам будет необходима для взятия элемента списка по индексу. В то время как в моём примере цикла for в Python в проходе по списку я сразу получал его элемент, не используя индекс. Прилагаю строку из Python для наглядности: for num in nums_list:. Далее идёт условие i < size; после которого произойдёт выход из цикла. Для корректной работы цикла в i++ мы будем увеличивать переменную для индекса после каждого прохода цикла for. В результате мы получим числа для индекса 0, 1, 2, 3, 4 и выйдем из цикла for, когда i станет равна 5 и условие 5 < 5 не выполнится. Это довольно сильно похоже на цикл while в Python из-за выхода из цикла for по условию. В одной из следующих статей я расскажу о while в Python подробнее и сравню его с while из C. Вернёмся к нашему циклу и посмотрим на операцию в его теле sum_nums += arr_nums[i];. Оператором присвоения += складываем переменную sum_nums c числом из arr_nums[i], которое мы берём по индексу из списка. Результат присваивается переменной sum_nums. Не забываем про {} для тела цикла и ; для обозначения конца инструкции. Компилятору нужно понимать где конец инструкции для его правильной работы. В Python мы аналогично используем оператор присвоения +=, но используем значение переменной, а не берём число по индексу из списка в sum_nums += num.Фаза 2: препроцессинг
После того как мы написали программный код, мы обязательно захотим его выполнить и посмотреть как работает наша программа. Для этого мы запускаем процесс компиляции в C.
В terminal
$ gcc sum_nums.c -o sum_nums
Как же с этим связан препроцессинг? Давайте разберёмся, что такое препроцессинг и для чего он нужен. В языке C есть программа-препроцессор, которая запускается автоматически перед компиляцией. Препроцессор языка C нужен для выполнения специальных команд, которые называются директивами препроцессора, которые определяют операции для выполнения, которые должны быть выполнены до компиляции. В нашем коде, написанном на языке C, есть директива
#include <stdio.h>, в которой <stdio.h> это заголовочный файл для библиотеки, хранящий в себе функции ввода/вывода (пример printf()). Директива в языке программирования C - это инструкция для препроцессора, которая выполняется до фазы компиляции. Директива #include используется для включения библиотек. Если мыслить на Python языке, то это похоже отдалённо на то, что мы импортировали библиотеку в код целиком и теперь можем её использовать во время выполнения программы. На языке Python мы пока что ничего не будем делать ибо у него нет стадии препроцессинга, так как он не требует предварительной обработки.Фаза 3: компиляция
🔥3
После того как отработал препроцессор, что обработал нам директивы, начинается процесс компиляции в C. Сначала компилятор выполняет лексический и синтаксический анализ исходного кода, чтобы проверить на наличие ошибок. Если ошибок не обнаружено, то компилятор транслирует программу в машинный код. Машинный код — это низкоуровневый код, который может быть напрямую выполнен процессором компьютера. Он представляет собой последовательность чисел, которые являются инструкциями для процессора. Если обнаруживается ошибка, то компилятор выводит сообщение с ошибкой компиляции. Я специально уберу индекс из кода
В terminal
Давайте разберёмся в ошибке. Мы видим, что ошибка в функции
Фаза 4: компоновка
Компоновка (или линковка) в языке C - это процесс, в котором компоновщик собирает различные модули кода, такие как исходные файлы и библиотеки, в один исполняемый файл. Процесс компоновки делится на следующие шаги:
1. Каждый исходный файл C компилируется в отдельный объектный файл (обычно с расширением
2. Компоновщик анализирует объектные файлы и библиотеки, чтобы определить, какие внешние ссылки (например, функции и глобальные переменные, которые определены в других файлах) необходимо разрешить;
3. Компоновщик включает в исполняемый файл библиотеки, необходимые для выполнения программы, и разрешает ссылки на функции и данные, которые определены в этих библиотеках;
4. Если в программе используются ресурсы, такие как изображения или звуки, компоновщик также включает их в исполняемый файл;
5. Наконец, компоновщик генерирует исполняемый файл, который содержит все необходимые машинные инструкции, данные и ресурсы, собранные из объектных файлов и библиотек;
После процесса компоновки у нас с вами получился исполняемый файл
Откроем исполняемый файл
Перед вами первые 10 строк файла
Каждая строка это 64-битное значение в шестнадцатеричной системе счисления. Чтобы понять содержимое файла, нужно знать архитектуру процессора и много чего ещё. Возможно, я затрону эту тему в будущем, но пока вам достаточно того что это машинный код, который выполняет процессор компьютера.
sum_nums += arr_nums[]; чтобы показать как выглядит ошибка при компиляции.В terminal
sum_nums.c: In function ‘main’:
sum_nums.c:9:30: error: expected expression before ‘]’ token
9 | sum_nums += arr_nums[];
| ^
Давайте разберёмся в ошибке. Мы видим, что ошибка в функции
main, в строке 9, видим саму строку с ошибкой error: expected expression before ‘]’ token. Ошибка нам говорит, что компилятор ожидает некое выражение перед закрытием ], что нам намекает на допущенную ошибку в синтаксисе и мы забыли что-то написать. В нашем случае мы не указали переменную i, которая отвечает за индекс. Мы должны были взять элемент по индексу из списка. Я исправлю данный код и продолжу процесс дальше. Машинный код пока рано показывать на данной стадии. Что же касается языка Python, то у него нет этапа компиляции так как это не компилируемый язык. Вместо этого у него есть процесс интерпретации, до которого мы дойдём, когда, наконец, получим исходный файл языка С чтобы сравнить процесс запуска программ.Фаза 4: компоновка
Компоновка (или линковка) в языке C - это процесс, в котором компоновщик собирает различные модули кода, такие как исходные файлы и библиотеки, в один исполняемый файл. Процесс компоновки делится на следующие шаги:
1. Каждый исходный файл C компилируется в отдельный объектный файл (обычно с расширением
.o или .obj), который содержит машинный код и информацию для компоновщика;2. Компоновщик анализирует объектные файлы и библиотеки, чтобы определить, какие внешние ссылки (например, функции и глобальные переменные, которые определены в других файлах) необходимо разрешить;
3. Компоновщик включает в исполняемый файл библиотеки, необходимые для выполнения программы, и разрешает ссылки на функции и данные, которые определены в этих библиотеках;
4. Если в программе используются ресурсы, такие как изображения или звуки, компоновщик также включает их в исполняемый файл;
5. Наконец, компоновщик генерирует исполняемый файл, который содержит все необходимые машинные инструкции, данные и ресурсы, собранные из объектных файлов и библиотек;
После процесса компоновки у нас с вами получился исполняемый файл
sum_nums. Давайте посмотрим как выглядит машинный код у него внутри.Откроем исполняемый файл
sum_nums с помощью sublime text7f45 4c46 0201 0100 0000 0000 0000 0000
0300 3e00 0100 0000 8010 0000 0000 0000
4000 0000 0000 0000 d036 0000 0000 0000
0000 0000 4000 3800 0d00 4000 1f00 1e00
0600 0000 0400 0000 4000 0000 0000 0000
4000 0000 0000 0000 4000 0000 0000 0000
d802 0000 0000 0000 d802 0000 0000 0000
0800 0000 0000 0000 0300 0000 0400 0000
1803 0000 0000 0000 1803 0000 0000 0000
1803 0000 0000 0000 1c00 0000 0000 0000
...
Перед вами первые 10 строк файла
sum_nums из 1002. Естественно, я не мог впихнуть все 1002 строки в данную статью поэтому сократил вывод =)Каждая строка это 64-битное значение в шестнадцатеричной системе счисления. Чтобы понять содержимое файла, нужно знать архитектуру процессора и много чего ещё. Возможно, я затрону эту тему в будущем, но пока вам достаточно того что это машинный код, который выполняет процессор компьютера.
🔥2👍1
В языке Python нет процесса компоновки так как это не компилируемый язык и не требуется генерировать исполняемый файл как в языке C. Однако стоит отметить, что есть такие механизмы как Cython и ctypes. Cython - статический компилятор, который позволяет языку Python компилировать код на C и C++ и вызывать его из Python3. Ctypes - это библиотека для Python, которая позволяет Python взаимодействовать с C кодом, что позволяет Python работать на более низком уровне. Правда, это касается взаимодействия языков C и Python. Это довольно интересная тема и в последующих статьях я обязательно её затрону. Сам же Python по прежнему не нужно компилировать и компоновать. Это касается только C кода, который можно использовать в коде Python.
Фаза 5: загрузка
Для того чтобы программу можно было запустить, её сначала нужно загрузить в оперативную память. В языке C эту операцию выполняет загрузчик, который читает выполняемый образ с диска и копирует его в оперативную память. Также загрузчик производит загрузку необходимых разделяемых библиотек. В языке Python программный код загружается в оперативную память полностью для того чтобы выполниться потом построчно. На этом этапе, если в коде обнаружится ошибка, то программа будет прервана. Теперь самое время запустить наши программы на обоих языках, так как выйти на эту фазу невозможно без запуска программы.
В terminal
В terminal
Фаза 6: выполнение
Наконец, мы дошли до финальной фазы - выполнение кода. На этой фазе компьютер выполняет программу, инструкция за инструкцией в языке C. Давайте посмотрим на вывод программы у программы на языке C.
В terminal
Мы видим, что программа на языке C отработала как нужно. Только вот прежде чем я расскажу, что произойдёт с программой на Python, вас будет ждать небольшой сюрприз с выполнением программы.
В terminal
До этого мы запускали программы на Python из IDE и не испытывали проблем с запуском программ. Сейчас мы видим, что у нас нет прав на файл. Разрешим права на него.
В terminal
Попробуем запустить программу после того как мы выдали права на выполнение файла для всех пользователей.
В terminal
Почему вместо привычного вывода он выводит эти странные предупреждения, ведь у нас нет ошибок в коде? Всё очень просто - это происходит потому что в нашем файле
Давайте запустим нашу программу после изменений и посмотрим на результат её выполнения.
Фаза 5: загрузка
Для того чтобы программу можно было запустить, её сначала нужно загрузить в оперативную память. В языке C эту операцию выполняет загрузчик, который читает выполняемый образ с диска и копирует его в оперативную память. Также загрузчик производит загрузку необходимых разделяемых библиотек. В языке Python программный код загружается в оперативную память полностью для того чтобы выполниться потом построчно. На этом этапе, если в коде обнаружится ошибка, то программа будет прервана. Теперь самое время запустить наши программы на обоих языках, так как выйти на эту фазу невозможно без запуска программы.
В terminal
$ ./sum_nums
В terminal
$ ./sum_nums.py
Фаза 6: выполнение
Наконец, мы дошли до финальной фазы - выполнение кода. На этой фазе компьютер выполняет программу, инструкция за инструкцией в языке C. Давайте посмотрим на вывод программы у программы на языке C.
В terminal
Сумма чисел списка = 78
Мы видим, что программа на языке C отработала как нужно. Только вот прежде чем я расскажу, что произойдёт с программой на Python, вас будет ждать небольшой сюрприз с выполнением программы.
В terminal
bash: ./sum_nums.py: Отказано в доступе
До этого мы запускали программы на Python из IDE и не испытывали проблем с запуском программ. Сейчас мы видим, что у нас нет прав на файл. Разрешим права на него.
В terminal
chmod +x sum_nums.py
Попробуем запустить программу после того как мы выдали права на выполнение файла для всех пользователей.
В terminal
$ ./sum_nums.py
./sum_nums.py: строка 1: nums_list: команда не найдена
./sum_nums.py: строка 2: sum_nums: команда не найдена
./sum_nums.py: строка 5: синтаксическая ошибка рядом с неожиданным маркером «sum_nums»
./sum_nums.py: строка 5: ` sum_nums += num'
Почему вместо привычного вывода он выводит эти странные предупреждения, ведь у нас нет ошибок в коде? Всё очень просто - это происходит потому что в нашем файле
sum_nums.py нет строки, которая бы указывала нам на интерпретатор Python. В Debian или Ubuntu она пытается выполниться как скрипт shell. Именно поэтому мы видим вывод неких ошибок при запуске. Поправим это, добавив на первую строчку кода #!/usr/bin/env python3. Строка #!/usr/bin/env python3 называется шебанг (shebang), которая указывает путь до интерпретатора Python. Таким образом в программе будет информация о нахождении интерпретатора Python, к которому следует обратиться для выполнения программы. Наш код теперь будет выглядеть вот так.#!/usr/bin/env python3
nums_list = [1, 3, 4, 50, 20]
sum_nums = 0
for num in nums_list:
sum_nums += num
print(f'Сумма чисел списка = {sum_nums}')
Давайте запустим нашу программу после изменений и посмотрим на результат её выполнения.
$ ./sum_nums.py
Сумма чисел списка = 78
🔥4