PyCoders (پایتون)
4.1K subscribers
979 photos
148 videos
69 files
238 links
◇ #پایتون جادوگر دنیای برنامه نویسی!
◇ معرفی حوزه های کاری پایتون
◇ معرفی کتابخونه های کاربردی
◇ معرفی دوره های مفید
◇ معرفی تکنیک ها و نکات
◇ نقشه راه حوزه های مختلف
◇ اخبار و آپدیت های پایتون
◇ و هر چیزی در مورد پایتون!

■ گروه پایتون:
@programmers_py
Download Telegram
🔆 تله کپی سطحی در ساختارهای تودرتو

🔹 خیلی از دولوپرهای پایتون تفاوت بین کپی معمولی و دیپ‌کپی رو نمی‌دونن و وقتی دیتای یک دیکشنری یا لیست تو در تو رو کپی می‌کنن، با تغییر مقدار یکی، اون یکی هم ناخواسته تغییر می‌کنه. خروجی کد زیر رو بررسی کن:

original = [[1, 2], [3, 4]]
shallow_copy = list(original)

shallow_copy[0][0] = 999

print(original[0][0])

🔹 خروجی عدد ۹۹۹ خواهد بود نه عدد ۱! دلیلش اینه که متد کپی سطحی فقط رفرنس لیست‌های داخلی رو کپی می‌کنه. اگر می‌خوای کپی کاملاً ایزوله‌ای بسازی که با تغییر دادنش آسیبی به اصل داده نرسه، باید از متد دیپ‌کپی در ماژول استاندارد کپی استفاده کنی.

🐍 @python_rd
🔆 اشتباه رایج: هندل کردن استثناها بدون ذکر نوع خطا

🔹 نوشتن یک عبارت اگزپت خالی یا گرفتن کلاس کلی اکسپشن یکی از بدترین عادت‌های کدنویسیه، چون تمام خطاهای سیستمی مثل بستن برنامه با کنترل سی یا خطاهای نگارشی رو مخفی می‌کنه.

🔹 کد پر از ریسک خطاهای نامرتبط رو پنهان می‌کنه، در حالی که راهکار درست اینه که دقیقاً نوع خطایی که انتظار داری رخ بده رو شکار کنی و ثبتش کنی.

# کد پر از باگ و مخفی‌کننده مشکلات
# try:
# val = int(user_input)
# except:
# pass

# راهکار استاندارد و شفاف
try:
val = int(user_input)
except ValueError as e:
print(f"فرمت ورودی نامعتبر است: {e}")

🔹 با این کار اگر توی تابع باگ عمیق‌تری مثل خطای دسترسی به حافظه یا نام‌گذاری اشتباه وجود داشته باشه، لاگ می‌شه و از دید تیم فنی مخفی نمی‌مونه.


🐍 @python_rd
🔆 یه وبسایت خوب برای یادگیری بازی‌سازی ساده با پایتون و pygame به همراه پروژه های عملی

🔹programarcadegames.com

🐍 @python_rd
❤3
🔆 بیش از  ۳۰ تمرین مقدماتی برای یادگیری زبان پایتون

🔹 practicepython.org

🐍 @python_rd
🔆 جادوی init_subclass: جایگزین مدرن و تمیز برای Metaclassها

🔹 اکثر پایتون‌کارها برای مانیتور کردن، ثبت (Registration) یا ولیدیشن کلاس‌های فرزندی که از یک کلاس به ارث می‌رسن، سراغ Metaclass میرن. اما متانویسی کد رو پیچیده، سنگین و خوانایی‌ش رو سخت می‌کنه.

🔹 از پایتون ۳.۶ به بعد، یک «تاس جادویی» به اسم init_subclass اضافه شد که ۹۰٪ نیازهای شما به متانویسی رو بدون هیچ پیچیدگی برطرف می‌کنه!

🔹 کاربرد واقعیش کجاست؟ (ساخت یک Plugin System خودکار)

🔹 فرض کنید می‌خواید هر وقت کلاسی از کلاس پایه شما ارث‌بری کرد، اسمش تلقائی توی یک دیکشنری ثبت بشه:

class BasePlugin:
plugins = {}

def __init_subclass__(cls, plugin_name: str = None, **kwargs):
super().__init_subclass__(**kwargs)
# اگر نام پلاگین مشخص نشده بود، از اسم خود کلاس استفاده کن
name = plugin_name or cls.__name__
cls.plugins[name] = cls


# حالا هر پلاگینی تعریف بشه، اتوماتیک ثبت میشه:
class AudioPlugin(BasePlugin, plugin_name="audio_player"):
pass

class VideoPlugin(BasePlugin, plugin_name="video_player"):
pass


print(BasePlugin.plugins)
# خروجی:
# {'audio_player': <class '__main__.AudioPlugin'>, 'video_player': <class '__main__.VideoPlugin'>}

🔹به چه دردی میخوره؟

بدون ساخت Metaclass پیچیده، رفتارهای ارث‌بری رو مدیریت می‌کنید.

می‌‌تونید ورودی‌های سفارشی (مثل plugin_name) مستقیماً موقع ارث‌بری کلاس بهش بدید.

کد کاملاً تمیز، خوانا و مطابق استاندارد روز پایتونه.

🐍 @python_rd
👍1
🔆 چرا نباید از global توی پروژه‌های پایتونی استفاده کنیم؟

🔹 متغیرهای Global با اینکه کار رو سریع راه می‌اندازن، اما چالش‌های بزرگی ایجاد می‌کنن:

سخت شدن دیباگ: هر تابعی می‌تونه متغیر رو تغییر بده و پیدا کردن منشأ ارور سخت میشه.

تست‌نویسی کابوس‌وار: تست‌های ایزوله (Unit Tests) به مشکل می‌خورن.


🔹جایگزین: پاس دادن متغیرها به عنوان پارامتر ورودی تابع، یا استفاده از الگوریتم‌های Object-Oriented و تزریق وابستگی (Dependency Injection).

🐍 @python_rd
❤5👍1
🔆 اجرای فرآیند پس‌زمینه بدون بلاک شدن برنامه با iter() دو آرگومانه‌ای!

🔹 مفهوم: همه با شکل معمولی iter(iterable) آشنا هستیم. اما کمتر کسی می‌دونه که iter() یک فرم دو آرگومانه‌ای به شکل iter(callable, sentinel) داره!

🔹 کاربرد واقعی: خواندن فایل‌های حجیم یا Stream دیتابیس/شبکه تکه‌تکه (Chunk) تا زمانی که به یک مقدار خاص (Sentinel) برسی، بدون نیاز به نوشتن حلقه while True و شرط‌های اضافه!

# خواندن یک فایل خط‌به‌خط یا بلوکی تا رسیدن به خط خالی:
with open('data.txt', 'r') as f:
# حلقه تا زمانی ادامه پیدا می‌کنه که خروجی f.readline برابر '' (خط خالی) بشه
for line in iter(f.readline, ''):
process(line.strip())

🔹 به چه دردی میخوره؟

کد فوق‌العاده تمیز، پایتونیک و بدون نیاز به تعریف متغیرهای موقت درون حلقه میشه.

🐍 @python_rd
🔆 فایل pip.conf؛ امن کردن Pip جلوی حملات Supply Chain!

🔹 خیلی وقت‌ها توی پروژه‌ها پکیج‌های شخصی یا سازمانی نصب می‌کنیم. حمله‌ای به اسم Dependency Confusion وجود داره که اگر نام پکیج داخلی شما با یک پکیج عمومی روی PyPI یکی باشه، Pip ممکنه نسخه مخرب عمومی رو دانلود کنه!

🔹 راه حل: ایجاد یک فایل کانفیگ اختصاصی برای Pip تا اولویت دانلود رو فقط روی مخزن امن تنظیم کنه:

# مسیر فایل: ~/.config/pip/pip.conf
[global]
index-url = https://your-private-repo.com/simple
extra-index-url = https://pypi.org/simple
require-hashes = true

🔹 به چه دردی میخوره؟

با اضافه کردن require-hashes = true حتی اگر کسی پکیجی روی PyPI رو هک کنه و تغییر بده، تا زمانی که Hash اون تغییر نکرده باشه Pip اجازه نصب نمیده. این نکته برای کسانی که پروژه واقعی و تجاری می‌زنن عالیه.

🐍 @python_rd
🔆 تکنیک ناشناخته و حرفه‌ای functools.singledispatch (اورلود کردن توابع در پایتون بدون if/elseهای طولانی!)

​🔹 چطوری تو پایتون تابع Overloading تمیز بنویسیم؟

​خیلی وقت‌ها پیش میاد که میخوایم یه تابع بستگی به اینکه چه جنس ورودی‌ای (String, List, Dict...) بهش میدیم، رفتار متفاوتی داشته باشه. روش مبتدیانه چیه؟ نوشتن یه سلسله if isinstance(...) طولانی!

​اما روش سینیورها توی پایتون استفاده از singledispatch از کتابخونه استاندارد functools هست.

from functools import singledispatch

@singledispatch
def process_data(data):
raise NotImplementedError("این تایپ پشتیبانی نمیشه!")

@process_data.register(str)
def _(data):
return f"متن پردازش شد: {data.upper()}"

@process_data.register(list)
def _(data):
return f"لیست پردازش شد با طول: {len(data)}"

@process_data.register(dict)
def _(data):
return f"کلیدهای دیکشنری: {list(data.keys())}"

# تست تابع
print(process_data("hello")) # متن پردازش شد: HELLO
print(process_data([1, 2, 3])) # لیست پردازش شد با طول: 3

🔹به چه دردی میخوره؟

کد بسیار کپسوله، خلوت و خوانا میشه.
اصل Open/Closed رعایت میشه (میتونی بعداً بدون دست زدن به تابع اصلی، تایپ جدید اضافه کنی).

🐍 @python_rd
👍2
🔆 مجموعه‌ای از نکات و تقلب‌‌نامه‌هایی برای زبان برنامه‌نویسی پایتون

🔹https://gto76.github.io/python-cheatsheet

🐍 @python_rd
❤1
🔆 مدیریت منابع با contextlib

🔹 از تکرار 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
🔆 خروجی این تکه کد چیه؟

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) تولید می‌کنه:

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 می‌توانید این کار را خیلی سریع‌تر و پایتونیک‌تر انجام دهید.

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 / --disable-gil) در دسترس قرار گرفته است.

▪️ تیم‌های توسعه کتابخانه‌های بزرگ مانند NumPy و PyTorch در حال بازنویسی بخش‌های C-API خود برای سازگاری با حالت بدون GIL هستند.

▪️ طبق پیش‌بینی هسته مرکزی، پایتون در پردازش‌های سنگین موازی تا چند برابر افزایش کارایی را تجربه خواهد کرد.

🔹 منبع رسمی:

• مستندات رسمی PEP 703: peps.python.org/pep-0703
• اعلامیه Steering Council پایتون: discuss.python.org

🐍 @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
کوییز پایتون

🔆 خروجی اجرای کد زیر چیست؟

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