@offtop
Добро пожаловать на канал 'Python Заметки'! Этот канал предоставляет интересные заметки и обучающие материалы по Python. Если вы хотите улучшить свои навыки в программировании на этом языке или узнать о последних трюках и библиотеках, то вы попали по адресу. На 'Python Заметки' вы найдете полезные советы и руководства, которые помогут вам стать более опытным разработчиком. Контактный лицо канала - @paulwinex
⚠️ Обратите внимание, что на канале 'Python Заметки' не размещается реклама! ⚠️nnДля вашего удобства мы добавили хештеги для поиска, такие как #tricks, #libs, #pep, #basic, #regex, #qt, #django, #2to3, #source, #offtop. Эти хештеги помогут вам быстро найти нужную информацию и материалы. Присоединяйтесь к нам сегодня и улучшите свои навыки программирования на Python вместе с 'Python Заметки'!
03 Dec, 09:01
11 Nov, 09:01
.gitignore
строчку: .idea/
. Это самый простой способ.~/.config/git/ignore
git config --global core.excludesfile ~/.gitignore
venv
в Python 3.13 по умолчанию в корень вирутального окружения добавляет файл .gitignore
с одним символом *
, что означает исключение всего в текущей директории. Таким образом папка с venv
автоматически исключается из репозитория. Удобно.28 Oct, 09:01
exit
, еще и скобки для вызова. И было бы удобней сделать это по аналогии с обычным терминалом.exit
или quit
: для выхода. Именно так, без вызова функции!clear
: для очистки терминалаhelp
или F1
: для входа в режим справки (q для выхода)IndentationError
, теперь это исправили. class A:
def test(self):
pass
F2
можно открыть всю историю ввода.tracebacks
и doctest
. Также я заметил что имеет цвет промт функции input()
.23 Oct, 09:02
btn_danger.setProperty('class', 'danger')
btn_warning.setProperty('class', 'warning')
btn_success.setProperty('class', 'success')
21 Oct, 09:00
button = QPushButton("Click Me")
button.setMinimumWidth(300)
button.setFlat(True)
button.setStyleSheet("font-size: 20pt")
button.setToolTip("Super Button")
button.clicked.connect(lambda: print("Button clicked"))
button = QPushButton(
"Click Me",
minimumWidth=300,
flat=True,
styleSheet="font-size: 20pt",
toolTip="Super Button",
clicked=lambda: print("Button clicked"),
)
widget = QWidget(minimumWidth=400)
layout = QHBoxLayout(widget)
layout.addWidget(QLabel("Button >", alignment=Qt.AlignRight))
layout.addWidget(QPushButton("Click Me", clicked=lambda: print("Button clicked")))
widget.show()
widget = QWidget(minimumWidth=400)
layout = QHBoxLayout(widget)
for wd in (
QLabel("Button >", alignment=Qt.AlignRight),
QPushButton("Click Me", clicked=lambda: ...)
):
layout.addWidget(wd)
widget.show()
kwargs
.kwargs = {"text": "Hello " * 30, "wordWrap": True}
my_label = QLabel(**kwargs)
def print_widget_properties(widget):
meta_object = widget.metaObject()
for i in range(meta_object.propertyCount()):
property_ = meta_object.property(i)
property_name = property_.name()
property_value = property_.read(widget)
print(f"{property_name}: {property_value}")
18 Oct, 09:01
–enable-experimental-jit
–without-gil
lib2to3
. Надеюсь больше никому она и не нужна)))docker run --rm -it python:3.13
07 Oct, 09:01
python3 -m http.server
# на рандомном порту read only
python3 -m pyftpdlib
# на указанном порту
python3 -m pyftpdlib -p 22222
# с доступом на запись
python3 -m pyftpdlib -w
# с авторизацией
python3 -m pyftpdlib -w --user=name --password=123
# полный список аргументолв
python3 -m pyftpdlib -h
alias ftp="python3 -m pyftpdlib -w -p 22222"
25 Sep, 09:00
12 Sep, 10:09
26 Aug, 09:05
shlex.split()
, которая имеет один важный аргумент - posix
.shlex.split()
будет учитывать переменную окружения IFS
(Internal Field Separator) для определения разделителей полей и будет более строго следовать стандарту POSIX. Из строки удаляются неэкранированные кавычки и обратные слеши.IFS
и использовать whitespaces как разделители полей.import shlex
# кавычки
text = r'"Do"Not"Separate" \"This\"'
shlex.split(text, posix=False)
# ['"Do"', 'Not"Separate"', '\\"This\\"']
shlex.split(text, posix=True)
# ['DoNotSeparate', '"This"']
# специсимволы
text = r'A\tB\nС\fD\vE'
shlex.split(text, posix=False)
# ['A\\tB\\nС\\fD\\vE']
shlex.split(text, posix=True)
# ['AtBnСfDvE']
# обратный слеш
text = r"cmd.exe c:\games\mario.exe"
shlex.split(text, posix=False)
# ['cmd.exe', 'c:\\games\\mario.exe']
shlex.split(text, posix=True)
# ['cmd.exe', 'c:gamesmario.exe']
posix
по умолчанию True
, стоит помнить этот факт при обработке строк с Windows-путями!05 Aug, 09:06
libpng warning: iCCP: known incorrect sRGB profile
from PIL import Image
Image.open(input_path).save(output_path, icc_profile=None)
from PySide2.QtGui import QImage, QImageWriter
image = QImage(input_path)
image.setText("icc", "")
writer = QImageWriter(output_path)
writer.write(image)
29 Jul, 09:04
format()
/path/to/app{version}/bin
/opt/{app_name}/bin:{DEFAULT_PATH}:/usr/bin
format()
не передать все переменные то будет ошибка KeyError
"/opt/{app_name}:{DEFAULT_PATH}".format(app_name="my_app")
# KeyError: 'DEFAULT_PATH'
srt
и метод format
regex
class SkipDict(dict):
def __missing__(self, key):
return f"{{{key}}}"
"/opt/{app_name}:{DEFAULT_PATH}".format_map(SkipDict(app_name='my_app'))
# "/opt/my_app:{DEFAULT_PATH}"
dict
и переопределяем __missing__
. Этот метод вызывается когда в словаре ключ не найден. По умолчанию он выбрасывает исключение KeyError
. Всякий раз когда ключ не найден, мы возвращаем исходный вид этой переменной и ошибки теперь не будет.${name}
. Это совсем другой синтаксис из bash
и подобных сред.dict
"...".format_map(SkipDict(kwargs))
format()
используется format_map()
, просто удобней в данном случае.SkipDict = type('SkipDict', (dict, ),{'__missing__': lambda self, key: f"{{{key}}}"})
15 Jul, 09:05
datetime.timedelta
поддерживают операторы деления и умноженияfrom datetime import timedelta
td1 = timedelta(hours=1)
# увеличим интервал в 2.5 раза
print(td1*2.5)
# 2:30:00
# разделим интервал на 2
print(td1/2)
# 0:30:00
td2 = timedelta(minutes=25)
print(td1/td2)
# 2.4
print(td1//td2)
# 2
print(td1%td2)
# 0:10:00
datetime.timedelta
поддерживают отрицательные значения. Эти две записи идентичны.datetime.now() - timedelta(hours=1)
datetime.now() + timedelta(hours=-1)
td1>td2
# True
10 Jul, 09:07
self
. *args
def decorator_func(func):
def wrapped(*args, **kwargs):
print('decorator_func')
return func(*args, **kwargs)
return wrapped
class MyClass:
@decorator_func
def method(self):
print('call method')
MyClass().method()
# decorator_func
# call method
staticmethod
. Это будет выглядеть страшно, но работать будет (тестировано на 3.11)class MyClass:
@staticmethod
def decorator(func):
def wrapper(*args, **kwargs):
print('decorator from staticmethod')
return func(*args, **kwargs)
return wrapper
@decorator.__func__
def method(self):
print('method called')
MyClass().method()
# decorator from staticmethod
# method called
classmethod
, но еще хуже.class MyClass:
@classmethod
def decorator(func):
def wrapper(self, *args, **kwargs):
print('decorator from classmethod')
return func(self, *args, **kwargs)
return wrapper
@decorator.__func__
def method(self):
print('method called')
MyClass().method()
# decorator from classmethod
# method called
cls
. Скорее всего это можно решить но лучше не надо. Оба варианта выглядят страшненько 🫣class MyClass:
class deco:
@staticmethod
def my_decorator(func):
def wrapper(*args, **kwargs):
print('decorator from subclass')
return func(*args, **kwargs)
return wrapper
@deco.my_decorator
def method(self):
print('method called')
MyClass().method()
# decorator from subclass
# method called
wraps
пропустил для краткости19 Jun, 09:05
set()
.set
происходит сравнение этого объекта по хешу. Если хеш совпадает с хешем уже существующего объекта, то происходит сравнение объектов на равенство. Если объекты равны, то новый объект не добавляется.class A:
def __init__(self, pk: int):
self.pk = pk
def __repr__(self):
return f"{self.__class__.__name__}(pk={self.pk})"
set([A(pk=1), A(pk=2), A(pk=2)])
>>> {A(pk=1), A(pk=2), A(pk=2)}
id()
, поэтому все объекты считаются разными. Чтобы изменить способ сравнения объектов нам требуется переопределить метод __eq__()
class A:
def __init__(self, pk: int):
self.pk = pk
def __eq__(self, other):
return self.pk == other.pk
set([A(pk=1), A(pk=2), A(pk=2)])
>>> TypeError: unhashable type: 'A'
__eq__()
то следует переопределить и __hash__()
.class A:
def __init__(self, pk: int):
self.pk = pk
def __eq__(self, other):
return self.pk == other.pk
def __hash__(self):
return hash(self.pk)
set([A(pk=1), A(pk=2), A(pk=2)])
>>> {A(pk=1), A(pk=2)}
class B(A):
pass
set([B(pk=1), B(pk=2), B(pk=2)])
>>> {B(pk=1), B(pk=2)}
hash(A(1)) == hash(B(1))
>>> True
set([A(1), B(1)])
>>> {A(pk=1)}
class A:
...
def __eq__(self, other):
return isinstance(other, self.__class__) and self.pk == other.pk
def __hash__(self):
return hash((self.pk, self.__class__))
...
class B(A):
def __eq__(self, other):
return abs(self.pk) == abs(other.pk)
set([B(pk=1), B(pk=2), B(pk=2)])
>>> TypeError: unhashable type: 'B'
__eq__()
в новом классе метод __hash__()
автоматически становится None
и его тоже требуется переопределить.25 Mar, 09:04
04 Mar, 09:10
import psutil
def list_file_handlers(process_name):
for proc in psutil.process_iter():
if proc.name().lower().startswith(process_name):
for file in proc.open_files():
print(file)
list_file_handlers('python')
None
.def who_is_use(fpath):
for proc in psutil.process_iter():
for item in proc.open_files():
if fpath == item.path:
return proc.name()
26 Feb, 09:10
await
.entities = session.execute(select(EntityModel)).scalars().all()
result = await session.execute(select(EntityModel))
entities = result.scalars().all()
session.execute
возвращает корутину, или awaitable объект. Сначала его нужно выполнить через await
, тогда получишь объект с которым можно дальше работать.entities = ( await session.execute(select(EntityModel)) ).scalars().all()
19 Feb, 09:03