🔆 نکات کلیدی برای تمیزتر کد زدن در پایتون و چندزبان دیگر
🔹github.com/zedr/clean-code-python
🔹github.com/jupeter/clean-code-php
🔹github.com/ryanmcdermott/clean-code-javascript
🔹github.com/thangchung/clean-code-dotnet
🔹github.com/labs42io/clean-code-typescript
🐍 @python_rd
🔹github.com/zedr/clean-code-python
🔹github.com/jupeter/clean-code-php
🔹github.com/ryanmcdermott/clean-code-javascript
🔹github.com/thangchung/clean-code-dotnet
🔹github.com/labs42io/clean-code-typescript
🐍 @python_rd
🔆 مدیریت منابع با contextlib
🔹 از تکرار try...finally برای بستن فایلها و اتصالها خسته شدی؟
🔹 پایتون ابزاری به نام Context Manager داره که با دستور with استفاده میشه. اما اگر بخوای خودت یک Context Manager سفارشی بسازی، نیازی نیست حتماً کلاس با متدهای enter و exit بنویسی!
با ماژول contextlib و دکوراتور @contextmanager میتونی خیلی تمیز این کار رو انجام بدی:
🐍 @python_rd
🔹 از تکرار try...finally برای بستن فایلها و اتصالها خسته شدی؟
🔹 پایتون ابزاری به نام Context Manager داره که با دستور with استفاده میشه. اما اگر بخوای خودت یک Context Manager سفارشی بسازی، نیازی نیست حتماً کلاس با متدهای enter و exit بنویسی!
با ماژول contextlib و دکوراتور @contextmanager میتونی خیلی تمیز این کار رو انجام بدی:
from contextlib import contextmanager
@contextmanager
def managed_resource():
print("-> باز کردن اتصال/فایل")
yield "Resource Object"
print("-> بستن ایمن اتصال/فایل")
# استفاده:
with managed_resource() as res:
print(f"در حال کار با: {res}")
🐍 @python_rd
🔆 خروجی این تکه کد چیه؟
🔹گزینهها:
الف) [1], [2], [9, 9, 3], [4]
ب) [1], [1, 2], [9, 9, 3], [1, 2, 4]
ج) [1], [2], [3], [4]
🐍 @python_rd
def add_item(item, lst=[]):
lst.append(item)
return lst
print(add_item(1))
print(add_item(2))
print(add_item(3, [9, 9]))
print(add_item(4))
🔹گزینهها:
الف) [1], [2], [9, 9, 3], [4]
ب) [1], [1, 2], [9, 9, 3], [1, 2, 4]
ج) [1], [2], [3], [4]
🐍 @python_rd
🔆 چرا برای دادههای حجیم نباید از return استفاده کنی؟
🔹 وقتی یک تابع لیست بزرگی از دادهها رو با return برمیگرداند، کل دادهها باید همزمان توی رم (RAM) لود بشن که باعث مصرف شدید حافظه و کندی سیستم میشه.
🔹 اما اگر به جای return از yield استفاده کنی، تابع تبدیل به یک Generator میشه که دادهها رو به صورت تکبهتک و تنبل (Lazy Evaluation) تولید میکنه:
🔹با این روش میتونی فایلهای چند گیگابایتی رو با مصرف چند مگابایت رم پردازش کنی!
🐍 @python_rd
🔹 وقتی یک تابع لیست بزرگی از دادهها رو با return برمیگرداند، کل دادهها باید همزمان توی رم (RAM) لود بشن که باعث مصرف شدید حافظه و کندی سیستم میشه.
🔹 اما اگر به جای return از yield استفاده کنی، تابع تبدیل به یک Generator میشه که دادهها رو به صورت تکبهتک و تنبل (Lazy Evaluation) تولید میکنه:
def read_large_file(file_path):
with open(file_path, 'r') as f:
for line in f:
yield line.strip() # هر بار فقط یک خط را در حافظه نگه میدارد
🔹با این روش میتونی فایلهای چند گیگابایتی رو با مصرف چند مگابایت رم پردازش کنی!
🐍 @python_rd
🔆 مدیریت تمیز منابع با Context Managerهای سفارشی (contextlib)
🔹 ساخت Context Managerها معمولاً با نوشتن کلاس و متدهای enter و exit انجام میشود. اما با دکوراتور contextmanager@ از ماژول contextlib میتوانید این کار را خیلی سریعتر و پایتونیکتر انجام دهید.
🐍 @python_rd
🔹 ساخت Context Managerها معمولاً با نوشتن کلاس و متدهای enter و exit انجام میشود. اما با دکوراتور contextmanager@ از ماژول contextlib میتوانید این کار را خیلی سریعتر و پایتونیکتر انجام دهید.
from contextlib import contextmanager
import time
@contextmanager
def measure_time(task_name: str):
start_time = time.perf_counter()
print(f"--- شروع: {task_name} ---")
try:
yield # کنترل اجرا در این نقطه به بدنه with منتقل میشود
finally:
elapsed = time.perf_counter() - start_time
print(f"--- پایان: {task_name} | زمان اجرا: {elapsed:.4f} ثانیه ---\n")
# استفاده کاربردی
with measure_time("پردازش سنگین دادهها"):
# شبیهسازی یک کار سنگین
total = sum(i**2 for i in range(10_000_000))
print(f"نتیجه محاسبات: {total}")
🐍 @python_rd
🔆 حذف تاریخی GIL از پایتون (Free-threaded Python)
🔹 یک رویداد تاریخی: حذف قفل مفسر (GIL) از هسته CPython رسماً کلید خورد!
🔹 سرانجام پس از سالها بحث و مناظره در بنیاد نرمافزار پایتون (PSF)، طرح PEP 703 (معروف به Free-threaded CPython) تصویب و گامهای اجرایی آن آغاز شد. با این تغییر، مفسر پایتون میتواند از تمام هستههای پردازنده (Multi-Core CPU) در Multi-threading به صورت واقعی بهره ببرد بدون اینکه گلوگاه قفل مفسر سر راهش باشد.
🔹 نکات کلیدی این تحول:
▪️ پشتیبانی اولیه به صورت بیلد آزمایشی (Experimental /
▪️ تیمهای توسعه کتابخانههای بزرگ مانند NumPy و PyTorch در حال بازنویسی بخشهای C-API خود برای سازگاری با حالت بدون GIL هستند.
▪️ طبق پیشبینی هسته مرکزی، پایتون در پردازشهای سنگین موازی تا چند برابر افزایش کارایی را تجربه خواهد کرد.
🔹 منبع رسمی:
• مستندات رسمی PEP 703: peps.python.org/pep-0703
• اعلامیه Steering Council پایتون: discuss.python.org
🐍 @python_rd
🔹 یک رویداد تاریخی: حذف قفل مفسر (GIL) از هسته CPython رسماً کلید خورد!
🔹 سرانجام پس از سالها بحث و مناظره در بنیاد نرمافزار پایتون (PSF)، طرح PEP 703 (معروف به Free-threaded CPython) تصویب و گامهای اجرایی آن آغاز شد. با این تغییر، مفسر پایتون میتواند از تمام هستههای پردازنده (Multi-Core CPU) در Multi-threading به صورت واقعی بهره ببرد بدون اینکه گلوگاه قفل مفسر سر راهش باشد.
🔹 نکات کلیدی این تحول:
▪️ پشتیبانی اولیه به صورت بیلد آزمایشی (Experimental /
--disable-gil) در دسترس قرار گرفته است.▪️ تیمهای توسعه کتابخانههای بزرگ مانند NumPy و PyTorch در حال بازنویسی بخشهای C-API خود برای سازگاری با حالت بدون GIL هستند.
▪️ طبق پیشبینی هسته مرکزی، پایتون در پردازشهای سنگین موازی تا چند برابر افزایش کارایی را تجربه خواهد کرد.
🔹 منبع رسمی:
• مستندات رسمی PEP 703: peps.python.org/pep-0703
• اعلامیه Steering Council پایتون: discuss.python.org
🐍 @python_rd
Python Enhancement Proposals (PEPs)
PEP 703 – Making the Global Interpreter Lock Optional in CPython | peps.python.org
CPython’s global interpreter lock (“GIL”) prevents multiple threads from executing Python code at the same time. The GIL is an obstacle to using multi-core CPUs from Python efficiently. This PEP proposes adding a build configuration (--disable-gil) to...
🔆 راز مکانیزم پیادهسازی و تغییر جهت
🔹 باگ ریاضیاتی پنهان: چرا پایتون هیچوقت نمیتواند لیستی از NaNها را مرتب کند؟!
🔹 در پایتون، مقدار
nan طبق استاندارد IEEE-754 با خودش هم برابر نیست!
🔹 حالا شگفتی ماجرا در متد
الگوریتم مرتبسازی CPython یعنی Timsort بر اصل تقارن و ترتیبی بودن مقایسهها استوار است. اگر شما لیستی شامل اعداد و NaN را با
🔹 نتیجه خروجی به ترتیب قرارگیری اولیه عناصر بستگی دارد و غیرقابلپیشبینی است!
🔹 پایتون هیچ خطایی (Error) raise نمیکند، اما خروجی نهایی مرتبشده نخواهد بود!
🔹 مهندسان CPython سالهاست که در گیتهاب پایتون روی این موضوع بحث دارند و تصمیم گرفتهاند برای حفظ پرفورمنس Timsort، هیچ لایه اعتبارسنجی اضافی اضافه نکنند و این مسئولیت را روی دوش برنامهنویس بگذارند!
🐍@python_rd
NaN در الگوریتم مرتبسازی پایتون (Timsort)🔹 باگ ریاضیاتی پنهان: چرا پایتون هیچوقت نمیتواند لیستی از NaNها را مرتب کند؟!
🔹 در پایتون، مقدار
float('nan') (Not a Number) خصوصیت عجیبی دارد:nan طبق استاندارد IEEE-754 با خودش هم برابر نیست!
float('nan') == float('nan') ⬅️ خروجی False است!float('nan') < 5 ⬅️ باز هم False است!🔹 حالا شگفتی ماجرا در متد
.sort() پایتون است:الگوریتم مرتبسازی CPython یعنی Timsort بر اصل تقارن و ترتیبی بودن مقایسهها استوار است. اگر شما لیستی شامل اعداد و NaN را با
.sort() مرتب کنید:🔹 نتیجه خروجی به ترتیب قرارگیری اولیه عناصر بستگی دارد و غیرقابلپیشبینی است!
🔹 پایتون هیچ خطایی (Error) raise نمیکند، اما خروجی نهایی مرتبشده نخواهد بود!
🔹 مهندسان CPython سالهاست که در گیتهاب پایتون روی این موضوع بحث دارند و تصمیم گرفتهاند برای حفظ پرفورمنس Timsort، هیچ لایه اعتبارسنجی اضافی اضافه نکنند و این مسئولیت را روی دوش برنامهنویس بگذارند!
🐍@python_rd
کوییز پایتون
🔆 خروجی اجرای کد زیر چیست؟
🔹 گزینهها:
1️⃣
2️⃣
3️⃣ خطای مدیریتنشده رخ میدهد و برنامه متوقف میشود
4️⃣ خروجی
🐍@python_rd
🔆 خروجی اجرای کد زیر چیست؟
t = (1, 2, [3, 4])
try:
t[2] += [5]
except TypeError:
pass
print(t)
🔹 گزینهها:
1️⃣
(1, 2, [3, 4])2️⃣
(1, 2, [3, 4, 5])3️⃣ خطای مدیریتنشده رخ میدهد و برنامه متوقف میشود
4️⃣ خروجی
(1, 2, [5]) خواهد بود🐍@python_rd
🔆 یک تله عجیب در پایتون:
🔹 خیلیها میدانند
🔹 این یعنی:
در سطح type system، از
🔹 این رفتار در خیلی از سناریوها مفید است، ولی اگر روی counting، hashing یا data processing کار کنی، گاهی میتواند نتایج عجیبی بسازد.
🐍 @python_rd
bool در واقع زیرکلاس int است🔹 خیلیها میدانند
True == 1 و False == 0، اما نکته عجیبتر اینجاست که:print(isinstance(True, int)) # True
print(True + True) # 2
print(False + 10) # 10
🔹 این یعنی:
True و False فقط مقدار بولی نیستنددر سطح type system، از
int ارثبری میکنند🔹 این رفتار در خیلی از سناریوها مفید است، ولی اگر روی counting، hashing یا data processing کار کنی، گاهی میتواند نتایج عجیبی بسازد.
🐍 @python_rd
❤4
🔆 آیا
🔹 خیلیها هنوز این شکلی مینویسند:
🔹 ولی راه پایتونیکتر:
🔹 اگر index را از 1 بخواهی:
🔹 چرا بهتر است؟
خواناتر است
خطای index کمتر میشود
پایتونیکتر و حرفهایتر است
🔹 این از آن تفاوتهای کوچک است که کیفیت کد را در بلندمدت خیلی بالا میبرد.
🐍 @python_rd
enumerate() بهتر از index-based loop است؟🔹 خیلیها هنوز این شکلی مینویسند:
items = ["apple", "banana", "orange"]
for i in range(len(items)):
print(i, items[i])
🔹 ولی راه پایتونیکتر:
items = ["apple", "banana", "orange"]
for index, value in enumerate(items):
print(index, value)
🔹 اگر index را از 1 بخواهی:
for index, value in enumerate(items, start=1):
print(index, value)
🔹 چرا بهتر است؟
خواناتر است
خطای index کمتر میشود
پایتونیکتر و حرفهایتر است
🔹 این از آن تفاوتهای کوچک است که کیفیت کد را در بلندمدت خیلی بالا میبرد.
🐍 @python_rd
🌐 خروجی این کد پایتون چیست؟
🔹 گزینهها:
🔹A)
[1, 2, 3, 4, 5]
[1, 2, 3]
🔹B)
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
🔹C)
Error
🔹D)
[4, 5]
[1, 2, 3]
🐍 @python_rd
x = [1, 2, 3]
y = x
x += [4, 5]
print(x)
print(y)
🔹 گزینهها:
🔹A)
[1, 2, 3, 4, 5]
[1, 2, 3]
🔹B)
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
🔹C)
Error
🔹D)
[4, 5]
[1, 2, 3]
🐍 @python_rd