Python Lounge: работа и стажировки для программистов – Telegram
Python Lounge: работа и стажировки для программистов
3.91K subscribers
93 photos
1.17K links
Здесь можно найти интересующую вас работу и стажировки для программистов, а так же полезные статьи про Python.

Размещение вакансии только - @perezvonyubot

Ссылка на канал: @python_lounge

Мы входим в сеть promopoisk.com

Реклама: @adtgassetsbot
Download Telegram
Контекстные менеджеры

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

Простейшей функцией, использующей данный протокол является функция open(). Каждый раз, когда мы открываем файл, нам необходимо его закрыть, чтобы вытолкнуть выходные данные на диск (на самом деле Python вызывает метод close() автоматически, но явное его использование является хорошим тоном). Например:

file = open("file.txt", "w")
file.write("Hello, World")
file.close()


Чтобы каждый раз не вызывать метод close() мы можем воспользоваться контекстным менеджером функции open(), который автоматически закроет файл после выхода из блока:

with open("file.txt", "w") as file:
file.write("Hello, World")


Здесь нам не нужно каждый раз вызывать метод close, чтобы вытолкнуть данные в файл. Из этого следует, что контекстный менеджер используется для выполнения каких-либо действий до входа в блок и после выхода из него. Но функциональность контекстных менеджеров на этом не заканчивается.
Реализация класса контекстного менеджера

Начнем с того, что в контекстном менеджере должны быть определены методы __enter__ и __exit__. Давайте создадим наш собственный менеджер контекста для открытия файлов и поймем суть его работы.

class NewOpen(object):
   def __init__(self, file_name, mode):
       self.file = open(file_name, mode)
   def __enter__(self):
       return self.file
   def __exit__(self, type, value, traceback):
       self.file.close()

Просто определив методы __enter__ и __exit__, мы можем использовать наш новый класс с оператором with. Давайте попробуем:

with NewOpen('test.txt', 'w') as file:
   file.write('Hello, world!')

Наш метод __exit__ принимает три аргумента. Они требуются для каждого метода __exit__, который является частью класса.

# test
В прошлых уроках мы научились рисовать графики и добавлять кнопки, в этом уроке мы с вами научимся располагать виджеты по нашему усмотрению

Tkinter: часть 3
Кэширование функций

Кэширование может сэкономить время, когда связанная с вводом или выводом функция периодически вызывается с одинаковыми аргументами. До Python 3.2 мы должны были написать собственную реализацию. В Python 3.2+ есть декоратор lru_cache, который позволяет нам быстро кэшировать и вскрывать возвращаемые значения функции.

Давайте реализуем калькулятор чисел Фибоначчи с использованием кэша.

from functools import lru_cache

@lru_cache(maxsize=32)
def fib(n):
if n < 2:
return n
return fib(n - 1) + fib(n - 2)

>>> print([fib(n) for n in range(10)])
# Output: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

Советую попробовать запустить любую рекурсивную функцию с кэшированием и без него, прирост в скорости замечается сразу.
Forwarded from Hello World
is vs ==

Два списка указывают на один и тот же объект:
>>> a = [1, 2, 3]
>>> b = a


Результат:
>>> a is b
True
>>> a == b
True


Пробуем создать абсолютно новый объект:
>>> c = a[:]


Результат:
>>> a == c
True
>>> a is c
False


📎 is возвратит True, если обе переменные ссылаются на один объект

📎 == возвратит True, если сравниваемые объекты идентичны

#tips
Учимся работать с полями для пользовательского ввода и вывода данных, а также практикуемся в использовании кнопок

Tkinter: часть 4
Использование списков в качестве стеков

Стек — абстрактный тип данных, представляющий собой список элементов, организованных по принципу LIFO (англ. last in — first out, «последним пришёл — первым вышел»).

Методы встроенного списка в Python позволяют очень легко использовать список в виде стека. Чтобы добавить элемент на вершину стека, используйте append(). Чтобы извлечь элемент из верхней части стека, используйте pop() без явного индекса. Пример:

>>> stack = [3, 4, 5]
>>> stack.append(6)
>>> stack
[3, 4, 5, 6]
>>> stack.pop()
6
>>> stack
[3, 4, 5]
>>> stack.pop()
5
Выражение del

Существует способ удалить элемент из списка по его индексу, а не по значению - с помощью оператора del. Это отличается от метода pop(), который возвращает значение. Оператор del также можно использовать для удаления фрагментов из списка или очистки всего списка. Например:

>>> a = [1, 2, 3, 4, 5, 6]
>>> del a[0]
>>> a
[2, 3, 4, 5, 6]
>>> del a[2:4]
>>> a
[2, 3, 6]
>>> del a[:]
>>> a
[]

del также может быть использован для удаления целых переменных:

>>> del a

Обращение к этой переменной в дальнейшем вызовет ошибку (по крайней мере, пока ей не присвоено другое значение).
"Быстрый" контейнер deque

Deque может быть реализован на Python с помощью модуля collections. Deque предпочтительнее, чем обычный список, в тех случаях, когда нам нужны более быстрые операции добавления и вытягивания элементо из обоих концов контейнера, поскольку deque обеспечивает линейную сложность O(1) для операций добавления и выталкивания по сравнению со списком, у которого сложность по времени для тех операций составляет O(n). Вот пример основных методов:

>>> from collections import deque
>>> x = deque([1, 2, 3])
>>> x.append(4)
>>> x.appendleft(0)
>>> x
deque([0, 1, 2, 3, 4])
>>> x.pop()
4
>>> x.popleft()
0
>>> x
deque([1, 2, 3])

Также для deque есть возможность использовать стандартные функции по типу sum, min, max и тому подобные.
Создаем свой простенький локер - вирус, блокирующий компьютер; а также используем новый интересный модуль

Tkinter: часть 5
Сохраняем данные с помощью pickle

Модуль pickle реализует двоичное сохранение объектных структур в Python. Однако будьте осторожнее, pickle не защищен от ошибочных или вредоносных данных. Никогда не извлекайте данные, полученные из ненадежных или не прошедших проверку подлинности источников.

Для начала поробуем сохранить, к примеру, список из различных типов данных.

import pickle

x = ['abc', 67, 3.14]

with open('data', 'wb') as file:
   pickle.dump(x, file)

Данные успешно сохранены, теперь откроем и убедимся в их сохранности.

with open('data', 'rb') as file:
   x = pickle.load(file)

print(x)

# Out: ['abc', 67, 3.14]

Что сохранили, то и получили - всё верно. В итоге, pickle - хорошее решение, на случай, когда требуется сохранить что-либо, а на написание полноценной базы данных нет времени.
Switch-конструкция с помощью словаря

К сожалению, в Python не существует switch-конструкций, в отличие от большинства других языков программирования, и поэтому приходится строить башни из условных операторов в своём коде.

Однако есть одно хитрое решение — использовать словарь, где значениями будут функции. Например, напишем словарь, который будет использован для математических операторов.

switch = {
'+': lambda x, y: x + y,
'-': lambda x, y: x - y,
'*': lambda x, y: x * y,
'/': lambda x, y: x / y
}

В этом примере были использованы lambda-функции для простоты, но вместо них можете подставить любые другие. Для тех, кто не знает: lambda - объявление анонимной функции (можно косвенно сравнить с def); x, y - принимаемые аргументы; x + y - то, что функция возвращает.

result = switch['*'](4, 5)
print(result)
# Output: 20

Примерно вот так мы можем пользоваться подобной штукой. Думаю, что многие найдут полезное применение подобному использованию словарей.
​​Как одной математической формулой по номеру месяца посчитать количество дней в нем?

Попробуем написать функцию f(x), которая бы давала следующий список значений (таблица №1), то есть количество дней в месяцах. Помимо стандартных арифметических операций, мы будем использовать целочисленное деление и взятие остатка по модулю.

Обычно количество дней в месяце колеблется между 30 и 31. При этом, можно заметить зависимость этого числа от четности месяца — значит, воспользуемся операцией взятия остатка по модулю 2. Кажется, это должно быть нечто, вроде:

f₁(x) = 30 + x % 2
# таблица №2

Пока что не обращая внимания на февраль, нам нужно, чтобы +1 в делимом «активировалось» только при достижении аргументом значений, больших 8. При этом значения аргумента не могут превосходить 12. Значит, нам идеально подойдет целочисленное деление аргумента на 8:

f₃(x) = 30 + (x + x // 8) % 2
# таблица №3

Все правильно, кроме февраля. Как неожиданно. В самой последней версии нашей формулы февралю достались целых 30 дней. А потому нам нужно отсечь у него пару дней. Естественно, от этого пострадают и еще какие-то месяцы, поэтому нам придется пожертвовать именно январем, затем подправив формулу и для него. Отсечь дни для первого и второго месяцев можно с помощью выражения 2 % x. Тогда наша формула принимает уже следующий вид:

f₄(x) = 28 + (x + x // 8) % 2 + 2 % x
# таблица №4

Остался последний шаг — подлатать январь. Это сделать не так сложно: просто добавим 2 дня только к нему, т.е. к такому месяцу, чей номер меньше либо равен единице. Как вам идея использовать для этой цели 1 // x? Проверяем:

f₅(x) = 28 + (x + x // 8) % 2 + 2 % x + 1 // x * 2
# таблица №5

Превосходно, 12 из 12. Подобная функция на языке Python может быть записана следующим образом:

f = lambda x: 28 + (x + x // 8) % 2 + 2 % x + 1 // x * 2
print(f'В июне {f(6)} дней')
# Out: В июне 30 дней
urlencode

Довольно часто приходится работать с разнообразными API и совершать get-запросы с передачей множества параметров. Чаще всего составление запроса в коде выглядит примерно так:

url = 'https://example.com?item={}&size={}&color={}&amount={}'.format('t-shirt', 'M', 'white', 5)

Смотрится не слишком презентабельно, однако есть слегка длиннее, но значительно улучающий читаемость вариант – функция urlencode из из модуля urllib:

from urllib.parse import urlencode

url = 'https://example.com'
params = {
'item': 't-shirt',
'size': 'M',
'color': 'white',
'amount': 5
}

encoded_params = urlencode(params)
url += '?' + encoded_params
print(url)

# Output: example.com?item=t-shirt&size=M&color=white&amount=5

P. S. Приносим извинения за настолько долгое отсутствие постов, возобновляем работу над каналом.
Абстрактные методы в Python

В абстрактном классе обычно реализуется общая часть нескольких сущностей или другими словами - абстрактная сущность.

Абстрактный метод – это метод, который не имеет своей реализации в базовом классе, и он должен быть реализован в классе-наследнике. 

Для того, чтобы создать абстрактный класс с абстрактными методами, надо импортировать вспомогательные метакласс ABCMeta и декоратор abstractmethod из модуля abc.

from abc import ABCMeta, abstractmethod

class AbstractClass(metaclass=ABCMeta):
@abstractmethod
def function(self):
pass

Если мы отнаследуем новый класс от абстрактного класса, не переопределив абстрактные методы (в данном случае function), и попробуем создать экземпляр, то получим исключение:

class BadExample(AbstractClass):
pass

child = BadExample() 
# TypeError: Can't instantiate abstract class BadExample with abstract methods function

Для того, чтобы код заработал корректно, нам необходимо переопределить все абстрактные методы. То есть по сути еще раз просто написать функцию, но уже в новом классе.

class GoodExample(AbstractClass):
def function(self):
print('Everything is ok')

anotherchild = GoodExample()
Паттерн проектирования Singleton

Одиночка или же синглтон – это паттерн проектирования, описывающий объект, у которого имеется один единственный экземпляр. 

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

new__(cls, *args, **kwargs) –
– вызывается для создания экземпляра класса, перед вызовом __init. На вход первым аргументом метод принимает сам класс, а возвращать должен уже экземпляр (даже можно экземпляр и другого класса).

class Singleton:
instance = None

def __new__(cls):
     if cls.instance is None:
       cls.instance = super().__new__(cls)

     return cls.instance

Здесь мы проверяем, есть ли значение у атрибута instance. Если нет, то присваиваем атрибуту экземпляр этого же класса. А если уже экземпляр создан, то просто его возвращаем.

То есть при вызове конструктора класса Singleton, будет возвращаться один и тот же объект из памяти.

a = Singleton()
b = Singleton()

Создали два экземпляра, теперь убедимся, что они содержат одинаковый объект.

print(a is b) # True
Модуль os

В данном посте мы не будем изучать от начала до конца этот модуль, а просто пройдемся по основным методам. Вкратце, os предоставляет функции для работы с операционной системой.

1. Отображение текущей рабочей директории.

>>> os.getcwd()
'/Users/Adrian'

2. Получение списка папок и файлов в текущей директории.

>>> os.listdir()
['Music', 'Pictures', 'Desktop', 'Library', 'Public', 'Movies', 'Applications', 'Documents', 'Downloads']

3. Смена рабочей директории.

>>> os.chdir('Documents')

4. Создание и удаление папок.

>>> os.mkdir('new_folder')
>>> os.rmdir('new_folder')

5. Отправка команд в терминал.

>>> os.system('echo hello')
hello
Неправильное использование выражений как значений по умолчанию для аргументов функции

Python позволяет указать, что аргумент функции является необязательным, предоставив для него значение по умолчанию. Хотя это отличная особенность языка, она может привести к некоторой путанице, когда значение по умолчанию является изменяемым. Например, рассмотрим определение такой функции:

>>> def foo(bar=[]):
...  bar.append('baz')
...  return bar

Распространенной ошибкой является мысль, что для необязательного аргумента будет задано указанное выражение по умолчанию каждый раз, когда вызывается функция, без указания значения для необязательного аргумента. Например, в приведенном выше коде можно ожидать, что повторный вызов foo() всегда будет возвращать ['baz'], поскольку предполагается, что каждый раз, когда вызывается foo(), bar установлен на [].

>>> foo()
['baz']
>>> foo()
['baz', 'baz']
>>> foo()
['baz', 'baz', 'baz']

Ответ на вопрос “почему так происходит?” заключается в том, что значение по умолчанию для аргумента функции создается только один раз, во время определения функции. Таким образом, аргумент bar инициализируется по умолчанию только тогда, когда foo() определен впервые, но затем вызовы foo() продолжат использовать тот же список для какой bar был изначально инициализирован.

Чаще всего такую ситуацию обходят примерно следующим образом:

>>> def foo(bar=None):
...   if bar is None:
...     bar = []
...   bar.append('baz')
...   return bar
... 
>>> foo()
['baz']
>>> foo()
['baz']
>>> foo()
['baz']

# test
​​Рубрика #Проекты

Буквально вчера я закончил переписывать того самого бота, который давал погоду в визуальном формате. Из глобальных обновлений: появилась возможность смены языка и просмотр публичной статистики. 

И теперь этот бот доступен по новой ссылке – @TeleWeatherRobot

А также делюсь с вами исходным кодом – https://github.com/adreex/TeleWeatherBot (поставьте звездочку проекту, плз)

P. S. буду благодарен за все баг-репорты в лс или в чат канала.
Python packages

Предположим, вы разрабатываете большое приложение, которое включает в себя множество модулей. Очевидно, что складывать всё в одну папку не просто неудобно, а в некоторых случаях даже нерационально. Создадим для примера модуль main.py и рядом с ним пакет с модулями (папку с файлами) примерно в таком виде:

├── main.py
└── package
  ├── __init__.py
  ├── module1.py
  └── module2.py

Модуль __init__.py нужен для инициализации пакета, а также он вызывается при импорте пакета или модулей из него. Тем не менее, __init__.py может был пустым, достаточно его присутствия. Простыми словами, такой модуль нужен для того, работать с папкой как с Python-пакетом.

В main.py мы уже можем импортировать пакет и модули примерно такими способами:

import package
from package import module1
import package.module2 as m2

Предположим, что у нас есть уже какие-то функции в module1.py и module2.py. Теперь давайте напишем кое-что в __init__.py для примера:

from .module1 import function1
from . import module2 as m2

variable = 'hello from __init__.py'

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

Теперь в main.py мы можем выполнить следующие команды:

from package import function1
from package import m2
from package import variable

Возможности пакетов и модулей в Python этим не ограничиваются, но для вступления и ознакомления этой информации должно хватить.