Показываем уведомления на рабочем столе
На macOS это очень просто, даже не нужно ставить дополнительный софт и модули, а использовать встроенный osascript.
На Linux можно пойти схожим путем, задействуя программу notify-send (если у вас Ubuntu, то она почти наверняка уже установлена):
Разработчики на Windows, и о вас я не забуду. Попробуйте win10toast.
Есть ли кросс-платформенное решение? Да, это библиотека plyer от создателей Kivy.
plyer умеет не только уведомления, но и предоставляет унифицированный интерфейс к всевозможным API декстопных и мобильных ОС.
Однако, plyer потребует установки дополнительного софта или модулей для каждой платформы. Когда вы в первый раз запустите код, не удивляйтесь ошибкам. Например, на macOS мне потребовалось установить Cython и pyobjus. Библиотека plyer сам по себе не вытягивает эти зависимости, поэтому в вашем проекте не забудьте их добавить самостоятельно (например, в requirements.txt)
На macOS это очень просто, даже не нужно ставить дополнительный софт и модули, а использовать встроенный osascript.
import os
def notify_macos(title, text):
os.system("""
osascript -e 'display notification "{}" with title "{}"'
""".format(text, title))notify_macos("Поздравляю", "Ген супер-человека найден!")На Linux можно пойти схожим путем, задействуя программу notify-send (если у вас Ubuntu, то она почти наверняка уже установлена):
import subprocess as s
def notify_linux(message, title):
subprocess.Popen(['notify-send', title, message])
return
Разработчики на Windows, и о вас я не забуду. Попробуйте win10toast.
# pip install win10toast
from win10toast import ToastNotifier
toaster = ToastNotifier()
toaster.show_toast("Заголовок",
"Текст",
duration=5)
Есть ли кросс-платформенное решение? Да, это библиотека plyer от создателей Kivy.
# pip install plyer
from plyer import notification
notification.notify(
title='Заголовок',
message='Сообщение',
app_icon=None, # e.g. 'C:\\icon_32x32.ico'
timeout=5, # секунд
)
plyer умеет не только уведомления, но и предоставляет унифицированный интерфейс к всевозможным API декстопных и мобильных ОС.
Однако, plyer потребует установки дополнительного софта или модулей для каждой платформы. Когда вы в первый раз запустите код, не удивляйтесь ошибкам. Например, на macOS мне потребовалось установить Cython и pyobjus. Библиотека plyer сам по себе не вытягивает эти зависимости, поэтому в вашем проекте не забудьте их добавить самостоятельно (например, в requirements.txt)
Счетчик itertools.count
Если вам нужно считать неизвестное заранее количество шагов цикла
Можно написать более лаконично, делегировав функциональность по счету к
Если вам нужно считать неизвестное заранее количество шагов цикла
while, то в место кода вида:attempt = 1
while True:
...
attempt += 1Можно написать более лаконично, делегировав функциональность по счету к
count:from itertools import count
for attempt in count(1):
...
count(start=0, step=1) – бесконечный итератор, который выдает возрастрающую последовательность чисел. По умолчанию счет начинается с 0 с шагом 1: 0, 1, 2, 3, 4, ... Но можно и настроить: первый аргумент – начальное значение, второй – шаг. Таким образом, count(2, 3) выдаст 2, 5, 8, 11, ...О наследовании атрибутов
Видел тут на одном из каналов задачку про поле класса и наследование. Загадывать вам ее не буду, но объяснение приведу. Пусть:
Тут понятно и новичку, что поле foo вроде как "наследуется" классами Barak и Clara у класса Abram. Однако, давайте попробуем его поменять:
Видим, что у класса Barak и Clara значение стало 30, а
Работает это так. При поиске атрибута класса сначала спрашивается у самого класса, есть ли у него этот атрибут, если да, то он вернется, если нет, то идут к следующему классу, который старше по иерархии наследования (Clara → Barak → Abram → object). Если у него тоже нет, то идут еще дальше, пока не найдут, иначе возникнет исключение AttributeError.
В нашем примере будем рассуждать с конца. Чему равно
Предок класса Clara – класс Barak. Как только мы написали
А до этого атрибут foo был изначально только у Abram. Если теперь написать
Вывод: как только мы присвоим атрибут, то атрибуты классов-предков перестают на него влиять. Будьте внимательны, ведь такая же логика действует и для методов класса.
Видел тут на одном из каналов задачку про поле класса и наследование. Загадывать вам ее не буду, но объяснение приведу. Пусть:
class Abram:
foo = 10
class Barak(Abram):
pass
class Clara(Barak):
pass
print(Abram.foo, Barak.foo, Clara.foo) # 10 10 10Тут понятно и новичку, что поле foo вроде как "наследуется" классами Barak и Clara у класса Abram. Однако, давайте попробуем его поменять:
Abram.foo = 20
print(Abram.foo, Barak.foo, Clara.foo) # 20 20 20
Barak.foo = 30
print(Abram.foo, Barak.foo, Clara.foo) # 20 30 30
Abram.foo = 40
print(Abram.foo, Barak.foo, Clara.foo) # 40 30 30Видим, что у класса Barak и Clara значение стало 30, а
Abram.foo живет своей жизнью после Barak.foo = 30 и не перестало влиять на прочие классы.Работает это так. При поиске атрибута класса сначала спрашивается у самого класса, есть ли у него этот атрибут, если да, то он вернется, если нет, то идут к следующему классу, который старше по иерархии наследования (Clara → Barak → Abram → object). Если у него тоже нет, то идут еще дальше, пока не найдут, иначе возникнет исключение AttributeError.
В нашем примере будем рассуждать с конца. Чему равно
Clara.foo? Есть ли атрибут foo у Clara? Вообще говоря, его нет, ведь мы ни разу не присваивали ничего к Clara.foo:>>> 'foo' in Clara.__dict__
False
Предок класса Clara – класс Barak. Как только мы написали
Barak.foo = 30 в классе Barak появился свой собственный foo:>>> Barak.foo = 20
>>> 'foo' in Barak.__dict__
True
А до этого атрибут foo был изначально только у Abram. Если теперь написать
Clara.foo = 50, то у каждого из классов будет свой foo.Clara.foo = 50
print(Abram.foo, Barak.foo, Clara.foo) # 40 30 50
Вывод: как только мы присвоим атрибут, то атрибуты классов-предков перестают на него влиять. Будьте внимательны, ведь такая же логика действует и для методов класса.
Как узнать имя переменной?
Какой-то из каналов про Python писал, что это невозможно узнать имя переменной, которой мы что-то присвоили. Это не совсем так. Представляю вам функцию, которая вернет все имена, ассоциированные с переданным ей объектом. Она использует модуль inspect, который позволяет узнать о загруженном в Python коде все, что можно только придумать, в том числе и имена переменных:
Тестируем:
Так как имен может быть несколько, то возвращается список. Кроме того, может быть ситуация, когда в список запрячутся посторонние имена. Например, на None могут ссылаться встроенные переменные интерпретатора:
Зачем это вообще нужно? Например, можно сделать функцию, что будет составлять словарь из переменных по их именам:
Это весело, но, пожалуйста, будьте с этим осторожны, так как код выше примитивен и написан только в демонстрационных целях. Я уже отмечал, что find_names может зацепить не те имена, поэтому не используйте его в своих программах, если нет очень веских на это причин.
#хаки #секреты
Какой-то из каналов про Python писал, что это невозможно узнать имя переменной, которой мы что-то присвоили. Это не совсем так. Представляю вам функцию, которая вернет все имена, ассоциированные с переданным ей объектом. Она использует модуль inspect, который позволяет узнать о загруженном в Python коде все, что можно только придумать, в том числе и имена переменных:
def find_names(obj):
import inspect
# currentframe - текущий контекст выполнения, т.е. эта же функция
# а f_back - фрейм код, который ее вызвал
parent_frame = inspect.currentframe().f_back
# соберем все глобальные и локальные переменные вызывающего кода
# это словарь имя переменной: ее значение
search = {**parent_frame.f_globals, **parent_frame.f_locals}
for name, v in search.items():
# если переменная ЯВЛЯЕТСЯ искомым объектом вернем ее имя
if v is obj:
yield nameТестируем:
class A: ...
x = A()
y = x
print(list(find_names(x))) # ['x', 'y']Так как имен может быть несколько, то возвращается список. Кроме того, может быть ситуация, когда в список запрячутся посторонние имена. Например, на None могут ссылаться встроенные переменные интерпретатора:
a = None
print(list(find_names(a)))
# ['__doc__', '__package__', '__spec__', '__cached__', 'a']Зачем это вообще нужно? Например, можно сделать функцию, что будет составлять словарь из переменных по их именам:
def make_dict(*args):
return {next(find_names(_arg)): _arg for _arg in args}
a, b, c = 10, 20, 30
d = make_dict(a, b, c)
print(d) # {'a': 10, 'b': 20, 'c': 30}Это весело, но, пожалуйста, будьте с этим осторожны, так как код выше примитивен и написан только в демонстрационных целях. Я уже отмечал, что find_names может зацепить не те имена, поэтому не используйте его в своих программах, если нет очень веских на это причин.
#хаки #секреты
NumPy-бродкастинг
Можно ли сложить NumPy-массивы совершенно разных форм?
Оказывается, да! Не будет никаких ошибок, а форма результата будет
Чтобы бродкастинг работал, формы должны быть все-таки совместимы. Вы выравниваем их друг под другом по правому краю и начинаем сравнивать каждый столбик справа налево (от более глубоких уровней вложенности до наружных). Если числа в столбиках равны – прекрасно, действие не требуется. Если в какое-то число в столбике – единица (1), то не беда, это измерение будет копировано столько раз, сколько нужно, чтобы уравнять размеры. А если размерности не хватает, она будет добавлена (это равносильно единице).
Кстати, кто из читателей знает, как выключить бродкастинг, пишите в наш чат. Лично я не нашел способа, а предложения со Stackoverflow оказались нерабочими.
#numpy #datascience
Можно ли сложить NumPy-массивы совершенно разных форм?
import numpy as np
a = np.ones((8, 1, 6, 1))
b = np.ones((7, 1, 5))
(a + b).shape # ?Оказывается, да! Не будет никаких ошибок, а форма результата будет
(8, 7, 6, 5). Интересно, как это получается? Дело в том, что здесь работает механизм бродкастинга (broadcasting), когда недостающие размеры расширяются путем "копирования" данных. А когда формы массивов выровнены, происходит простое поэлементное сложение.Чтобы бродкастинг работал, формы должны быть все-таки совместимы. Вы выравниваем их друг под другом по правому краю и начинаем сравнивать каждый столбик справа налево (от более глубоких уровней вложенности до наружных). Если числа в столбиках равны – прекрасно, действие не требуется. Если в какое-то число в столбике – единица (1), то не беда, это измерение будет копировано столько раз, сколько нужно, чтобы уравнять размеры. А если размерности не хватает, она будет добавлена (это равносильно единице).
A (4d массив): 8 x 1 x 6 x 1
B (3d массив): 7 x 1 x 5
Результат (4d массив): 8 x 7 x 6 x 5Кстати, кто из читателей знает, как выключить бродкастинг, пишите в наш чат. Лично я не нашел способа, а предложения со Stackoverflow оказались нерабочими.
#numpy #datascience
tirinox.ru
NumPy-бродкастинг
Эта тема не очень освещена на русском языке, но является весьма важной по паре причин: бродкастинг упрощает жизнь, и порой он же ее усложняет. Давайте разберемся что это, и как оно работает? Бродкастинг (broadcasting) – автоматическое расширение размерности…
Чтобы сохранять и загружать данные на уровне отдельных байтов пригодится модуль struct.
Форматная строка указывает в какой последовательности и какие типы данных упакованы в байты. За ней следуют сами данные. Вот пример упаковки:
И распаковки:
Приглашаю прочитать статью про struct, где вы найдете:
• Объяснение форматов
• Таблицы типов данных
• Little vs big endian
• Много примеров
Форматная строка указывает в какой последовательности и какие типы данных упакованы в байты. За ней следуют сами данные. Вот пример упаковки:
>>> import struct
>>> struct.pack('>hhl', 1, 2, 3)
b'\x00\x01\x00\x02\x00\x00\x00\x03'
И распаковки:
>>> struct.unpack('>hhl', _)
(1, 2, 3)
Приглашаю прочитать статью про struct, где вы найдете:
• Объяснение форматов
• Таблицы типов данных
• Little vs big endian
• Много примеров
tirinox.ru
Пакуем байты на Python: struct
Кто сказал, что нельзя делать низкоуровневые вещи на Python? Конечно, можно. Давайте научимся упаковывать данные из Python в байты и распаковывать их обратно. Встроенный модуль struct как раз создан для этих целей. В низкоуровневом деле важны детали, а именно…
Задачка. Имеется такой код, где мы делаем 5 записей в словарь:
d = {}
d[float('nan')] = 1
d[float('nan')] = 2
d[1.0] = 'float'
d[1] = 'int'
d[True] = 'bool'
print(len(d))🌷Всех дам поздравляю с Международным женским днем! 🌷
Желаю вам счастья, любви, здоровья, отличного настроения, улыбок, солнца на улице и в душе!
Мы вас очень любим и ценим!
[код]
Желаю вам счастья, любви, здоровья, отличного настроения, улыбок, солнца на улице и в душе!
Мы вас очень любим и ценим!
[код]
Решение предыдущей задачи
Если кратко, то при поиске словарь проверяет сначала хэш (hash) от ключей. Разные хэши – разные ключи – разные записи. Если хэши равны, то проверяется простое равенство (==) ключей. Если и они равны, то считается, что это один и тот же ключ, и ему отвечает одна и та же запись в словаре.
Все
Кстати, спрашивали, как добраться до этих nan. Вот так:
Теперь ситуация с ключами
Поэтому для словаря – ключи
Таким образом, у нас будет 2 записи от двух nan, и одна запись от
Если кратко, то при поиске словарь проверяет сначала хэш (hash) от ключей. Разные хэши – разные ключи – разные записи. Если хэши равны, то проверяется простое равенство (==) ключей. Если и они равны, то считается, что это один и тот же ключ, и ему отвечает одна и та же запись в словаре.
Все
float('nan') имеют одинаковый хэши, но значение NaN (not a number – не число), не равно никакому другому float, включая само себя и другие float('nan'), поэтому для словаря все nan – разные ключи, и каждому из них отвечает отдельная запись.>>> float('nan') == float('nan')
False
>>> hash(float('nan'))
0
>>> {float('nan'): 1, float('nan'): 2}
{nan: 1, nan: 2}Кстати, спрашивали, как добраться до этих nan. Вот так:
>>> keys = list(d.keys()) # список ключей
>>> d[keys[0]], d[keys[1]] # по ключам добираемся до значений
(1, 2)
>>> del d[keys[0]] # убрать одноТеперь ситуация с ключами
1, 1.0, True. Оказывается, их хэши тоже равны между собой. Нюанс в том, что и сами они равны между собой!>>> hash(1), hash(1.0), hash(True)
(1, 1, 1)
>>> 1 == 1.0 == True
TrueПоэтому для словаря – ключи
1, 1.0, True – одинаковые и дают доступ к одной и той же записи. Фактический ключ будет тот, что был записан самым первым.Таким образом, у нас будет 2 записи от двух nan, и одна запись от
1, 1.0, True. Итого, ответ – 3.Танчики на PyGame
Занятые вышли дни, поэтому не смог написать новых статей. Но, чтобы вы не скучали, вот вам один из моих проектов – Танчики на PyGame.
Игра хоть и не доделана полностью: в ней нет меню, звуков и редактора, но геймплей вполне работоспособный. Танчики спавнятся, атакуют, взрываются, стены разрушаются.
Управление – стрелки и пробел на выстрел.
Возможно, кому-то код пригодится, как учебное пособие, или вдруг найдутся добровольцы, которые внесут в него свой вклад. Ссылка на GitHub.
Занятые вышли дни, поэтому не смог написать новых статей. Но, чтобы вы не скучали, вот вам один из моих проектов – Танчики на PyGame.
Игра хоть и не доделана полностью: в ней нет меню, звуков и редактора, но геймплей вполне работоспособный. Танчики спавнятся, атакуют, взрываются, стены разрушаются.
Управление – стрелки и пробел на выстрел.
main.py – точка входа. Инициализирует PyGame, создает класс Game, обрабатывает ввод с клавиатуры.ai.py – интеллект врагов, включая алгоритм их появления.bonus.py – игровой объект бонуса.bonus_field_protect.py – алгоритм работы бонуса на защиту базы.config.py – конфигурация и ключи запуска.discrete_map.py – объект дискретной 2D карты (нужна для карты поля боя и карты для столкновений).explosion.py – игровой объект взрыва.field.py – игровой объект поля боя, обрабатывает столкновения и разрушение мира.game.py – собирает все объекты вместе и связывает события.my_base.py – игровой объект базы игрока (орел).projectile.py – игровой объект снаряда.score_node.py – игровой объект очков при уничтожении врага.spritesheet.py – загрузчик спрайтов из одной сборной текстуры.tank.py – игровой объект любого танка (своего или вражеского).ui.py – элементы пользовательского интерфейса.util.py – вспомогательные функции и классы, включая аниматор, таймер и базовый игровой объект.Возможно, кому-то код пригодится, как учебное пособие, или вдруг найдутся добровольцы, которые внесут в него свой вклад. Ссылка на GitHub.
Думаю, вы знаете, что при форматировании можно задавать параметры, например, число знаков для дробных чисел или выравнивание текста:
Эти параметры тоже можно задать динамически. Нет нужды дважды вызывать
Также вы без проблем можете получать доступ к элементам списков, словарей или объектов прямо внутри форматных строк:
С богатыми возможностями форматирования вы можете познакомиться на сайте https://pyformat.info/ (англ.)
От себя еще добавлю, что f-строки еще круче, чем
Главное условие, чтобы это выражение допускало обертывание в круглые скобки, поэтому нельзя вот так:
Вообще, способность вычислять выражения внутри строк и подставлять результат в нужно место строки называется: "интерполяция строк". Она работает не зависимо от типа кавычек строки, главно наличии буквы f перед строкой.
>>> '{:.3}'.format(2.7182)
'2.72'
>>> '{:^15}'.format('hello')
' hello 'Эти параметры тоже можно задать динамически. Нет нужды дважды вызывать
format, а достаточно просто добавить фигурные скобки внутрь фигурных скобок:>>> '{:.{prec}}'.format(2.7182, prec=3)
'2.72'
>>> '{:{align}{width}}'.format('hello', align='^', width=15)
' hello 'Также вы без проблем можете получать доступ к элементам списков, словарей или объектов прямо внутри форматных строк:
data = [4, 8, 15, 16, 23, 42]
'{d[4]} {d[5]}'.format(d=data)
# '23 42'
class Plant(object):
type = 'tree'
'{p.type}'.format(p=Plant())С богатыми возможностями форматирования вы можете познакомиться на сайте https://pyformat.info/ (англ.)
От себя еще добавлю, что f-строки еще круче, чем
''.format(...): внутри фигурных скобок возможно поставить вообще любое валидное Python выражение, хоть вызов функций:>>> f'2 + 2 = {2 + 2}'
'2 + 2 = 4'
>>> f'sqrt(2) = {2**0.5:.5}'
'sqrt(2) = 1.4142'
>>> data = [1, 2, 3, 4]
>>> f'data sum = {sum(data)}'
'data sum = 10'Главное условие, чтобы это выражение допускало обертывание в круглые скобки, поэтому нельзя вот так:
>>> f'{import os}'
File "<fstring>", line 1
(import os)
^
SyntaxError: invalid syntaxВообще, способность вычислять выражения внутри строк и подставлять результат в нужно место строки называется: "интерполяция строк". Она работает не зависимо от типа кавычек строки, главно наличии буквы f перед строкой.
📕 #Библиотека XlsxWriter
Белые воротнички не умеют читать файлы JSON? Начальник требует от вас выгружать отчеты в ламповой Эксельке? Не беда. Библиотека XlsxWriter поможет все автоматизировать без головной боли. Просто взгляните на код:
В статье больше примеров!
#xls #excel
Белые воротнички не умеют читать файлы JSON? Начальник требует от вас выгружать отчеты в ламповой Эксельке? Не беда. Библиотека XlsxWriter поможет все автоматизировать без головной боли. Просто взгляните на код:
import xlsxwriter
# откроем файл на запись
workbook = xlsxwriter.Workbook('my_report.xlsx')
# создадим лист
worksheet = workbook.add_worksheet()
# данные
expenses = (
['Аренда', 1000],
['Комуналка', 100],
['Еда', 300],
['Качалка', 50],
)
# формат для денег
money = workbook.add_format({'num_format': '#,##0"₽"'})
# формат жирности шрифта
bold = workbook.add_format({'bold': True})
worksheet.write('A1', 'Наименование', bold)
worksheet.write('B1', 'Потрачено', bold)
for i, (item, cost) in enumerate(expenses, start=2):
worksheet.write(f'A{i}', item)
worksheet.write(f'B{i}', cost, money)
# колонкой ниже добавить подсчет суммы
worksheet.write('A6', 'Итого:', bold)
worksheet.write('B6', '=SUM(B2:B5)', money)
# задать колонкам от 0 до 1 каждой ширину 15
worksheet.set_column(0, 1, 15)
# сохраняем и закрываем
workbook.close()В статье больше примеров!
#xls #excel
tirinox.ru
Пишем файл Excel из Python
Если вдруг вам потребуется, к примеру, выгружать отчеты из вашей программы, почему бы не воспользоваться общепринятым офисным форматом – Excel? В этом нет ничего сложного, потому что есть прекрасная библиотека XlsxWriter. Приведу для вас немного примеров…
Python – это компилятор или интерпретатор?
Ответ неоднозначный. Python – это и первое, и второе. (Здесь мы говорим про самый распространенный CPython)
Когда вы вводите в терминале операторы по одному, то они выполняются сразу после ввода, в этом случае Python играет роль интерпретатора.
А если вы скармливаете Python исходный файл целиком, то он сначала компилирует его в промежуточное представление: низкоуровненый байт-код. Замечали файлы
Набросал для вас реализацию языка Brainfuck, причем в двух вариантах: интерпретатора и компилятора. Интерпретатор читает программу и сразу выполняет ее команда за командой, а компилятор выдает нам исполняемый файл, которым мы запускаем отдельно от компилятора. Уловили разницу?
Ответ неоднозначный. Python – это и первое, и второе. (Здесь мы говорим про самый распространенный CPython)
Когда вы вводите в терминале операторы по одному, то они выполняются сразу после ввода, в этом случае Python играет роль интерпретатора.
А если вы скармливаете Python исходный файл целиком, то он сначала компилирует его в промежуточное представление: низкоуровненый байт-код. Замечали файлы
*.pyc? Вот это уже скомпилированный байт-код. Он выполняется виртуальной машиной Python.Набросал для вас реализацию языка Brainfuck, причем в двух вариантах: интерпретатора и компилятора. Интерпретатор читает программу и сразу выполняет ее команда за командой, а компилятор выдает нам исполняемый файл, которым мы запускаем отдельно от компилятора. Уловили разницу?
tirinox.ru
Пишем Brainfuck на Python
Есть мнение, что каждый программист должен написать в жизни хотя бы один язык программирования, либо реализовать уже существующий, но своими руками. В качестве примера мы начнем с самого простого и создадим Brainfuck. Согласно Вики: Brainfuck — один из и…
Рассказ о том, как я автоматизировал загрузку гербов субъектов РФ из Википедии как небольшой туториал по веб-скрейпингу.
tirinox.ru
Парсим Википедию с Beautiful Soup 4
Для одного из моих проектов понадобилось раздобыть список субъектов РФ с их гербами. Я решил автоматизировать этот процесс, написав скрипт на языке Python. Поделюсь с вами процессом разработки, трудностями, с которыми столкнулся и их решениями. Парсить будем…
Разбор URL
Функция urlparse из модуля urllib.parse разбирает URL на составные части: протокол, имя хоста, порт, путь, запрос и прочие.
Имя хоста, порт, логин и пароль объединены в поле netloc, но их компоненты доступны для чтения по этим атрибутам:
Собрать обратно ParseResult в URL:
Если мы хотим в URL поменять какие-то части, удобно делать вот так:
Однако таким способом нельзя поменять компоненты netloc, например, отдельно порт. netloc нужно менять целиком:
Функция urlparse из модуля urllib.parse разбирает URL на составные части: протокол, имя хоста, порт, путь, запрос и прочие.
>>> u1 = urlparse('https://tirinox:1234@www.site.com:8080/some/page/index.html?page=2&action=login')
>>> u1
ParseResult(scheme='https', netloc='tirinox:1234@www.site.com:8080', path='/some/page/index.html', params='', query='page=2&action=login', fragment='')
>>> u1.scheme, u1.query, u1.netloc
('https', 'page=2&action=login', 'tirinox:1234@www.site.com:8080')Имя хоста, порт, логин и пароль объединены в поле netloc, но их компоненты доступны для чтения по этим атрибутам:
>>> u1.username, u1.password, u1.hostname, u1.port
('tirinox', '1234', 'www.site.com', 8080)Собрать обратно ParseResult в URL:
>>> u1.geturl()
'https://www.site.com:8080/some/page/index.html?page=2&action=login'Если мы хотим в URL поменять какие-то части, удобно делать вот так:
>>> u1._replace(scheme='http').geturl()
'http://www.site.com:8080/some/page/index.html?page=2&action=login'
Однако таким способом нельзя поменять компоненты netloc, например, отдельно порт. netloc нужно менять целиком:
>>> u1._replace(netloc="user:password@www.site.com:8090").geturl()
'https://user:password@www.site.com:8090/some/page/index.html?page=2&action=login'globals(), locals(), vars(), dir()
Программист на Python может узнать, какие именно переменные определенны в данный момент в интерпретаторе. Переменные можно разделить на локальные и глобальные. Глобальные определены на верхнем уровне кода снаружи функций и классов (грубо говоря без отступов слева). Локальные переменные наоборот определены внутри своих зон видимости, ограниченных классами и функциями.
Функция globals() выдает словарь глобальных переменных (ключ – имя переменной). Функция locals() возвращает словарь только локальных переменных. Пример:
Обратите внимание, что переменная y в locals() имеет другое значение, нежели чем в globals(). Это две разные переменные из разных областей, но внутри функции приоритет имеет локальная y.
Еще важно знать, что в список переменных входят не только простые переменные, которые вы определяете через знак присваивания, но и функции, классы и импортированные модули!
Через словари из locals() и globals() переменные можно не только читать, но и создавать, перезаписывать и удалять:
Функция vars() ведет себя как locals(), если вызвана без аргумента, а если с аргументом, то она просто получает
В глобальном контексте все три функции возвращают одно и тоже – глобальные переменные. Проверьте:
Функциия dir(), будучи вызвана без параметра, возвращает список имен переменных. Глобальных или локальных в зависимости от места вызова:
Все рассмотренные выше функции являются встроенными и не требуют импортов.
Программист на Python может узнать, какие именно переменные определенны в данный момент в интерпретаторе. Переменные можно разделить на локальные и глобальные. Глобальные определены на верхнем уровне кода снаружи функций и классов (грубо говоря без отступов слева). Локальные переменные наоборот определены внутри своих зон видимости, ограниченных классами и функциями.
Функция globals() выдает словарь глобальных переменных (ключ – имя переменной). Функция locals() возвращает словарь только локальных переменных. Пример:
x, y = 5, 10
def test():
y, z = 33, 44
print('globals:', globals())
print('locals:', locals())
test()
"""Вывод:
globals: {'__name__': '__main__', ... '__file__': '/Users/.../vars.py', '__cached__': None, 'x': 5, 'y': 10, 'test': <function test at 0x107677280>}
locals: {'y': 33, 'z': 44}"""Обратите внимание, что переменная y в locals() имеет другое значение, нежели чем в globals(). Это две разные переменные из разных областей, но внутри функции приоритет имеет локальная y.
Еще важно знать, что в список переменных входят не только простые переменные, которые вы определяете через знак присваивания, но и функции, классы и импортированные модули!
Через словари из locals() и globals() переменные можно не только читать, но и создавать, перезаписывать и удалять:
>>> x = 10
>>> globals()['x'] = 5
>>> x
5
>>> globals()['new_var'] = 10
>>> new_var
10
>>> del globals()['new_var']
>>> new_var
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'new_var' is not definedФункция vars() ведет себя как locals(), если вызвана без аргумента, а если с аргументом, то она просто получает
_ _ dict _ _ от аргумента. Если его нет у аргумента, то будет TypeError.class Foo:
def __init__(self):
self.x = 5
f = Foo()
print(vars(f)) # {'x': 5}
print(vars(f) == f.__dict__) # TrueВ глобальном контексте все три функции возвращают одно и тоже – глобальные переменные. Проверьте:
print(globals())
print(locals())
print(vars())
print(globals() == locals() == vars()) # TrueФункциия dir(), будучи вызвана без параметра, возвращает список имен переменных. Глобальных или локальных в зависимости от места вызова:
def test():
x = 10
print(dir()) # ['x']
y = 10
test()
print(dir()) # ['__annotations__', ..., '__spec__', 'test', 'y']Все рассмотренные выше функции являются встроенными и не требуют импортов.
В дополнение об областях видимости переменных
В отличие он некоторых других языков в Python блоки типа
Частая ошибка – затирание внешней переменной в цикле for:
Зоны видимости отделяются только функциями, классами и модулями. Здесь все переменные x – разные:
Самая широкая зона видимости называется builtin. В нее попадают все имена, известные интерпретатору в данный момент, включая вещи импортированные из других модулей.
Казалось бы мы затерли pi, но мы затерли его лишь в глобальной области видимости. Повторно импортируя pi, мы получаем старую переменную с тем же адресом, иными словами мы достаем ее из builtin области в global.
Вы знали о всех этих особенностях?
В отличие он некоторых других языков в Python блоки типа
for, if, while, with не создают областей видимости (scope) для переменных, то есть переменная внутри и снаружи блока будет одна и та же:x = 1
if True:
x = 2
print(x) # 2Частая ошибка – затирание внешней переменной в цикле for:
i = 10
for i in range(5): # затирает i
...
print(i) # 4Зоны видимости отделяются только функциями, классами и модулями. Здесь все переменные x – разные:
x = 1
class Foo:
x = 2
def method(self):
x = 3
return x
print(x, Foo.x, Foo().method()) # все 3 разныеСамая широкая зона видимости называется builtin. В нее попадают все имена, известные интерпретатору в данный момент, включая вещи импортированные из других модулей.
>>> from math import pi
>>> pi, id(pi)
(3.141592653589793, 4465320624)
>>> pi = 3
>>> pi, id(pi)
(3, 4462262880)
>>> from math import pi
>>> pi, id(pi)
(3.141592653589793, 4465320624)Казалось бы мы затерли pi, но мы затерли его лишь в глобальной области видимости. Повторно импортируя pi, мы получаем старую переменную с тем же адресом, иными словами мы достаем ее из builtin области в global.
Вы знали о всех этих особенностях?
Зачем мне вообще нужны комплексные числа? – спросят многие из вас.
Но разве не круто извлечь корень из -1?
А вы посмотрите на этот классный синтаксис:
Самое чудесное, что простыми формулами на комплексных числах можно описывать бесконечно самоподобные структуры, например, множество Мандельброта.
Заинтересованы?
Но разве не круто извлечь корень из -1?
А вы посмотрите на этот классный синтаксис:
>>> 1 + 2j
(1+2j)
>>> type(1 + 2j)
<class 'complex'>Самое чудесное, что простыми формулами на комплексных числах можно описывать бесконечно самоподобные структуры, например, множество Мандельброта.
c = x + 1j * y
z = 0j
for n in range(iters):
z = z ** 2 + c
if (z * z.conjugate()).real > 4.0:
break
img.putpixel((px, py), palette[n])Заинтересованы?
tirinox.ru
Комплексные числа в Python. Бонус: фрактал
В Python есть встроенный тип данных complex, который моделируют комплексные числа. По-моему, теория комплексных чисел – настоящий прорыв в математике, оказавший колоссальное влияние на современную физику. Неудивительно, что комплексные числа оказались в стандартной…
Что если нужно импортировать модули не из директории проекта и не те, что установлены через pip, а из произвольного места на диске?
Конечно, можно было бы скопировать код оттуда в своей проект, но так не рекомендуется делать. Есть и другие решения.
В модуле sys есть переменная path. Она содержит список путей, в которых Python ищет названия модулей для импорта. Пожалуйста, не путайте
Мы можем влиять на эту переменную, например, добавляя туда свои пути. Если добавить в начало списка, то поиск модулей начнется именно с нового пути.
Порядок операторов здесь важен. Нельзя сделать сначала import, потому что на момент импорта my_module система еще не знает, где его можно найти.
Функция
Также, набрав команду
Минус способов с добавлением путей через
PYTHONPATH – переменная окружения, которую вы можете установить перед запуском интерпретатора. Будучи заданной, она также влияет на sys.path, добавляя пути поиска модулей в начало списка.
На Windows можно использовать команду set. Если надо задать два и более путей, разделите их точкой с запятой:
На Linux и macOS можно использовать export. Два и более путей разделяются двоеточием:
Или даже в одну строку:
Кто не знал, ключ
Если вам заранее известны пути импорта дополнительных модулей, можно задать их прямо в IDE. На примере PyCharm, заходите в настройки: Project: ваш проект – Project Structure – Add Content Root.
Таким образом, у вас будут работать все фишки IDE для импортированных по сторонним путям модулей, но код будет запускаться корректно только из этой IDE, а чтобы запустить его из-вне, например из терминала, придется все равно прописать PYTHONPATH.
Конечно, можно было бы скопировать код оттуда в своей проект, но так не рекомендуется делать. Есть и другие решения.
В модуле sys есть переменная path. Она содержит список путей, в которых Python ищет названия модулей для импорта. Пожалуйста, не путайте
sys.path и переменную окружения PATH (которая, кстати, доступна через os.environ['PATH']). Это разные вещи, последняя не имеет отношения к поиску модулей Python.>>> import sys
>>> sys.path
['', '/usr/local/Cellar/python@3.8/3.8.1/Frameworks/Python.framework/Versions/3.8/lib/python38.zip', ..., '/usr/local/lib/python3.8/site-packages']
Мы можем влиять на эту переменную, например, добавляя туда свои пути. Если добавить в начало списка, то поиск модулей начнется именно с нового пути.
import sys
sys.path.insert(0, '/Users/you/Projects/my_py_lib')
import my_module # этот модуль лежит в my_py_libПорядок операторов здесь важен. Нельзя сделать сначала import, потому что на момент импорта my_module система еще не знает, где его можно найти.
import sys
import my_module # ModuleNotFoundError
sys.path.insert(0, '/Users/you/Projects/my_py_lib') # поздно
Функция
site.addsitedir тоже модифицирует sys.path, добавляя путь в конец списка. Еще она делает некоторые дополнительные вещи, но мы их не касаемся. Пример использования:import site
site.addsitedir('/Users/you/Projects/my_py_lib')
import my_moduleТакже, набрав команду
python3 -m site в командной строке, вы можете узнать пути для импорта в текущим интерпретаторе Python.Минус способов с добавлением путей через
sys.path и site – IDE скорее всего не будет видеть и индексировать эти динамические пути, а значит будет много красных подчеркиваний и отсутствие автодополнения, даже если код при этом прекрасно выполняется.PYTHONPATH – переменная окружения, которую вы можете установить перед запуском интерпретатора. Будучи заданной, она также влияет на sys.path, добавляя пути поиска модулей в начало списка.
На Windows можно использовать команду set. Если надо задать два и более путей, разделите их точкой с запятой:
set PYTHONPATH=C:\pypath1\;C:\pypath2\
python -c "import sys; print(sys.path)"
# Пример вывода:
['', 'C:\\pypath1', 'C:\\pypath2', 'C:\\opt\\Python36\\python36.zip', 'C:\\opt\\Python36\\DLLs', 'C:\\opt\\Python36\\lib', 'C:\\opt\\Python36', ..., 'Python36\\lib\\site-packages\\Pythonwin']На Linux и macOS можно использовать export. Два и более путей разделяются двоеточием:
export PYTHONPATH='/some/extra/path:/foooo'
python3 -c "import sys; print(sys.path)"
# Пример вывода
['', '/some/extra/path', '/foooo', ...]Или даже в одну строку:
PYTHONPATH='/some/path' python3 -c "import sys; print(sys.path)"Кто не знал, ключ
-c для python3 просто выполняет строчку кода. И да, лишних пробелов вокруг знака равно не должно быть, это такой синтаксис.Если вам заранее известны пути импорта дополнительных модулей, можно задать их прямо в IDE. На примере PyCharm, заходите в настройки: Project: ваш проект – Project Structure – Add Content Root.
Таким образом, у вас будут работать все фишки IDE для импортированных по сторонним путям модулей, но код будет запускаться корректно только из этой IDE, а чтобы запустить его из-вне, например из терминала, придется все равно прописать PYTHONPATH.