Python etc
Open in Telegram
Regular tips about Python and programming in general Owner — @pushtaev The current season is run by @orsinium Tips are appreciated: https://ko-fi.com/pythonetc / https://sobe.ru/na/pythonetc © CC BY-SA 4.0 — mention if repost
Show moreThe country is not specifiedTechnologies & Applications16 318
6 179
Subscribers
No data24 hours
No data7 days
No data30 days
Posts Archive
6 179
Every method can be treated as a plain function and called with a custom
self:
In : class A:
...: def foo(self):
...: return self
...:
In : A().foo
Out: <bound method A.foo of <...>>
In : A.foo
Out: <function __main__.A.foo>
In : A.foo(A())
Out: <__main__.A at 0x7f55ddd32898>
You can even convert a function back to the bound method. Any function is a descriptor, so it can be abused by calling __get__:
In [8]: b = A()
In [9]: A.foo.__get__(b, A)
Out[9]: <bound method A.foo of <...>>6 179
In Python 3
keys, values and items methods of dicts return view objects. They returned lists back in Python 2. The main difference is views don't store all items in memory, but yield them as long as they are requested. It works just fine as long as you are trying to iterate over keys (which you usually are), but you can't access elements by index anymore.
TypeError: 'dict_keys' object does not support indexing
You can argue that you don't really need indexing keys since their order is random, but it's not completely true. First of all, d.keys()[0] can be a proper way to get any key (use next(d.keys()) in Python 3). Second, since Python 3.7 dicts are insertion ordered.6 179
If you want a context manager to make asynchronous operations upon entering or exiting context, you should use asynchronous context managers. Instead of calling
m.__enter__() and m.__exit__() Python does await m.__aenter__() and await m.__aexit__() respectively.
Asynchronous context managers are used with async with syntax:
import asyncio
class Slow:
def __init__(self, delay):
self._delay = delay
async def __aenter__(self):
await asyncio.sleep(self._delay / 2)
async def __aexit__(self, *exception):
await asyncio.sleep(self._delay / 2)
async def main():
async with Slow(1):
print('slow')
loop = asyncio.get_event_loop()
loop.run_until_complete(main())6 179
__getattribute__ is a powerful tool that allow you to easily use delegation pattern when it’s appropriate. Here is how you add an ability to be comparable to a non-comparable object:
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()) # 26 179
Hi. The weekend task section doesn't welcome you today. I believe It's time for it to go.
6 179
a : b : c notation can be used to define slice(a, b, c) only within brackets:
>>> [1, 2, 3, 4, 5][0:4:2]
[1, 3]
>>> [1, 2, 3, 4, 5][slice(0, 4, 2)]
[1, 3]
If you want to pass the slice object as an argument to a function, you have to define it explicitly:
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],
))
Here is how you can convert such a function to an object that supports [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],
))6 179
The
in operator can be used with generators: x in g. Python will iterate over g until x is found or g is exhausted.
>>> def g():
... print(1)
... yield 1
... print(2)
... yield 2
... print(3)
... yield 3
...
>>> 2 in g()
1
2
True
However, range() does more than this for you. It has the __contains__ magic method overriden that allows in to work with the O(1) complexity:
In [1]: %timeit 10**20 in range(10**30)
375 ns ± 10.7 ns per loop
Mind that it doesn't work for the Python 2 xrange() function.6 179
complex is the Python built-in type for complex numbers:
>>> 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)'
There is not need to use it directly though since Python has literals for complex numbers:
>>> (3 + 4j).imag
4.0
>>> not (3 + 4j)
False
>>> (-3 - 4j) + (2 - 2j)
(-1-6j)6 179
Write a generator that takes any number of iterables as arguments. Those iterables yield values in ascending order. Your generator should yield all values of all iterables in ascending orders.
>>> list(merge([1, 5], [2, 3, 4]))
[1, 2, 3, 4, 5]6 179
Welcome to the weekend task section. Below is the task the you can solve in Python. My solution will be published in 36 hours.
6 179
To make regular expressions more readable you may use the
re.VERBOSE flag. It allows you to use extra spaces wherever you want as well as add comments with the # symbol:
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 is an alias for re.VERBOSE.6 179
PATH is an environment variable that stores paths where executables are looked for. When you ask your shell to runls, the sell looks for the ls executable file across all paths that are presented in 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
In the example above paths are separated by : in PATH. No escaping is possible: a path that contains : cannot be used inside PATH.
However, that is not true for all operating systems. In Python you can get the right separator for the local system with os.pathsep:
Python 3.5.0 [...] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.pathsep
';'
os.pathsep is not to be mixed up with os.path.sep which is the separator for file paths:
>>> os.path.sep
'/'6 179
You can use any object as a dictionary key in Python as long as it implements the
__hash__ method. This method can return any integer as long as the only requirement is met: equal objects should have equal hashes (not vice versa).
You also should avoid using mutable objects as keys, because once the object becomes not equal to the old self, it can't be found in a dictionary anymore.
There is also one bizarre thing that might surprise you during debugging or unit testing:
...: class A:
...: def __init__(self, x):
...: self.x = x
...:
...: def __hash__(self):
...: return self.x
...:
In : hash(A(2))
Out: 2
In : hash(A(1))
Out: 1
In : hash(A(0))
Out: 0
In : hash(A(-1)) # sic!
Out: -2
In : hash(A(-2))
Out: -2
In CPython -1 is internally reserved for error states, so it's implicitly converted to -2.6 179
Fed up with webinars of no use oriented only on sales, that don’t provide you any practically valuable information?
🔥 Special for you on November 18th SkillFactory online school hosts really worth a visit webinar - just your questions and our answers to them.
Follow the link https://clc.to/RxBmQA , ask any questions to the expert and come to the online session where all of your questions will be answered!
⚡ No extra advertising and engaging in empty talk - only relevant information, only answers to target requests.
6 179
def catalan(n: int):
result = 1
for i in range(1, n + 1):
result = (
result * 2 * (2 * i - 1)
// (i + 1)
)
return result6 179
Write a function that returns the nth Catalan number without using explicit recursion.
6 179
Welcome to the weekend task section. Below is the task the you can solve in Python. My solution will be published in 36 hours.
