🔶 ماژول itertools توابعی را در اختیار قرار میدهد که به شما امکان ایجاد ایتریتورهای مختلف و کارهایی را که معمولا با استفاده از حلقههای while و for انجام میشوند، به راحتی و با کمترین کد ممکن را میدهد.
🔷 این ماژول همچنین کلاسهایی دارد که به شما امکان میدهد دو یا چند ایتریتور را ترکیب یا فیلتر کنید، ترتیب عناصر را تغییر دهید و بسیاری از عملیاتهای دیگر را بر روی ایتریتورها انجام دهید.
در کل، Itertools یک ابزار بسیار کارآمد و پرکاربرد است که به شما کمک میکند تا کد خود را بهینهتر کنید و در نتیجه عملکرد آن را بهبود بخشید.
🔸 در ادامه، به توضیح هر یک از اجزای ماژول itertools میپردازیم.
#itertools #iterable #iterator #Module
✍🏻 *ژنرال*
💎 Channel: @DevelopixPython
🔷 این ماژول همچنین کلاسهایی دارد که به شما امکان میدهد دو یا چند ایتریتور را ترکیب یا فیلتر کنید، ترتیب عناصر را تغییر دهید و بسیاری از عملیاتهای دیگر را بر روی ایتریتورها انجام دهید.
در کل، Itertools یک ابزار بسیار کارآمد و پرکاربرد است که به شما کمک میکند تا کد خود را بهینهتر کنید و در نتیجه عملکرد آن را بهبود بخشید.
🔸 در ادامه، به توضیح هر یک از اجزای ماژول itertools میپردازیم.
#itertools #iterable #iterator #Module
✍🏻 *ژنرال*
💎 Channel: @DevelopixPython
👍4🔥3
🔸 توضیح اجزای ماژول itertools
🔹 پارت یک
🔘 itertools.count(start, step)
🔸 کلاس count یک شمارنده ایجاد می کند که به طور پیشفرض از عدد صفر شروع می کند و به طور پیوسته به بی نهایت ادامه پیدا می کند.
🔹این کلاس در پایتون دو پارامتر اختیاری به نامهای start و step دارد. پارامتر start مشخص میکند از کدام عدد باید شروع به تولید دنباله کنیم و پارامتر step تعداد فاصلههای بین اعداد را تعیین میکند.
💡مثال
🔸 کلاس cycle یک iterator برای تکرار یک iterable به صورت بینهایت ایجاد میکند.
🔹در پایتون، iterable ها نمیتوانند تکرارپذیر باشند و برای دوباره استفاده از آنها، باید iterable ها را مجدداً تعریف کرد. اما با استفاده از کلاس cycle میتوانید به سادگی این محدودیت را نادیده بگیرید و iterable را به صورت یک حلقه نامتناهی تکرار کنید.
💡مثال
🔸کلاس chain دو یا چند iterable را به عنوان ورودی میگیرد و آنها را به صورت پشت سر هم در یک iterator واحد قرار میدهد.
💡مثال
✍🏻 *ژنرال*
💎 Channel: @DevelopixPython
🔹 پارت یک
🔘 itertools.count(start, step)
🔸 کلاس count یک شمارنده ایجاد می کند که به طور پیشفرض از عدد صفر شروع می کند و به طور پیوسته به بی نهایت ادامه پیدا می کند.
🔹این کلاس در پایتون دو پارامتر اختیاری به نامهای start و step دارد. پارامتر start مشخص میکند از کدام عدد باید شروع به تولید دنباله کنیم و پارامتر step تعداد فاصلههای بین اعداد را تعیین میکند.
💡مثال
counter = itertools.count(30, 10)
print(next(counter)) # 30
print(next(counter)) # 40
print(next(counter)) # 50
🔘 itertools.cycle(iterable)🔸 کلاس cycle یک iterator برای تکرار یک iterable به صورت بینهایت ایجاد میکند.
🔹در پایتون، iterable ها نمیتوانند تکرارپذیر باشند و برای دوباره استفاده از آنها، باید iterable ها را مجدداً تعریف کرد. اما با استفاده از کلاس cycle میتوانید به سادگی این محدودیت را نادیده بگیرید و iterable را به صورت یک حلقه نامتناهی تکرار کنید.
💡مثال
cycle = itertools.cycle([1, 2])
print(next(cycle)) # 1
print(next(cycle)) # 2
print(next(cycle)) # 1
🔘 itertools.chain(*iterables)🔸کلاس chain دو یا چند iterable را به عنوان ورودی میگیرد و آنها را به صورت پشت سر هم در یک iterator واحد قرار میدهد.
💡مثال
iterator = itertools.chain([1, 2, 3], [4, 5, 6])
for item in iterator:
print(item) # 1, 2, ..., 6
#itertools #iterable #iterator #Module✍🏻 *ژنرال*
💎 Channel: @DevelopixPython
👍3🔥2
🔸 توضیح اجزای ماژول itertools
🔹 پارت دو
🔸 کلاس repeat یک شیء و یک تعداد بار تکرار را به عنوان ورودی میگیرد و تکرار این مقدار را به تعداد مشخص شده تولید میکند.
🔹اگر به عنوان پارامتر times مقداری داده نشود، شیء داده شده برای بینهایت بار تکرار خواهد شد.
💡مثال
🔸کلاس compress یک iterable معمولی و یک iterable از مقادیر بولین با طول برابر (با تعداد مقادیر iterable اولیه) را به عنوان ورودی میگیرد و فقط مقادیری را که در مقابل هر مقدار بولینی که در ورودی داده شده است True هستند، در یک iterator تولید میکند.
💡مثال
🔸کلاس filterfalse یک iterator و یک تابع پذیرنده گرفته و همانند تابع filter عمل می کند، با این تفاوت که در جایگاه شرط منفی تابع پذیرنده قرار میگیرد.
💡مثال
✍🏻 *ژنرال*
💎 Channel: @DevelopixPython
🔹 پارت دو
🔸 کلاس repeat یک شیء و یک تعداد بار تکرار را به عنوان ورودی میگیرد و تکرار این مقدار را به تعداد مشخص شده تولید میکند.
🔹اگر به عنوان پارامتر times مقداری داده نشود، شیء داده شده برای بینهایت بار تکرار خواهد شد.
💡مثال
iterator = itertools.repeat("AnyObject", 2)
for item in iterator:
print(item) # AnyObject, AnyObject
🔘 itertools.compress(data, selectors)🔸کلاس compress یک iterable معمولی و یک iterable از مقادیر بولین با طول برابر (با تعداد مقادیر iterable اولیه) را به عنوان ورودی میگیرد و فقط مقادیری را که در مقابل هر مقدار بولینی که در ورودی داده شده است True هستند، در یک iterator تولید میکند.
💡مثال
values = ("A", "B", "C")
bools = (True, False, True)
iterator = itertools.compress(values, bools)
for item in iterator:
print(item) # A, C
🔘 itertools.filterfalse(predicate, iterable)🔸کلاس filterfalse یک iterator و یک تابع پذیرنده گرفته و همانند تابع filter عمل می کند، با این تفاوت که در جایگاه شرط منفی تابع پذیرنده قرار میگیرد.
💡مثال
iterator = itertools.filterfalse(
lambda n: n % 2 == 0,
[1, 2, 3, 4, 5]
)
for item in iterator:
print(item) # 1, 3, 5
#itertools #iterable #iterator #Module✍🏻 *ژنرال*
💎 Channel: @DevelopixPython
👍2🔥2
🔸 توضیح اجزای ماژول itertools
🔹 پارت سه
🔘 itertools.dropwhile(predicate, iterable)
🔸کلاس dropwhile برای حذف مقادیر اول یک iterable استفاده میشود. با دادن یک تابع برای بررسی به عنوان پارامتر اول و یک iterable به عنوان پارامتر دوم، این کلاس مقادیر iterable را از اولین مقداری که تابع داده شده برای آن درست نیست شروع به بازگشت میدهد.
🔹تفاوت اصلی بین dropwhile و تابع filter این است که dropwhile اجزای iterable را به ترتیب بررسی میکند و تا زمانی که شرط تعیین شده توسط تابع شرطی درست باشد، اجزا را رد میکند. ولی filter همه اجزای iterable را بررسی میکند و فقط اجزایی که شرط تعیین شده را برآورده میکنند را برمیگرداند.
💡مثال
🔸کلاس groupby برای گروهبندی مقادیر یک iterable بر اساس یک تابع کلید استفاده میشود. با دادن یک iterable به عنوان پارامتر اول و یک تابع کلید به عنوان پارامتر دوم، groupby مقادیر iterable را بر اساس مقداری که تابع کلید برای آنها برمیگرداند، گروهبندی میکند.
💡مثال
🔸کلاس islice برای ساخت یک iterator از یک iterable با طول مشخص استفاده میشود.
🔹با دادن یک iterable به عنوان پارامتر اول و حداقل، حداکثر و فاصلههای بین اندیسها به عنوان پارامتر دوم، سوم و چهارم، islice یک iterator از مقادیر iterable با اندیسهای مشخص شده ایجاد میکند.
💡مثال
✍🏻 *ژنرال*
💎 Channel: @DevelopixPython
🔹 پارت سه
🔘 itertools.dropwhile(predicate, iterable)
🔸کلاس dropwhile برای حذف مقادیر اول یک iterable استفاده میشود. با دادن یک تابع برای بررسی به عنوان پارامتر اول و یک iterable به عنوان پارامتر دوم، این کلاس مقادیر iterable را از اولین مقداری که تابع داده شده برای آن درست نیست شروع به بازگشت میدهد.
🔹تفاوت اصلی بین dropwhile و تابع filter این است که dropwhile اجزای iterable را به ترتیب بررسی میکند و تا زمانی که شرط تعیین شده توسط تابع شرطی درست باشد، اجزا را رد میکند. ولی filter همه اجزای iterable را بررسی میکند و فقط اجزایی که شرط تعیین شده را برآورده میکنند را برمیگرداند.
💡مثال
iterator = itertools.dropwhile(
lambda x: x < 3,
[1, 2, 3, 4, 5]
)
for item in iterator:
print(item) # 3, 4, 5
🔘 itertools.groupby(iterable, key)🔸کلاس groupby برای گروهبندی مقادیر یک iterable بر اساس یک تابع کلید استفاده میشود. با دادن یک iterable به عنوان پارامتر اول و یک تابع کلید به عنوان پارامتر دوم، groupby مقادیر iterable را بر اساس مقداری که تابع کلید برای آنها برمیگرداند، گروهبندی میکند.
💡مثال
dicts = [
{"name": "Mona", "age": 21},
{"name": "Mina", "age": 21},
{"name": "Nima", "age": 23},
{"name": "Sina", "age": 23}
]
iterator = itertools.groupby(
dicts,
key=lambda x: x["age"]
)
for key, group in iterator:
print(key, list(group))
# 21 [{'name': 'Mona', 'age': 21}, {'name': 'Mina', 'age': 21}]
# 23 [{'name': 'Nima', 'age': 23}, {'name': 'Sina', 'age': 23}]
🔘 itertools.islice(iterable, start, stop, step)🔸کلاس islice برای ساخت یک iterator از یک iterable با طول مشخص استفاده میشود.
🔹با دادن یک iterable به عنوان پارامتر اول و حداقل، حداکثر و فاصلههای بین اندیسها به عنوان پارامتر دوم، سوم و چهارم، islice یک iterator از مقادیر iterable با اندیسهای مشخص شده ایجاد میکند.
💡مثال
iterable = range(10)
for i in itertools.islice(iterable, 1, 8, 2):
print(i) # 1, 3, 5, 7
#itertools #iterable #iterator #Module✍🏻 *ژنرال*
💎 Channel: @DevelopixPython
👍2🔥2
🔸 توضیح اجزای ماژول itertools
🔹 پارت چهار
🔘 itertools.tee(iterable, n)
🔸تابع tee یک iterable را به عنوان ورودی دریافت میکند و چندین iterator مستقل از آن ترتیب را بازگردانده میکند.
💡مثال
🔸کلاس pairwise یک ترکیب از دو مقدار پشت سر هم در یک iterable را برمیگرداند. به عبارت دیگر، این کلاس دو تا دو تا مقادیر iterable را در اختیار میگذارد و آنها را به صورت زوجهایی از مقادیر متوالی برمیگرداند.
🔹استفاده از این کلاس، نیازمند استفاده از نسخه پایتون 3.10 یا بالاتر آن است.
💡مثال
🔸کلاس batched به شما امکان می دهد تا یک iterable را به دسته های مشخص تقسیم کنید و هر دسته را به صورت یک tuple برگردانید.
🔹استفاده از این کلاس، نیازمند استفاده از نسخه پایتون 3.12 یا بالاتر آن است.
💡مثال
✍🏻 *ژنرال*
💎 Channel: @DevelopixPython
🔹 پارت چهار
🔘 itertools.tee(iterable, n)
🔸تابع tee یک iterable را به عنوان ورودی دریافت میکند و چندین iterator مستقل از آن ترتیب را بازگردانده میکند.
💡مثال
iterators = itertools.tee([1, 2, 3, 4, 5], 3)
for iterator in iterators:
print(tuple(iterator))
# (1, 2, 3, 4, 5)
# (1, 2, 3, 4, 5)
# (1, 2, 3, 4, 5)
🔘 itertools.pairwise(iterable)🔸کلاس pairwise یک ترکیب از دو مقدار پشت سر هم در یک iterable را برمیگرداند. به عبارت دیگر، این کلاس دو تا دو تا مقادیر iterable را در اختیار میگذارد و آنها را به صورت زوجهایی از مقادیر متوالی برمیگرداند.
🔹استفاده از این کلاس، نیازمند استفاده از نسخه پایتون 3.10 یا بالاتر آن است.
💡مثال
for a, b in itertools.pairwise([1, 2, 3, 4]):
print(f"{a} & {b}")
# 1 & 2
# 2 & 3
# 3 & 4
🔘 itertools.batched(iterable, n)🔸کلاس batched به شما امکان می دهد تا یک iterable را به دسته های مشخص تقسیم کنید و هر دسته را به صورت یک tuple برگردانید.
🔹استفاده از این کلاس، نیازمند استفاده از نسخه پایتون 3.12 یا بالاتر آن است.
💡مثال
iterator = itertools.batched([1, 2, 3, 4, 5, 6], 2)
for batch in iterator:
print(batch) # (1, 2), (3, 4), (5, 6)
#itertools #iterable #iterator #Module✍🏻 *ژنرال*
💎 Channel: @DevelopixPython
👍4🔥2
💠 PEP 749: Deferred Evaluation Of Annotations Using Descriptors
بعد از چند سال حالا PEP 649 به لطف ارائه خوب PEP 749 تایید شده و قراره تحولی رو در annotation ها داشته باشیم.
به این کد دقت کنید:
در حالت عادی چون نوع برگشتی method ما B هست و B هم تا اون لحظه تعریف نشده به
خب، این واقعا کثیف کاری بود. IDE ها به درستی میتونستند type ها رو تشخیص بدند و مفسر هم دیگه خطای
اما همونطور که گفته شد همه اونها به string تبدیل میشدند و اگر کد زیر خواسته میشد خروجی مطلوب (که خود کلاس B هست) داده نمیشد و در عوض
این یعنی مشکل. چرا؟ چون در صورتی که مقدار local باشه الزاما دیگه به متغیر ها دسترسی نداریم و حتی اگر دسترسی داشته باشیم باید اون رو eval کنیم که کار جالبی نیست.
راهحلی درحال اضافه شدن هست. در نسخه 3.14 باز هم از مفهوم lazy evaluation قراره استفاده دیگهای بشه. علت برخورد شما به
این یک تحول نسبتا بزرگ برای زبان پایتون هست، اللخصوص برای نویسندگان کتابخونه ها. ممکنه دیده باشید که به جای
چه اتفاقی برای
این موضوع حتی فراتر از این حرف ها هست و ما حتی یک module کاملا جدید رو قراره در stdlib داشته باشیم. همونطور که گفته شده استفاده از inspect برای دسترسی به annotation ها راه خوبی نیست چون واقعا سنگینه. پس حالا
ما تابهحال نوع خاصی برای annotation ها نداشتیم (نوع کلی) اما حالا داریم:
1. VALUE: همون مقدار پیشفرض که تا الان هم داشتیم
2. FORWARDREF: در صورت نبود مقدار مشخصی برای اسم به کار برده شده
3. STRING: مقدار متنی اونها (کاملا مناسب برای ابزار document کردن)
تنها مورد جدید ForwardRef هست. چه زمانی این نوع دیده میشه؟ زمانی که عملا هیچ چیزی با این name وجود نداشته باشه (قبلا در این شرایط
این موضوع هیچ تاثیر منفی روی std wrapper هایی مثل classmethod، staticmethod، functools.wraps و موارد دیگه قرار نیست بزاره و همه همگام میشن پس لازم نیست در این مورد نگران باشیم.
به طور خلاصه، تغییر سنگینی در انتظار نویسندگان کتابخونه های بزرگ هست اما بعد از اون نوشتن annotation ها واقعا خیلی راحت تر میشه و پایتون خیلی مهربون تر با این قضیه برخورد میکنه.
✍️ *ژنرال*
🏷 #Python, #PEP, #annotations, #typehint, #pep749, #NameError
💎 Channel: @DevelopixPython
بعد از چند سال حالا PEP 649 به لطف ارائه خوب PEP 749 تایید شده و قراره تحولی رو در annotation ها داشته باشیم.
به این کد دقت کنید:
class A:
def method(self) -> B: ...
class B: ...
در حالت عادی چون نوع برگشتی method ما B هست و B هم تا اون لحظه تعریف نشده به
NameError
برخورد میکنیم. این تا حد زیادی تبدیل به یک معضل شده بود تا اینکه اجازه استفاده از literal string ها به عنوان نوعی ارجاع دهنده داده شد که در __annotations__
هم لحاظ میشن. این موضوع حتی فراتر از این حدود هم پیش رفت و با ارائه PEP 563 و امکان استفاده از annotations
در __future__
، تمام annotation ها هنگام اجرای کد (runtime) تبدیل به string میشن (بدون استثنا، تمام annotation ها).خب، این واقعا کثیف کاری بود. IDE ها به درستی میتونستند type ها رو تشخیص بدند و مفسر هم دیگه خطای
NameError
نمیداد:from __future__ import annotations
class A:
def method(self) -> B: ...
class B: ...
اما همونطور که گفته شد همه اونها به string تبدیل میشدند و اگر کد زیر خواسته میشد خروجی مطلوب (که خود کلاس B هست) داده نمیشد و در عوض
"B"
رو میدیدم.print(A.method.__annotations__)
این یعنی مشکل. چرا؟ چون در صورتی که مقدار local باشه الزاما دیگه به متغیر ها دسترسی نداریم و حتی اگر دسترسی داشته باشیم باید اون رو eval کنیم که کار جالبی نیست.
راهحلی درحال اضافه شدن هست. در نسخه 3.14 باز هم از مفهوم lazy evaluation قراره استفاده دیگهای بشه. علت برخورد شما به
NameError
در کد اول این هست که مفسر بلافاصله میخواد به annotation دسترسی پیدا کنه، اما حالا این کار رو انجام نمیده و فقط زمانی که باید بهشون دسترسی گرفته بشه این کار رو انجام میده که باعث میشه موقع load کردن code شما حتی اگر annotation وجود خارجی هم نداشت باعث مشکل نشه.این یک تحول نسبتا بزرگ برای زبان پایتون هست، اللخصوص برای نویسندگان کتابخونه ها. ممکنه دیده باشید که به جای
SomeType
نوشته شده باشه "SomeType"
چرا؟ چون به هر دلیلی نویسنده خواسته از NameError
فرار کنه. اما حالا نه، لازم نیست quote قرار داده بشه و مستقیما میشه از خودش استفاده کرد.چه اتفاقی برای
annotations
در __future__
میوفته؟ در نسخه 3.15 حذف میشه و احتمالا هشدار منسوخ شدن برای استفاده از اون در نسخه 3.14 اضافه خواهد شد.این موضوع حتی فراتر از این حرف ها هست و ما حتی یک module کاملا جدید رو قراره در stdlib داشته باشیم. همونطور که گفته شده استفاده از inspect برای دسترسی به annotation ها راه خوبی نیست چون واقعا سنگینه. پس حالا
annotationlib
رو قراره داشته باشیم که ابزاری کاملا مناسب هست و به راحتی قابل استفادهست.ما تابهحال نوع خاصی برای annotation ها نداشتیم (نوع کلی) اما حالا داریم:
1. VALUE: همون مقدار پیشفرض که تا الان هم داشتیم
2. FORWARDREF: در صورت نبود مقدار مشخصی برای اسم به کار برده شده
3. STRING: مقدار متنی اونها (کاملا مناسب برای ابزار document کردن)
تنها مورد جدید ForwardRef هست. چه زمانی این نوع دیده میشه؟ زمانی که عملا هیچ چیزی با این name وجود نداشته باشه (قبلا در این شرایط
NameError
داده میشد) و حالا با این نوع گفته میشه که "این نوع unresolved هست"این موضوع هیچ تاثیر منفی روی std wrapper هایی مثل classmethod، staticmethod، functools.wraps و موارد دیگه قرار نیست بزاره و همه همگام میشن پس لازم نیست در این مورد نگران باشیم.
به طور خلاصه، تغییر سنگینی در انتظار نویسندگان کتابخونه های بزرگ هست اما بعد از اون نوشتن annotation ها واقعا خیلی راحت تر میشه و پایتون خیلی مهربون تر با این قضیه برخورد میکنه.
💎 Channel: @DevelopixPython
Please open Telegram to view this post
VIEW IN TELEGRAM
Python Enhancement Proposals (PEPs)
PEP 749 – Implementing PEP 649 | peps.python.org
This PEP supplements PEP 649 by providing various tweaks and additions to its specification:
👍11❤3🔥3