Python Hints
رفتن به کانال در Telegram
Python tips and tricks The Good, Bad and the Ugly توی این کانال فقط قرار هست در مورد core python صحبت کنیم. این کانال یک بلاگ شخصی هست و پیرامون نظرات و چیزهایی که توی بیش از ۱۰ سال کد زدن یاد گرفتم (فقط برای کمک به دوستان تازهکار) Admin: @Abbasi_ai
نمایش بیشتر9 613
مشترکین
+924 ساعت
+647 روز
+22130 روز
آرشیو پست ها
9 604
خواستم یکبار دیگه تأکید کنم روی
EAFP ( easier to ask forgiveness than permission )
که هم به خودم یادآوری کرده باشم هم باقی دوستان،
اصولاً توی دنیای واقعی هم همین هست مثال میزنم که جا بیوفته (چون متاسفانه خیلی کم رعایت میشه)
کودکی رو به خاطر بیارید، یک کاری میخواستی بکنی که با شک بالا میدونستی پدر و مادر اجازه نمیدهند.
وقتی میرفتی و اجازه میگرفتی، درجا نه میشنیدی حالا باید تمام جزئیات و ... رو توضیح میدادی تا همهی نگرانیها برطرف بشه
بعد شاید حتی ۱ همراه یا ... هم باهات میفرستادند و در اینصورت شما اجازه داشتی کاری که میخوای رو انجام بدی.
مثال میزنم :
یک تفریح سالمی که ما (از درس فیزیک و شیمی) داشتیم این بود که ۲ تا آجر میذاشتیم نزدیک هم ی تشتک نوشابه (باید پلاستیک کفش رو میکندیم، قدیما داشت، جدیدا نداره) میذاشتیم روی آجرها و یک تیکه شمع رو میریختیم داخلش (نقش روغن) بعد یک شمع دیگه زیر این تشتک روشن میکردیم صبر میکردیم شمع داخل تشتک به نقطه جوش برسه (یا حتی ی کم آتیش بگیره) بعد ی قطره آب داخلش مینداختیم و شعله چندبرابر میشد.
درس ایمنی : اگر ماهیتابه روغن روی گاز آتیش گرفت آب توش نریزید، فقط درش رو بذارید و شعله زیرش رو خاموش کنید 😁
۹۰٪ بچهها اجازه انجام اینکار رو نداشتند، من اولین بار بدون اجازه رفتم اینکارو کردم جلو در خونه خودمون وقتی پدرم دید گفت نباید اینکارو میکردی و ...
منم عذرخواهی کردم و توضیح دادم که شعله کوچیک هست (صورتمم عقب گرفتم که ابرو و موژهام نسوزه) و نمیدونستم که باید براش اجازه بگیرم، بعد چندبار به خودش نشون دادم، درنهایت گفت پس مراقب باش اشکالی نداره (بزرگ شدی دیگه)
اما قبل از اینکه پدرم من رو ببینه، بیش از ۵۰ بار اون کار رو گرده بودم.
EAFP
هم همین هست، وقتی نسبت بروز Exception خیلی کم هست چرا هر دفعه میخوای چک کنی که اجازه انجام اون محاسبه رو داری یا نه ؟!
این همه گفتم، که خواهش کنم این مورد رو توی کدهاتون بیشتر رعایت کنید.9 604
خواستم یادآوری کنم
Neuralink
امسال (2024) شروع تست روی انسان رو انجام میده و با توجه به نتایجی که روی حیوانات داشته مجوز برای تست روی چند انسان رو گرفته، طبق گزارش قبلی قرار بود ۱۱ نفر باشه، با توجه به حدود قیمت و اینکه تستش تا ۳ سال آینده هر سال روی آدمهای بیشتری خواهد بود و البته اینکه سرعت و هزینه هم هر سال به ترتیب بیشتر و کمتر خواهد شد.
من رو دقیقاً یاد فیلم Upgrade انداخت
9 604
حالا بازی ما قراره بره پروداکشن و ویژگی
shuffle رو نداره ۳ تا راهکار :
۱- ایمیل بزنیم؛ که به این دلایل __setitem__ باید اضافه بشه یا اینکه merge request بزنیم و ... که میره برای ورژنهای بعدی
۲- خودمون سورس کد رو تغییر بدیم؛ ی داکیومنت بنویسیم برای تیم DevOps و بگیم بعد از نصب پیکج باید این چیزا رو توی سورس کد کتابخونه تغییر بدی و ... که خیلی کار کثیفی هست و کل پروسه اتوماسیون رو میبره زیر سوال چون ممکنه جای دیگه از همین تیم و شرکت با فرض اینکه __setitem__ وجود نداره یک بازی دیگه درحال توسعه باشه
۳- از تکنیک monkey patch استفاده کنیم.
توی این تصویر خط ۵ تا ۱۰ اینکارو میکنه ی تابع تعریف میکنم توی کد بازی حکم خودم و بهش میگم روی
__setitem__
که برای کلاس
CardDeck
پیادهسازی نشده بود رو تعریف کن و متدش رو برابر با تابع set_card درنظر بگیر.
نه نیازی به Merge Request دارم؛ نه DevOps و تیم های دیگه رو کارشون رو خراب کردم
Inheritance , ....رو هم خودم رو درگیرش نکردم و چون موقتی و سریع هم هست اگر توی ورژنهای بعدی
__setitem__
اضافه بشه حذف این ۵ خط کد هیچ تاثیری روی کدهای پروژه و بازی نخواد داشت.9 604
Monkey Patchingبرای این مورد ترجیح میدم از مثال خود کتاب استفاده کنم؛ قطعا ۹۰٪ شما میدونید مانکی پچ چیکار میکنه و ساده هم هست برای همین نمیخوام عملکردش رو توضیح بدم اما جایگاه استفادهاش رو میخوام صحبت کنم (بسیار دیدم که اشتباه استفاده میشه) لازم نیست اهل ورق بازی باشی تا بدونی که جذابیت بازی ورق (حکم بخصوص) به این هست که دست بر بخوره پس کلاس
CardDeck کامل نیست مگر اینکه shuffle رو داشته باشه.
ازونجایی که این کلاس Sequence Protocol رو رعایت کرده طبق آنچه که صحبت شد؛ از Internal ها استفاده میکنیم یعنی random.shuffle.
اما random.shuffle میگه من به یک MutableSequence نیاز دارم؛ ی مقدار دقت کنیم روی مثال قبلی MutableSequence چه متدهایی رو میخواست ؟
__len__, __getitem__, __setitem__, __delitem__با توجه به ارور من
goose typing ندارم و shuffle هم به __delitem__ نیازی نداره و فرض رو هم بر این میگیریم که کلاس CardDeck از یک کتابخونه میاد ( بیاید فرض کنیم کتابخونه بزرگی هست و نمیتونیم بازنویسیش کنیم ) که برنامه نویسش __setitem__ رو اضافه نکرده.9 604
تا اینجا میدونیم که وقتی صحبت از
runtime check میشه گزینه اصلی Goose Typing هست اما ی مشکلی اینجا داره اگر من از goose typing استفاده کنم باید از MutableSequence هم Inherit کنم و همهی کلاسهایی که ازین مورد میخوان استفاده کنند حتما باید
__delitem__رو هم پیادهسازی کنند. اگر اینترفیس شما ترکیبی از چند
abc باشه چی ؟
اون موقع شاید مجبور باشید برای اینکار بیش از ۱۰ متد رو پیادهسازی کنید وقتی فقط ۵-۶ متد رو لازم داشتید.
راهکار
Static Protocol +
runtime_checkable
به کد تصویر دقت کنید؛ اول اینکه هر کلاسی از
typing.Protocolاستفاده کنه میشه
Static Protocolو اینطوری
type checker ها میتونند بررسی کنند.(توی سورس کدهای مختلف هم نگاه کنید فقط تا همین بخش استفاده میشه و کسی سراغ runtime_checkable نمیره معمولا اما بعنوان یک برنامهنویس پایتون شما باید همه ابزارها رو بشناسید)
برگردیم سراغ مثال خودمون الان که من میخوام فقط همون ۳ متد رو داشته باشه میام یک کلاس بدون پیادهسازی میسازم به اسم
SupportMutSeq
و به راحتی با isinstance میتونم بررسی کنم که کلاسهای دیگه از این Interface پیروی میکنند یا خیر بدون اینکه هیچ برنامه نویسی یا حتی خودم رو مجبور کنم که __delitem__ پیادهسازی بشه.
مثال سمت چپ هم از خود داکیومنت پایتون آوردم. چون سادهتر بود ( بخصوص Closable )9 604
قبل از اینکه بریم سراغ تصویر :
یک مفهومی داریم توی پایتون به اسم
Static Duck Typing
حدس زدید دیگه تا الان ترکیبی هست از
Static typing, duck typing
استفادهاش؛ اجازه میده Interface رو طوری تعریف کنیم که کلاسهای مختلفی رو بشه بجاش استفاده کرد.
اما تصویر بالا؛ فرض کنید شما میخواید یک Interface بسازید و مهمتر از اون میخواید
runtime type checkingرو هم داشته باشه اما
Interface شما سختگیری ABC های موجود رو لازم نداره (میدونیم که تعریف abc هم کار درستی نیست توی ۹۹٪ موارد).
مثال بزنم شاید بهتر درک بشه :
collections.abc.MutableSequence
رو در نظر بگیرید؛ و فرض کنید Interface من که قرار هست runtime checking هم داشته باشه نیاز به ۳ تا متد داره :
__len__, __getitem__, __setitem__
میخوام مطمئن بشم هرکسی هر موردی رو بهم تحویل میده بعنوان Instance ایی از Interface باید حتما هر ۳ تا این متدها رو پیادهسازی کرده باشه Hard Rule هست برای عملکرد درست کدهام برخلاف Duck typing که soft rule هست و دیدیم که میگه اگر نیازی به این متد نداری پس پیادهسازی نشدنش هم مشکلی نداره.
ادامه پست بعدی9 604
اول با تصویر ۲ شروع کنیم (بالای کد 2 کامنت شده)
از دیگر مزایای
Goose typing همین مورد هست وقتی برای اطمینان از Interface میاید و کلاسهای فریمورکی که مینویسید رو به ABC ها وصل میکنید (منظورم Inheritance هست).
دقت کنید اگر من __len__ رو پیادهسازی نکنم بهم ارور میده؛ به عمد ارور رو گذاشتم که باهاش آشنا بشید.
برای رفع این مشکل پایتون و Goose Typing و البته ABC من رو مجبور میکنند که __len__ رو پیادهسازی کنم.
پس برای همین runtime type checking هم داریم توی پایتون اما مفهومش با زبانهای دیگه کمی فرق داره که حالا همگی دلیلش رو میدونیم.9 604
Goose Typingرو بعنوان
runtime type check بهش اشاره میکنند؛ دلیلش هم توی عکس واضح هست.
اما دقت کنید که من برای isinstance از
from collection.abc import Sequence
چرا این مورد وجود داره؛ برطرف کردن مشکلاتی که Duck typing بوجود میاره همونطور که دیدیم برای duck typing تکمیل بودن تمام متدها اهمیتی نداره.
همینجا یک نکتهای رو بگم؛ توی پایتون استفاده بیش از اندازه از isinstance , issubclass, hasattr اصلا چیز خوبی نیست و به قول معروف code smell هست (برای دلیلش میتونید راجب __subclasshook__ بخونید.)
با این همه؛ goose typing جایگاهی مطمئنتر از duck typing برای تست پیادهسازی کامل یک Interface بهمون میده و همیشه هم باید به یک ABC برسه (پیادهسازی درست و اصولی)9 604
Dynamic Protocolهم از همین مفهموم استفاده میکنه؛ اگر یادتون باشه قبلا راجب پروتوکل مربوط به Sequence صحبت کردیم و گفتیم که اگر یک
class متدهای
__len__, __getitem__
رو داشته باشه میتونیم بعنوان Sequence Protocol رو رعایت میکنه و پایتون میتونه مثل Sequence باهاش رفتار کنه و برخی از فانکشنالیتیهایی که پیاده سازی هم نکردیم رو بهش بده.
Dynamic Protocolی قدم جلوتر میره و میگه اگر قرار نیست
len اون آبجکت رو بگیری پس نیازی نیست توی اون کلاس حتی __len__ رو پیاده سازی کنی و صرف وجود __getitem__ من بهت یک سری ویژگیهای Sequence رو میدم؛ ویژگیهایی که فقط به __getitem__ نیاز داره و نه چیز دیگه.
توی مثال تصویر قبل؛ من هیچوقت __iter__ رو پیادهسازی نکردم اما میتونم روی dp از for loop استفاده کنم؛ به لطف
Duck typing, Dynamic Protocol
پایتون از __getitem__ استفاده میکنه و با شروع از اندیس 0 میتونه کار __iter__ رو انجام بده و for loop بهمون خروجی خواهد داد.
برای in هم موضوع همین هست؛ توی کد قبلی من هیچوقت __contain__ رو پیادهسازی نکردم اما
9 in dp
خروجی میده (اینبار هم پایتون از __getitem__ بعنوان fallback برای __contain__ استفاده میکنه)
بحثی که پیش میاد اینه که؛ آیا این موضوع اتفاق خوبی هست ؟
نه همیشه؛ خیلی وقتها میشه نسخه optimize شده تری رو نوشت مثلاْ توی کد قبلی اگر من لیست رو بصورت sort قرار باشه داشته باشم همیشه میتونم بجای __contain__ که خود پایتون بهم میده و linear search هست که مرتبه زمانی O(n) داره از Binary Search استفاده کنم و مرتبه زمانی رو تا O(log n) کاهش بدم.
اما تا وقتی نیازی به بهبود ندارم؛ هیچوقت __contain__ یا ... رو خودم پیادهسازی نمیکنم و از آنچه که پایتون بهم ارائه میده استفاده میکنم (اینطوری نه نیاز به تست هست؛ نه باگ ازش در میاد و کد تمیزتری هم خواهم داشت)9 604
Duck typing, Dynamic Protocol
رو میشه با هم نشون داد؛ ی جمله معروف داره که همه بلد هستند اما خیلی ها مفهومش رو نمیدونند
Duck typing :If it looks like a duck and quacks like a duck, it’s a duck.
چیزی که این جمله سعی داره بگه اینه که؛
برای ما مهم نیست object کدوم کلاس هستی اگر این متدها و فانکشنالیتی ها رو داری عضوی از ما هستی.
ما برنامه نویسها همیشه Duck type mode هستیم بصورت پیشفرض؛ برای ما فرقی نمیکنه طرف رشته کامپیوتر خونده یا حقوق و حسابداری و ... یا اصلا درس نخونده
برای ما مهم هست که طرف توانایی کد زدن داشته باشه و اگر بتونه این کار رو به خوبی انجام بده بهش لقب برنامه نویس میدیم.
پس توی Duck typing اولویت متدها هستند و نه خروجی isinstance9 604
خوانش گروهی کتاب
Fluent Python
به فصل ۱۳ رسید (عضو جدید نمیگیره گروه)
Interfaces, Protocol and ABCs
داشتم راجب همین موضوع پیش گروهی دیگر از دوستان صحبت میکردم که متوجه شدم خیلی از بچهها با این مفاهیم آشنا هستند، اما کاربرد درستش رو نمیدونند حتی بچههایی که پایتون رو تا سطح بالایی دنبال کردند.
برای همین تصمیم گرفتم توی پستهای بعدی این مفاهیم رو با مثال توضیح بدم، منظورم از این مفاهیم :
Interface, Duck typing, Goose typing, Static typing, Static Duck typing, ABC, Protocol, polymorphic interface, ....
هست.9 604
قابلیت
Boost
مثل اینکه محدودیت زمانی داره + هرچه تعداد اکانتهای پریمیوم بالاتر بره تعداد
Boost
مورد نیاز برای هر لول هم بیشتر میشه
درحال حاضر امکان گذاشتن استوری (معرفی کتاب) از کانال گرفته شده.
9 604
آقا من نمیدونم این به گوش بچههای طراح سایت اینترنت مخابرات میرسه یا نه
یا مثلاً مدیر فنی و ... (قبلاً این اتفاق افتاده چون)
ولی دوست دارم شما همگی بدونید؛
مودم من به یک مشکلی خورده بود و بنا به دلایلی رفتم پسورد اینترنت رو تغییر دادم، برای امنیت بیشتر کاراکتر ' رو داخل پسورد گذاشتم، اتفاقی که افتاد این بود
فرض کنید پسوردی که من زدم این بود :
P
yhints2023'24
سایت مخابرات چی توی دیتابیس برای مچ کردن گذاشته بنظرتون ؟! 🤣😂
اول اینکه hash، نشده و اصل پسورد رو برام فرستادند اما چی بنظرتون بود پسورد :
\"pyhints2023\'24\"
یعنی : پسورد رو نرمالایز کردن حروف بزرگ رو کردن کوچیک بعد ' رو escape کرده توی دیتابیس گذاشتن و چون ' توی پسورد داشتم از " اطرافش استفاده کردند و همونجوری توی دیتابیس گذاشتن
شما ببین سایتای ایرانی رو کیا کد میزنند. 😂🤣😂9 604
به لطف شما عزیزان, کانال قابلیت استوری گذاشتن داره
و سعی میکنم ازین قابلیت برای معرفی کتابها استفاده کنم
تا دوستان به راحتی بتونند کتابها رو پیدا کنند.
همونطور که قبلاً گفتم، فقط و فقط کتابهایی رو معرفی میکنم که شخصاً خوندم و بنظرم مفید بوده.
اما، قابلیت استوری و ... بستگی به
Boost کانال داره که محدودیت زمانی هم داره این ویژگی (تلگرامم باید پول دربیاره دیگه) اگر دوست داشتید میتونید کانال رو boost کنید تا این حرکت رو ادامه بدم.
https://t.me/pyHints?boost9 604
Reaction
روی پستها لطفاً فراموش نشه، کمک میکنه بدونم کدوم مطالب رو دیگه نیازی نیست راجبش توضیح بدم و ....
9 604
دوستان به موارد زیادی اشاره کردند اما گفتم یکبار هم خودم همهی آن چیزی که توی کد ریویو انجام میدم رو بگم :
۱- وقتی کلاس یا تابع تعریف میکنید که خودش یا اجزا تشکیل دهندهاش مشخص نیست حتما باید داکیومنت یا کامنت داشته باشه
v0, v1, v2 , ...
بدترین اسامی هست که میشه انتخاب کرد؛ چون برنامه نویس داره فرض میکنه که همهی افرادی که کد رو میخونند بیزینس رو بخوبی میشناسند.
۲- استفاده از typing optional در اینجا درست نیست مخصوصا که برای همهی موارد تکرار شده و به همهی موارد دیفالت None داده شده؛ حتی اگر همین کد رو بخوایم نگه داریم این راهکارها بهتر خواهد بود :
v0: str | None
v0: typing.Union[str, None]
۳- از dataclass هیچ استفادهای نشده (frozen, ordering, slot , ....) حتی از ویژگیهای حالت سادهترش هم استفاده نشده؛ مثل پیاده سازی __methods__ که یعنی __repr__ و __str__ نیازی نبود نوشته بشه.
۴- حالا که نوشته شده
__repr__
در انتهای خروجی به str(self) رو داره و این یعنی برنامه نویس سواد نوشتن __repr__ درست رو نداشته و چون توی حلقه بینهایت میوفته مجبور شده که __str__ رو هم پیادهسازی کنه
۵- داخل __repr__ همه چیز پر از ایراد هست (تمام موارد رو قبلا بررسی کردیم تو کانال) :
عدم استفاده از qualname , هاردکد کردن اسم کلاس
عدم استفاده از r! جهت نمایش درست تایپهای داخلی
فرمت اشتباه؛ خروجی __repr__ رو برای ساخت مجدد آبجکت از کلاس نمیشه استفاده کرد.
۶- خورد __str__ کلا سوال هست؛ نوشتاری که تمیز نیست؛ هدفش مشخص نیست و ....
من حتی به این حالت هم فکر کردم که چون تعداد متغییرها زیاد بوده برنامهنویس خواسته از یک جایی به بعد ... نشون بده مثل کاری که numpy , .... میکنند؛ که اگر هدف هم این بوده پیاده سازی اشتباهی انجام داده و با یک جستجوی ساده حتی میتونسته به راهکار درست برسه
reprlib builtin module
تقریبا ۲۰ خط کد بود و ۳۰ خط ایراد.9 604
من راجب
repr, str , ... صحبت کردم.
این کد رو یکی از اعضا فرستاده (درحال code review این کد رو دیده)
@dataclass
class CasbinRuleEntity:
id: typing.Optional[int] = None
ptype: typing.Optional[str] = None
v0: typing.Optional[str] = None
v1: typing.Optional[str] = None
v2: typing.Optional[str] = None
v3: typing.Optional[str] = None
v4: typing.Optional[str] = None
v5: typing.Optional[str] = None
def __str__(self):
arr = [self.ptype]
for v in (self.v0, self.v1, self.v2, self.v3, self.v4, self.v5):
if v is None:
break
arr.append(v)
return ', '.join(arr)
def __repr__(self):
return '<CasbinRule {}: "{}">'.format(self.id, str(self))
ی مورد رو من بگم و بعد سکوت کنم :
یکی از دلایلی که
@dataclass
رو استفاده میکنیم این هست که دیگه repr بدرد نخور ننویسیم.
باقی مشکلات رو شما بگید (به اکثر موارد قبلاً اشاره شده توی کانال)
اکنون در دسترس! پژوهش تلگرام ۲۰۲۵ — مهمترین بینشهای سال 
