Python Hints
الذهاب إلى القناة على Telegram
Python tips and tricks The Good, Bad and the Ugly توی این کانال فقط قرار هست در مورد core python صحبت کنیم. این کانال یک بلاگ شخصی هست و پیرامون نظرات و چیزهایی که توی بیش از ۱۰ سال کد زدن یاد گرفتم (فقط برای کمک به دوستان تازهکار) Admin: @Abbasi_ai
إظهار المزيد9 607
المشتركون
-524 ساعات
+587 أيام
+21130 أيام
أرشيف المشاركات
9 612
تا داریم از
functools صحبت میکنیم بیاید و اجازه بدید راجب total_ordering هم صحبت کنیم :
کارش اینه من یک کلاس کاستوم میسازم و میخوام بین آبجکت های کلاسم مقایسه رو پشتیبانی کنم
اما ازونجایی که حال ندارم همهی موارد مقایسه رو بنویسم :
__lt__, __le__, __gt__, __ge__, ....میام یکی ازین موارد رو پیاده سازی میکنم و در کنارش هم
__eq__ رو پیاده سازی میکنم.
توصیه مهمی هست که حتما __eq__ پیادهسازی بشه وگرنه باگ مخفی میخورید
باقی عملگرها به لطف
@total_ordering
بصورت خودکار برای کلاس مدنظرم پیاده سازی میشه
@PyHints9 612
بحث راجب
functools, partial کامل نمیشه مگر با صحبت راجب
singledispatch
ی decorator خیلی عالی و قوی بجای if-else های تو در تو برای چک کردن type داده
هدف اصلی :
Clean code
فقط نکته مهم این هست که singledispatch با آرگومان اول ورودی تابع کار میکنه فقط
پ.ن : توی مثال بالا مثلا اگر خواستید ی تابع برای
int, floatاضافه کنید که هر ۲ رو پشتیبانی کنه در این حالت نیاز دارید از
Union و Typing هم استفاده کنید:
from typing import Union
@PyHints9 612
این یکی ساده هست ولی خیلی مهم :
from functools import partial
اگر قرار هست تابعی از فریمورک مورد نظرتون رو همیشه با چندتا
argument
ثابت صدا بزنید حتما از partial استفاده کنید.
هم تمیزتر هست هم کد رو خواناتر میکنه
Don't Repeat Yourselfهم که رعایت میشه اگر قرار باشه اون تابع رو بسیار استفاده کنید؛ دیگه لازم نیست آرگومانهای ثابت رو هی براش ارسال کنید @PyHints
9 612
9 612
همونطوری که احتمالا حدس زدید؛ خروجی خط ۲۱ :
@PyHints
هست.
اما توضیحاتش مهمتر از اینه که بگید خروجی چی هست :
توی پایتون یک موضوعی داریم به اسم
variable shadowing
اتفاقی که میوفته اینه که توی کد بالا به این موضوعی احترامی گذاشته نمیشه اگر name توی کد بالا یک property نبود قطعا متنی که توی خط ۱۹ بهش داده بودیم رو چاپ میکرد؛
حالا چرا property باعث شده که به variable shadowing احترام گذاشته نشه
توی پایتون یک موضوع دیگری هم وجود داره به اسم
Descriptor
که خودش ۲ مدل داره و توی کد بالا ما از data descriptor داریم استفاده میکنیم وقتی شما از property استفاده میکنید چه به صورت تابع چه بصورت decorator اون property در نهایت به صورت data descriptor تعریف میشه
پروتوکل data descriptor به این صورت تعریف میشه:
کلاسی در پایتون که شامل dunder method های :
__get__ and __set__ or __delete__
باشه که توی property هر ۳ مورد وجود داره
پایتون هم که باشعور وقتی متوجه میشه از پروتوکل data descriptor استفاده شده دیگه از __dict__ موجود برای instance اطلاعات نمیگیره بلکه
__get__
اون data descriptor رو صدا میزنه به همین دلیل هم خروجی کد بالا
@PyHints
هست.9 612
بنظر شما توی این کد خروجی خط ۲۱ چی هست ؟
آیا میتونید راجب این رفتار توضیح هم بدید ؟
بحثی داشتم با یکی از دوستان راجب این مطلب که یاد مصاحبه مرحله دوم برای آمازون افتادم موضوع مربوط میشه به ۳-۴ سال پیش.
سطح
upper mid-level, senior python
9 612
اول از بزرگترین عیب استفاده از
__slots__
بگم؛ و اونم از دست رفتن
monkey patching
هست؛ خط ۲۱ کد رو نگاه کنید توی حالت معمول اگر یک instance از کلاسی بدون
__slots__
داشتیم هیچوقت به ارور نمیخورد و education تبدیل میشد به یک
instance attribute
و روی p مینشست.
همین رفتار اولین کاری که __slots__ میکنه رو لو میده حذف __dict__ از کلاس علاوه بر اون __weakref__ رو هم بیخیال میشه
پس مزیتهاش بدست میاد :
۱- سرعت بالاتری داره (توی پایتون ۳.۵ تا ۳۰٪ سریعتر میکرد دسترسی به attribute هارو)
۲- حافظه خیلی کمتری استفاده میکنه
چون شما دقیقا بهش میگید چه attribute هایی دارید و دیگه dynamic نیستید؛ سربار دیکشنری توی پایتون بسیار زیاد هست.
حالا کجاها استفاده میشه ؟
چندتا مورد من بیشتر از همه دیدم :
مواقعی که از کلاسی که نوشتید ممکنه هزاران یا بیشتر instance ساخته بشه و نیازی هم به monkey patch ندارید (بازیهای آنلاین - اکانتهای آنلاین و ...)
حالت دوم :
ABC class
اما اگر توی این ۲ حالت نیستید و محدودیت حافظه براتون پیش نمیاد نباید رفت سراغش9 612
__slots__
ازون مواردی هست که ممکنه ۲۰ سال توسعه دهنده پایتون باشید و هیچوقت استفاده نکنید ولی اگر توی شرایط درست و بجا استفاده کنید
قطعا از کابوس نجاتتون میده
توضیحات پست بعدی
@PyHints9 612
اما بحث اصلاً راجب
@lru_cache, ...
نبود و از فرصت استفاده کردم و توضیح دادم.
اما مسئله بحث چی بود، استفاده از cache فقط برای مصاحبه نیست
crawler
موقعیت خیلی مناسبی هست، دوستان زیادی در جریان برخی از کرالرهای نوشته شده بنده هستند بخصوص مواردی که نیاز به محاسبات پردازشی و درخواست به لینکهای تو در تو داره
درصد زیادی که کرالرهای بنده بلاک نمیشه یا توی معروفترین موارد تا بیش از ۱۰۰ گیگ دیتای سایتهای داخلی رو کرال کردم
استفاده از cache هست، یا حتی بهتر استفاده از ابزارهای دیگه که url های کرال شده دوباره براشون درخواست فرستاده نشه.
نکته دیگه راجب
@lru_cache
که فراموش کردم بگم اگر argument های تابع رو جابجا بفرستید، دوباره محاسبات رو انجام میده پس به این نکته توجه کنید ینی :
add(a=1, b=2)
و
add(b=2, a=1)
۲ بار محاسبه میشه9 612
در ابتدا
@lru_cache
توی سورس کد از dict استفاده میکنه پس ازین نظر فرقی با
cache = {}
نداره اما چرا پس
@lru_cache
تعریف شده ؟
maxsize
بهترین دلیلش هست اگر تعریف بشه Ram با نتایج کش شده پر نمیشه
فرض کنید خروجی محاسبات چندین گیگابایت باشه، اگر محدودیت نداشته باشه مثل
cache = {}
رم رو پر میکنه و کد رو از کار میندازه، ولی این اتفاق توی lru_cache نمیافته9 612
قبلا راجب cache نوشتن برای پروژههایی با محاسبات سنگین صحبت کردم
البته توی یک کانال دیگه :
https://t.me/pytens/1018
دوستانی که کد تصویر رو متوجه نشدند شاید بهتره اون پیامهارو هم بخونند.
اینجا میخوام راجب دلیلی صحبت کنم که شما توی مصاحبه midlevel قبول میشی اما در طول یا بعد از قرارداد ۳ ماهه ارزیابی یا باهات خداحافظی میشه یا اینکه بهتون پیشنهاد دستمزد و کار junior داده میشه
(البته فقط بحث فنی)
@PyHints
9 612
یکی دیگه از مزایای استفاده از
type(self).__name__
موقع fall-back و inheritance هست با وجود اینکه کلاس
Student
متد __repr__ براش پیاده سازی نشده (لازمم نداره اینجا) اما میتونه از آنچه که برای
Person
پیاده سازی شده استفاده کنه و به درستی هم نمایش بده
بازم اشاره میکنم که لاین ۸ از ... استفاده شده که اینجا کار همون pass رو انجام میده.
@PyHints9 612
چطوری میشه یک شرکت، استارتاپ یا ... رو نابود کرد !؟
موضوع بر میگرده به ۳ سال پیش، یک شرکت (داخلی) برای همکاری به تیم ما پیشنهاد داد و یک مبلغی اعلام شد بعد از چندروز البته اعلام کرد که دستمزد ما ۲ برابر یک شرکت دیگه بوده و به همین دلیل با اون شرکت همکاری میکنند (نه تیم ما، یک دلیل هم همین بود که اونها شرکت ثبت شده هستند و ما یک تیم)
بگذریم، زمانبندی پروژه ۶ ماه عقب افتاد و بعد بالاخره پروژه لانچ شد (اینهارو میدونم چون یکی از دوستانم توی شرکت co-founder بود)
دقیقاً وقتی شرکت به اوج درآمد خودش رسیده بود و قرار بود این پروژه درآمد رو حداقل ۳ برابر کنه پروژه لانچ شد، اما ۱ سال بعد نه تنها درآمد ۳ برابر نشده بود بلکه بدهی پروژه مبلغی حدوداً ۱ میلیاردی بود (برای یک استارتاپ مبلغ خیلی زیادی بود) ۱ سال پول و وقت و ... چندین سال توسعه پروژه در نهایت ۱ میلیارد کسری بودجه با وجود فروش چند ده میلیاردی ؟ چطور ممکن هست ؟
۱- وقتی کار رو میدید دست نیرویی که با پول واقعی پروژه نزده اینطوری میشه.
۲- وقتی کار رو به تیمی میدید که زبان برنامهنویسی رو بخوبی نمیشناسه اینطوری میشه.
۳- وقتی نیرو کار رو از روی چندتا دوره آموزشی یاد میگیره اینطوری میشه.
اینها اولین صحبت من با دوستم قبل از code review بود چون بعد از توضیح منطق بیزینس ۹۹٪ میدونستم مشکل چی هست :
حالا مشکل چی بود:
یک اصطلاحی داریم به اسم
Banker's Rounding
مشکلی هست که با رند کردن اعداد به وجود میاد، اگر درست انجام بشه میانگین رند کردن سود هست برای صاحب بیزینس و اگر اشتباه باشه کاملاً ضرر مالی میشه
یک بخشی از قضیه این موضوع بود و بخش دوم که من توی ۹۰٪
Code Review
هایی که برای استارتاپها انجام میدم میبینم استفاده از نوع داده
Float
هست، اگر قرار به تمرین باشه این نوع داده خیلی هم خوبه ولی وقتی پای پول واقعی وسط هست اگر نمیخواهید کسی رو بدبخت کنید از
Decimal
استفاده کنید.
Decimal
هر ۲ مشکل شمارو حل میکنه، بخصوص مشکل False بودن عبارت زیر :
0.3 == 0.1 + 0.1 + 0.1
برای نسل جدید : هیچکس با یک دوره آموزشی برنامهنویس نمیشه، زیاد به دورهها تکیه نکنید.
@PyHints9 612
جواب سوال :
classScope says hello
['classScope', 'classScope', 'classScope']
['@pyHints', '@pyHints', '@pyHints']
چیزی که به نظر بعضی افراد عجیب هست رفتار متفاوت
list_1, list_2
هست؛ همینجا توضیح بدم که توابع - متدها (انواع متدها منظورم هست چه
class bounded
چه
instance bounded
و حتی
static method
) همگی Scope رو از parent میگیرند توی این کد میشه global :
سوال ممکنه پیش بیاد: پس متد hello چرا داره classScope رو چاپ میکنه ؟
دلیلش واضح هست چون class bound method هست و خود کلاس رو بعنوان پارارمتر اول میگیره و اتفاقا چون scope خودش گلوبال هست برای دسترسی به classScope باید از cls.name استفاده کنیم.
اما مورد دوم و سوم ؛
list_1
که توی قانون بالا نیست پس scope اش مربوط به خود کلاس هست در نتیجه classScope رو چاپ میکنه
اما چالش سر
list_2
هست؛ دلیل اینکه
@pyHints
رو چاپ میکنه اینه که یک list comprehension هست و list comp چیزی نیست جز یک تابع؛ برای همین اونهایی که فکر میکنند این رفتار عجیب یا اشتباه هست مشخصا نحوه عملکرد و جزئیات پایتون رو نمیشناسند.
@pyHints9 612
بنظرتون خروجی print چی هست ؟ چرایی قضیه رو هم توضیح بدید ؟
اینم یک سوال مصاحبه هست؛ بخاطر اینکه به نظر گروهی از افراد خروجی عجیب یا اشتباه هست که خب نیست و طبق منطق scope بندی کلاسها توی پایتون کاملا رفتار درست هست.
پ.ن : اینکه میگم سوال مصاحبه منظورم این نیست که دقیقا همین رو و همینقدر ساده میپرسند اما نکتهی مهم سوال این بخش بوده که من بیرون کشیدم و bold کردم تا توی یک پست بشه کامل بهش پرداخت.
@PyHints
9 612
توی این پست کلی سوال درمورد
!r
شده، این مورد جایگزین تابع repr میشه :
ینی بجای :
f"{self.name!r}"
از
repr(self.name)
استفاده کنید که خب من اصلاً ترجیح نمیدم؛ بعضی دوستان میگن حالت دوم خوانایی بیشتری داره و ... پس باید ازین استفاده بشه
که مخالفم با این صحبت، اگر یک فیچری توی زبان برنامهنویسی هست که کار رو راحت میکنه پس باید ازش استفاده کرد این وظیفه باقی دولوپرها هست که خودشون رو آپدیت کنند.
مثل این میمونه که بگید از
Match-case
استفاده نکنیم چون خیلیها بلد نیستند همون
if-else
تو در تو بهتره
بگذریم، بصورت خلاصه این نمادها و توابع مهم هست :
!r : repr()
!s : str()
!a : ascii()
@PyHints9 612
میدونید که ساعتها از امسال تغییری نمیکنه
اما ازونجایی که بصورت بینالمللی ثبت نشده درخواست ایران، همهی سرویس دهندهها، کتابخونهها و ابزارهای هوشمند ساعتها رو مثل قبل ۱ ساعت جلو بردند.
اپلیکیشنها و ساعت سرورهاتون رو مراقب باشید.
(البته ممکنه توی چندروز آینده این اتفاق بیوفته و ساعتها درست بشه ولی خب همین الان هم لاگها بهم ریخته)
@PyHints
9 612
یک نکته که شاید لازم باشه بهش اشاره کنم در این تصویر (مخصوصا برای دوستان تازهکار)
استفاده از
...
هست (اصطلاحا بهش Ellipsis گفته میشه توی پایتون اگر خواستید بیشتر بخونید)
یکی از کاربردهاش زمانی هست که ی بخش از کد رو هنوز پیاده سازی نکردید.
توی این کاربرد مثل pass میمونه
@PyHints9 612
__mro__
یکی ازون موارد جذاب هست؛ پیادهسازی و الگوریتم جالبی هم داره
برای دیباگ هم خیلی خیلی کمک کننده هست (مخصوصا وقتی دیباگر در درسترس نیست) که مخفف :
Method Resolution Order
معمولا توی ۹۰٪ پروژهها نیازی بهش ندارید اما توی مصاحبههای فنی ممکن هست بهش برخورد کنید مخصوصا اگر شرکت تولید کننده ابزار برای برنامهنویسها هست (مثلا تیم Microsoft Vscode )
همونجوری که توی خروجی یا حتی از اسم متد پیداس اولویت اجرای متد رو بهتون نشون میده؛ و یک اثبات دیگه ازین موضوع هست که همه چیز توی پایتون Object هست.
@PyHints
متاح الآن! بحث تيليغرام 2025 — أهم رؤى العام 
