
Pilihan baru tips dan pemrograman Python dari umpan @pythonetc saya.
←
Koleksi sebelumnyaDi
asyncio
sebuah loop tidak harus dimulai untuk memuat tugas. Anda dapat membuat dan menghentikan tugas bahkan ketika siklus dihentikan. Jika dihentikan, beberapa tugas mungkin tetap tidak lengkap.
import asyncio async def printer(): try: try: while True: print('*') await asyncio.sleep(1) except asyncio.CancelledError: print('') finally: await asyncio.sleep(2) print('')
Hasil:
* * || *
Pastikan Anda menunggu semua tugas selesai sebelum menghentikan siklus. Jika ini tidak dilakukan, maka Anda dapat melewati beberapa blok
finally
dan beberapa manajer konteks tidak akan dinonaktifkan.
Python memungkinkan Anda untuk menimpa banyak operator, termasuk operator shift bitwise. Berikut adalah contoh membuat komposisi fungsi menggunakan operator ini. Tanda panah menunjukkan arah transfer 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))
Saat mendefinisikan kelas, Anda bisa meneruskan argumen ke metaclassnya. Notasi
class
mendukung kata kunci sebagai argumen:
class Klass(Parent, arg='arg')
. Kata kunci metaclass dicadangkan untuk memilih metaclass, dan Anda dapat menggunakan yang lain sesuai keinginan.
Berikut ini adalah contoh dari sebuah metaclass yang menciptakan kelas tanpa salah satu atribut. Nama atribut 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)
Kadang-kadang Anda perlu menghabiskan generator, tetapi pada saat yang sama Anda tidak tertarik pada nilai-nilai yang dihasilkannya, tetapi pada beberapa efek samping. Misalnya, pengecualian, menulis ke file, mengubah variabel global, dll.
Ada cara mudah dan populer untuk melakukan ini adalah
list(gen())
. Namun, metode ini menyimpan semua nilai ke memori, dan kemudian segera menghapusnya. Ini mungkin berlebihan. Jika Anda ingin menghindari perilaku ini, Anda dapat menggunakan
deque
dengan batas ukuran:
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')
Demi akurasi semantik, Anda dapat mendefinisikan fungsi
exhaust
Anda sendiri:
def exhaust(iterable): for _ in iterable: pass
Misalkan Anda memiliki beberapa kelas - anak induk,
User
dan
Admin
. Dan Anda juga memiliki fungsi yang mengambil daftar pengguna sebagai argumen. Bisakah Anda memberikan daftar admin? Tidak: fungsi dapat menambahkan pengguna lain ke daftar admin, yang salah dan melanggar jaminan yang disediakan oleh daftar.
Namun, Anda bisa memberikan jenis
Sequence
karena itu hanya baca. Lebih tepatnya, dalam hal ini,
Sequence
adalah kovarian dalam jenis peserta.
Anda dapat mendefinisikan tipe kovarian dengan memberikan
covariant=True
sebagai argumen untuk
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, suatu fungsi mungkin memerlukan wadah hanya untuk menempatkan admin di dalamnya. Wadah seperti itu, yang hanya tersedia untuk rekaman, bersifat
contravarian menurut jenis peserta:
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 .