Библиотека Python разработчика | Книги по питону
Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍 По всем вопросам @evgenycarter РКН clck.ru/3Ko7Hq
نمایش بیشتر📈 تحلیل کانال تلگرام Библиотека Python разработчика | Книги по питону
کانال Библиотека Python разработчика | Книги по питону (@bookpython) در بخش زبانی روسی بازیگری فعال است. در حال حاضر جامعه شامل 17 959 مشترک است و جایگاه 7 250 را در دسته فناوری و برنامهها و رتبه 36 565 را در منطقه روسيا دارد.
📊 شاخصهای مخاطب و پویایی
از زمان ایجاد در невідомо، پروژه رشد سریعی داشته و 17 959 مشترک جذب کرده است.
بر اساس آخرین دادهها در تاریخ 04 نوامبر, 2026، کانال فعالیت پایداری دارد. در ۳۰ روز گذشته تغییر اعضا برابر -87 و در ۲۴ ساعت گذشته برابر -3 بوده و همچنان دسترسی گستردهای حفظ شده است.
- وضعیت تأیید: تأیید نشده
- نرخ تعامل (ER): میانگین تعامل مخاطب 5.31% است و در ۲۴ ساعت نخست پس از انتشار، محتوا معمولاً 2.70% واکنش نسبت به کل مشترکان کسب میکند.
- دسترسی پستها: هر پست به طور میانگین 953 بازدید دریافت میکند. در اولین روز معمولاً 485 بازدید جمعآوری میشود.
- واکنشها و تعامل: مخاطبان بهطور فعال حمایت میکنند؛ میانگین واکنش به هر پست 4 است.
- علایق موضوعی: محتوا بر موضوعات کلیدی مانند numbers, yield, модуль, none, декоратор تمرکز دارد.
📝 توضیح و سیاست محتوایی
نویسنده این فضا را محل بیان دیدگاههای شخصی توصیف میکند:
“Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍
По всем вопросам @evgenycarter
РКН clck.ru/3Ko7Hq”
به لطف بهروزرسانیهای پرتکرار (آخرین داده در تاریخ 05 نوامبر, 2026)، کانال همواره بهروز و دارای دسترسی بالاست. تحلیلها نشان میدهد مخاطبان بهطور فعال با محتوا تعامل دارند و آن را به نقطه اثرگذاری مهم در دسته فناوری و برنامهها تبدیل کردهاند.
def edges(lst):
return lst[0], lst[-1]
first, last = edges([1, 2, 3])
assert first == 1
assert last == 3
In truth, lst[0], lst[-1] is a simple tuple. It's returned as usual and then unpacked to first and last:
result = edges([1, 2, 3])
assert isinstance(result, tuple)
first, last = result
assert first == 1
assert last == 3
Usually, you don't care about it at all. However, all these things come to the surface when you use type hints. You have to define the function return value as tuple:
def edges(lst) -> Tuple[int, int]:
return lst[0], lst[-1]
Calling that function is even harder. You may think that you can do something like this:
first: int, last: int = edges([1, 2, 3])
Or at least this:
first, last: Tuple[int, int] = edges([1, 2, 3])
But both ways are incorrect. This is the only reasonable thing you can do to annotate these variables:
first: int
last: int
first, last = edges([1, 2, 3])datetime. The interesting part is, datetime objects have the special interface for timezone support (namely the tzinfo attribute), but this module only has limited support of its interface, leaving the rest of the job to different modules.
The most popular module for this job is pytz. The tricky part is, pytz doesn't fully satisfy tzinfo interface. The pytz documentation states this at one of the first lines: “This library differs from the documented Python API for tzinfo implementations.”
You can't use pytz timezone objects as the tzinfo attribute. If you try, you may get the absolute insane results:
In : paris = pytz.timezone('Europe/Paris')
In : str(datetime(2017, 1, 1, tzinfo=paris))
Out: '2017-01-01 00:00:00+00:09'
Look at that +00:09 offset. The proper use of pytz is following:
In : str(paris.localize(datetime(2017, 1, 1)))
Out: '2017-01-01 00:00:00+01:00'
Also, after any arithmetic operations, you should normalize your datetime object in case of offset changes (on the edge of the DST period for instance).
In : new_time = time + timedelta(days=2)
In : str(new_time)
Out: '2018-03-27 00:00:00+01:00'
In : str(paris.normalize(new_time))
Out: '2018-03-27 01:00:00+02:00'
Since Python 3.6, it's recommended to use dateutil.tz instead of pytz. It's fully compatible with tzinfo, can be passed as an attribute, doesn't require normalize, though works a bit slower.
If you are interested why pytz doesn't support datetime API, or you wish to see more examples, consider reading the decent article on the topic.map function calls another function for every element of some iterable. That means that function should accept a single value as an argument:
In : list(map(lambda x: x ** 2, [1, 2, 3]))
Out: [1, 4, 9]
However, if each element of the iterable is tuple, then it would be nice to pass each element of that tuple as a separate argument. It was possible in Python 2, thanks to the tuple parameter unpacking (note the parentheses):
>>> map(lambda (a, b): a + b, [(1, 2), (3, 4)])
[3, 7]
In Python 3, this feature is gone, but there is another solution. itertools.starmap unpacks tuple for you, as though a function is called with a star: f(*arg) (hence the function's name):
In [3]: list(starmap(lambda a, b: a + b, [(1, 2), (3, 4)]))
Out[3]: [3, 7]locals()) is used by a metaclass (type by default) to construct an actual class object.
class Meta(type):
def __new__(meta, name, bases, ns):
print(ns)
return super().__new__(
meta, name,
bases, ns
)
class Foo(metaclass=Meta):
B = 2
The above code prints {'__module__': '__main__', '__qualname__': 'Foo', 'B': 3}.
Obviously, if you do something like B = 2; B = 3, then the metaclass only knows about B = 3, since only that value is in ns. This limitation is based on the fact, that a metaclass works after the body evaluation.
However, you can interfere in the evaluation by providing custom namespace. By default, a simple dictionary is used but you can provide a custom dictionary-like object using the metaclass __prepare__ method.
class CustomNamespace(dict):
def __setitem__(self, key, value):
print(f'{key} -> {value}')
return super().__setitem__(key, value)
class Meta(type):
def __new__(meta, name, bases, ns):
return super().__new__(
meta, name,
bases, ns
)
@classmethod
def __prepare__(metacls, cls, bases):
return CustomNamespace()
class Foo(metaclass=Meta):
B = 2
B = 3
The output is the following:
__module__ -> __main__
__qualname__ -> Foo
B -> 2
B -> 3
And this is how enum.Enum is protected from duplicates.Все уроки записаны в 2022 году, материал обновлен и дополнен.
Спикеры:
Марсель Ибраев (Southbridge)
Павел Селиванов (Yandex Cloud).
Форматы обучения:
Поток: открываем доступ к двум новым темам каждую неделю, общаемся в чате с куратором и спикерами, два раза в неделю — AMA-сессии по темам курса со спикерами.
Видеокурс: доступны сразу все темы, можно изучать в своём темпе.
Оба формата включают практику на стендах и итоговую сертификацию.
Подробнее про курс: https://slurm.club/3zPAuGrsuper() function allows referring to the base class. This can be extremely helpful in cases when a derived class wants to add something to the method implementation instead of overriding it completely:
class BaseTestCase(TestCase):
def setUp(self):
self._db = create_db()
class UserTestCase(BaseTestCase):
def setUp(self):
super().setUp()
self._user = create_user()
The function's name doesn't mean excellent or very good. The word super implies above in this context (like in superintendant). Despite what I said earlier, super() doesn't always refer to the base class, it can easily return a sibling. The proper name could be next() since the next class according to MRO is returned.
class Top:
def foo(self):
return 'top'
class Left(Top):
def foo(self):
return super().foo()
class Right(Top):
def foo(self):
return 'right'
class Bottom(Left, Right):
pass
# prints 'right'
print(Bottom().foo())
Mind that super() may produce different results since they depend on the MRO of the original call.
>>> Bottom().foo()
'right'
>>> Left().foo()
'top'gen.throw(e) you may raise an exception at the point where the gen generator is paused, i. e. at some yield. If gen catches the exception, get.throw(e) returns the next value yielded (or StopIteration is raised). If gen doesn't catch the exception, it propagates back to you.
In : def gen():
...: try:
...: yield 1
...: except ValueError:
...: yield 2
...:
...: g = gen()
...:
In : next(g)
Out: 1
In : g.throw(ValueError)
Out: 2
In : g.throw(RuntimeError('TEST'))
...
RuntimeError: TEST
You can use it to control generator behavior more precisely, not only by sending data to it but by notifying about some problems with values yielded for example. But this is rarely required, and you have a little chance to encounter g.throw in the wild.
However, the @contextmanager decorator from contextlib does exactly this to let the code inside the context catch exceptions.
In : from contextlib import contextmanager
...:
...: @contextmanager
...: def atomic():
...: print('BEGIN')
...:
...: try:
...: yield
...: except Exception:
...: print('ROLLBACK')
...: else:
...: print('COMMIT')
...:
In : with atomic():
...: print('ERROR')
...: raise RuntimeError()
...:
BEGIN
ERROR
ROLLBACK