Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Новая подборка советов про Python и программирование из моего авторского канала @pythonetc.
← Previous publications
PATH
— это переменная окружения, в которой хранятся пути, по которым ищутся исполняемые файлы. Когда вы просите оболочку выполнить ls
, она сначала ищет исполняемый файл ls
по всем путям, указанным в PATH
.$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/v.pushtaev/.local/bin:/home/v.pushtaev/bin
$ which ls
/usr/bin/ls
В этом примере пути в
PATH
разделены с помощью :
. Путаница не возникнет: если путь содержит :
, то он не может использоваться в PATH
.Но это верно не для всех операционных систем. В Python вы можете узнать правильный разделитель для вашей ОС с помощью
os.pathsep
:Python 3.5.0 [...] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.pathsep
';'
Не путайте
os.pathsep
с os.path.sep
, которая является разделителем для путей к файлам:>>> os.path.sep
'/'
Чтобы регулярные выражения легче было читать, можете использовать флаг
re.VERBOSE
. Он позволяет использовать дополнительные пробелы везде, где хотите, а также добавлять комментарии после символа #
:import re
URL_RE = re.compile(r'''
^
(https?)://
(www[.])?
(
(?: [^.]+[.] )+
( [^/]+ ) # TLD
)
(/.*)
$
''', re.VERBOSE)
m = URL_RE.match('https://www.pythonetc.com/about/')
schema, www, domain, tld, path = m.groups()
has_www: bool = bool(www)
print(f'schema={schema}, has_www={has_www}')
print(f'domain={domain}, tld={tld}')
print(f'path={path}')
re.X
является псевдонимом для re.VERBOSE
.complex
— это встроенный в Python тип для комплексных чисел:>>> complex(1, 2).real
1.0
>>> abs(complex(3, 4))
5.0
>>> complex(1, 2) == complex(1, -2).conjugate()
True
>>> str(complex(2, -3))
'(2-3j)'
Однако не обязательно использовать его напрямую, потому что в Python есть литералы для комплексных чисел:
>>> (3 + 4j).imag
4.0
>>> not (3 + 4j)
False
>>> (-3 - 4j) + (2 - 2j)
(-1-6j)
Нотацию
a : b : c
можно использовать для определения slice(a, b, c)
с помощью одних лишь скобок:>>> [1, 2, 3, 4, 5][0:4:2]
[1, 3]
>>> [1, 2, 3, 4, 5][slice(0, 4, 2)]
[1, 3]
Если вы хотите передать функции slice-объект в качестве аргумента, то придётся определить его явным образом:
def multislice(slc, *iterables):
return [i[slc] for i in iterables]
print(multislice(
slice(2, 6, 2),
[1, 2, 3, 4, 5, 6, 7],
[2, 4, 2, 4, 2, 4, 2],
))
Вот так можно преобразовать подобную функцию в объект, который поддерживает
[a : b : c]
:from functools import partial
class SliceArgDecorator:
def __init__(self, f):
self._f = f
def __getitem__(self, slc):
return partial(self._f, slc)
slice_arg = SliceArgDecorator
@slice_arg
def multislice(slc, *iterables):
return [i[slc] for i in iterables]
print(multislice[2:6:2](
[1, 2, 3, 4, 5, 6, 7],
[2, 4, 2, 4, 2, 4, 2],
))
__getattribute__
— это мощный инструмент, позволяющий легко использовать паттерн делегирования, когда это уместно. Так можно добавить возможность сравнения с несравниваемым объектом:class CustomEq:
def __init__(self, orig, *, key):
self._orig = orig
self._key = key
def __lt__(self, other):
return self._key(self) < self._key(other)
def __getattribute__(self, name):
if name in {'_key', '_orig', '__lt__'}:
return super().__getattribute__(name)
return getattr(self._orig, name)
class User:
def __init__(self, user_id):
self._user_id = user_id
def get_user_id(self):
return self._user_id
def comparable(obj, *, key):
return CustomEq(obj, key=key)
user1 = comparable(User(1), key=lambda u: u.get_user_id())
user2 = comparable(User(2), key=lambda u: u.get_user_id())
print(user2 > user1) # True
print(user2 < user1) # False
print(user2.get_user_id()) # 2