Kiat dan trik dari saluran Telegram saya @pythonetc, September 2019



Ini adalah pilihan baru tips dan trik tentang Python dan pemrograman dari saluran-Telegram saya @pythonetc.

Publikasi sebelumnya


loop asyncio tidak harus dijalankan untuk memiliki tugas. Anda dapat membuat dan menghentikan tugas meskipun loop dihentikan sekarang. Jika loop dihentikan, beberapa tugas mungkin tidak selesai untuk selamanya.

 import asyncio async def printer(): try: try: while True: print('*') await asyncio.sleep(1) except asyncio.CancelledError: print('x') finally: await asyncio.sleep(2) print('o') # never happens loop = asyncio.get_event_loop() run = loop.run_until_complete task = loop.create_task(printer()) run(asyncio.sleep(1)) # printer works here print('||') run(asyncio.sleep(1)) # printer works here task.cancel() # nothing happens run(asyncio.sleep(1)) # x printed 

Keluaran:

 * * || * x 

Anda harus yakin untuk menunggu semua tugas sebelum menghentikan loop. Jika Anda tidak, Anda mungkin memiliki beberapa blok finally dilewati dan beberapa manajer konteks tidak keluar.


Python memungkinkan Anda membebani banyak operator yang berbeda dan operator shift adalah salah satunya. Berikut adalah contoh cara membuat komposisi fungsi menggunakan operator ini. Di sini, tanda panah seperti menunjukkan arah aliran data:

 from collections import deque from math import sqrt class Compose: def __init__(self): self._functions = deque() def __call__(self, *args, **kwargs): result = None for f in self._functions: result = f(*args, **kwargs) args = [result] kwargs = dict() return result def __rshift__(self, f): self._functions.append(f) return self def __lshift__(self, f): self._functions.appendleft(f) return self compose = Compose sqrt_abs = (compose() << sqrt << abs) sqrt_abs2 = (compose() >> abs >> sqrt) print(sqrt_abs(-4)) # 2.0 print(sqrt_abs2(-4)) # 2.0 


Anda bisa meneruskan argumen ke metaclass khusus dari definisi kelas. Notasi class mendukung argumen kata kunci: class Klass(Parent, arg='arg') . Kata kunci metaclass dicadangkan untuk mengatur metaclass, tetapi yang lain bebas untuk digunakan.

Berikut ini adalah contoh dari metaclass yang menciptakan kelas tanpa salah satu atribut. Nama atribut itu disediakan dalam argumen remove :

 class FilterMeta(type): def __new__(mcs, name, bases, namespace, remove=None, **kwargs): if remove is not None and remove in namespace: del namespace[remove] return super().__new__(mcs, name, bases, namespace) class A(metaclass=FilterMeta, remove='half'): def half(x): return x // 2 half_of_4 = half(4) half_of_100 = half(100) a = A() print(a.half_of_4) # 2 print(a.half_of_100) # 50 a.half # AttributeError 


Terkadang Anda ingin menghabiskan generator, tetapi Anda tidak peduli dengan nilai yang dihasilkannya. Anda peduli tentang beberapa efek samping, mungkin pengecualian, menulis ke file, modifikasi variabel global dll.

Cara yang mudah dan banyak digunakan untuk melakukan ini adalah list(gen()) . Namun, kode ini menyimpan semua nilai ke dalam memori hanya untuk membuangnya segera setelahnya. Itu bisa tidak diinginkan.

Jika Anda ingin menghindari ini, Anda dapat menggunakan deque dengan ukuran terbatas sebagai gantinya:

 from collections import deque def inversed(nums): for num in nums: yield 1 / num try: deque(inversed([1, 2, 0]), maxlen=0) except ZeroDivisionError: print('E')</code> To be more semantically precise you better define your own <code>exhaust</code> function: <source lang="python"> def exhaust(iterable): for _ in iterable: pass 


Bayangkan Anda memiliki sepasang kelas yang merupakan induk dan anak, katakanlah User dan Admin . Anda juga memiliki fungsi yang mengambil daftar pengguna sebagai argumen. Bisakah Anda memberikan daftar admin? Jawabannya adalah tidak: fungsi dapat menambahkan pengguna lain ke daftar admin yang tidak valid dan melanggar jaminan yang disediakan daftar.

Namun, Anda dapat memberikan Sequence admin karena Sequence hanya baca. Istilah yang tepat di sini adalah Sequence kovarian pada tipe anggotanya.

Anda dapat mendefinisikan tipe kovarian dengan memberikan covariant=True sebagai argumen TypeVar :

 from typing import TypeVar, Generic T = TypeVar('T', covariant=True) class Holder(Generic[T]): def __init__(self, var: T): self._var: T = var def get(self) -> T: return self._var class User: pass class Admin(User): pass def print_user_from_holder(holder: Holder[User]) -> None: print(holder.get()) h: Holder[Admin] = Holder(Admin()) print_user_from_holder(h) 

Sebaliknya, fungsi mungkin memerlukan wadah hanya untuk menempatkan admin di sana. Wadah hanya-tulis semacam itu bersifat contravarian pada jenis anggotanya:

 from typing import TypeVar, Generic T = TypeVar('T', contravariant=True) class Holder(Generic[T]): def __init__(self, var: T): self._var: T = var def change(self, x: T): self._var = x class User: pass class Admin(User): pass def place_admin_to_holder(holder: Holder[Admin]) -> None: holder.change(Admin()) h: Holder[User] = Holder(User()) place_admin_to_holder(h) 

Kelas yang bukan kovarian atau contravarian disebut invarian .

Source: https://habr.com/ru/post/id470107/


All Articles