Python etc
رفتن به کانال در 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
نمایش بیشترکشور مشخص نشده استفناوری و برنامهها16 318
6 179
مشترکین
اطلاعاتی وجود ندارد24 ساعت
اطلاعاتی وجود ندارد7 روز
اطلاعاتی وجود ندارد30 روز
آرشیو پست ها
6 179
You can’t get an element from a generator by index even it’s finite. You can convert it to
list but you mean load in memory more elements that you actually need.
To get exactly one element you can use islice:
from itertools import islice
def gen():
return (x for x in range(100))
print(next(islice(gen(), 20, None)))
# 20
To get different elements many time you may implement simple caching lazy sequence:
class LazySeq(Sequence):
def __init__(self, it: Iterable):
self._it = it
self._list = []
def __getitem__(self, idx):
for x in self._it:
self._list.append(x)
if len(self._list) > idx:
break
if len(self._list) <= idx:
raise IndexError()
return self._list[idx]
def __len__(self):
for x in self._it:
self._list.append(x)
return len(self._list)
seq = LazySeq(gen())
print(seq[20]) # 20
print(seq[40]) # 40
print(seq[80]) # 80
print(seq[200]) # error6 179
Some things should be closed after the use. Some of them are provided as context managers (
open is a notable example), and some of them aren't (say, socket.socket).
Writing such context manager is trivial:
@contextmanager
def socket_context(*args, **kwargs):
try:
sock = socket(*args, **kwargs)
yield sock
finally:
sock.close()
To avoid writing a context manager for every type of closing object , you can you universal contextlib.closing:
with closing(socket.socket()) as sock:
sock.connect(addr)
sock.sendall(data)
If you still like to have a socket_context name, but don't want to write the monotonous try-yield-finally-close, you should wrap closing:
def socket_context(*args, **kwargs):
return closing(socket.socket(*args, **kwargs))6 179
If you want objects of a class to have an auto-incremented ID, you can make it happen by tracking current ID in the class attribute:
class Task:
_task_id = 0
def __init__(self):
self._id = self._task_id
type(self)._task_id += 1
Mind, that you can't do self._task_id += 1. That creates the _task_id attribute within the instance, not the class. You should consider using a factory method instead of __init__ to make it look prettier:
class Task:
_task_id = 0
def __init__(self, task_id):
self._id = task_id
@classmethod
def create(cls):
obj = cls(cls._task_id)
cls._task_id += 1
return obj
This version is also easier to test since any custom ID can be easily provided.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
str is not constructed like any other class. When you do str(x), x is used in __new__, but completely ignored in __init__.
>>> str.__new__(str, object="abc")
'abc'
>>> str.__init__(str)
>>>
You can take this into consideration if you want to inherit from str:
class MyString(str):
def __new__(cls, string: str, extra_data: Dict):
return super().__new__(cls, string)
def __init__(self, string: str, extra_data: Dict):
super().__init__()
self._extra_data = extra_data6 179
In Python 3, once the
except block is exited, the variables that store caught exceptions are removed from locals() even if they previously existed:
>>> e = 2
>>> try:
... 1/0
... except Exception as e:
... pass
...
>>> e
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'e' is not defined
If you want to save a reference to the exception, you have to use another variable:
>>> error = None
>>> try:
... 1/0
... except Exception as e:
... error = e
...
>>> error
ZeroDivisionError('division by zero',)
This is not true for Python 2.6 179
Write a container for the line of dominoes. It should support at least adding and removing tiles, inserting other chains, splitting into chains and rendering to 🀻🁻🁋🁔.
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
__init__ allows you to modify an object right after the creation. If you want to control what is created you should use __new__ instead:
from typing import Tuple, Dict
from cached_property import cached_property
class Numbers:
_LOADED: Dict[Tuple[int, ...], 'Numbers'] = {}
def __new__(cls, ints: Tuple[int, ...]):
if ints not in cls._LOADED:
obj = super().__new__(cls)
cls._LOADED[ints] = obj
return cls._LOADED[ints]
def __init__(self, ints: Tuple[int, ...]):
self._ints = ints
@cached_property
def biggest(self):
print('calculating...')
return max(self._ints)
print(Numbers((4, 3, 5)).biggest)
print(Numbers((4, 3, 5)).biggest)
print(Numbers((4, 3, 6)).biggest)6 179
If your class is derived from another, the metaclass of your class have to be also derived from the metaclass of that class:
from collections import UserDict
from abc import ABCMeta
# ABCMeta is a metaclass of UserDict
class MyDictMeta(ABCMeta):
def __new__(cls, name, bases, dct):
return super().__new__(cls, name, bases, dct)
class MyDict(UserDict, metaclass=MyDictMeta):
pass
It may be a good idea to get the metaclass of that other class automatically:
def create_my_dict_class(parents):
class MyDictMeta(*[type(c) for c in parents]):
def __new__(cls, name, bases, dct):
return super().__new__(cls, name, bases, dct)
class MyDict(*parents, metaclass=MyDictMeta):
pass
MyDict = create_my_dict_class((UserDict,))6 179
Some Python modules are compiled into the interpreter itself. They are called built-in modules, not to be confused with the standard library. One can use
sys.builtin_module_names to get the full list of such modules. The notable examples are sys, gc, time and so on.
Usually you don't care whether the module is built-in or not; however, you should be aware, that import always looks for a module among built-ins first. So, the built-in sys module is loaded even if you have sys.py available. On the other hand, if you have, say, datetime.py in the current directory it indeed can be loaded instead of the standard datetime module.6 179
Make a function that replace usual quotes in a string with a pretty ones:
He said, "she said "yes", guys!". ⟶ He said, “she said ‘yes’, guys!”.
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
f-strings allow you to specify the width for the printed value as well as other format specifiers:
>>> x = 42
>>> f'{x:5}+{x:15f}'
' 42+ 42.000000'
They can also contain evaluated expressions which can be useful when width is unknown upfront:
def print_table(matrix):
cols_width = [
max(len(str(row[col])) for row in matrix)
for col in range(len(matrix[0]))
]
for row in matrix:
for i, cell in enumerate(row):
print(
f'{cell:{cols_width[i]}} ',
end=''
)
print()
albums = [
['Eleven. Return and Revert', 2010],
['Wilderness', 2013],
['The Menagerie Inside', 2015],
['Evaporate', 2018],
]
print_table(albums)
Output:
Eleven. Return and Revert 2010
Wilderness 2013
The Menagerie Inside 2015
Evaporate 20186 179
You can add unicode characters in a string literal not only by its number, but by also by its name.
>>> '\N{EM DASH}'
'—'
>>> '\u2014'
'—'
It’s also compatible with f-strings:
>>> width = 800
>>> f'Width \N{EM DASH} {width}'
'Width — 800'6 179
If you want to create a dictionary from the know set of keys and some fixed value for all of them you can you use dictionary comprehensions:
>>> keys = ['a', 'b', 'c']
>>> {k: True for k in keys}
{'a': True, 'b': True, 'c': True}
However, the dict class has the fromkeys classmethod designed specially for this case:
>>> dict.fromkeys(keys, True)
{'a': True, 'b': True, 'c': True}