Generators
درود. میخواستم درباره ی آبجکت معروف و شناخته شده ی generator حرف بزنیم ولی با نگاه کمی متفاوت تر و به این برسیم که دقیقا چطور کار میکنه و چطور پیداش شد. نیاز هست که کمی حرف های پیش نیاز بزنیم صبور باشید.
قبل از هر چیزی درباره ی خود فانکشن حرف بزنیم ولی نه تو پایتون بلکه تو C:
وقتی یه فانکشنی کال میشه، توی call stack یک frame جدید میاد که برای اون فانکشن هست. این frame شامل تمام متغیر های لوکال و پارامتر های اون فانکشن هست. وقتی فانکشن تموم میشه چه اتفاقی میفته؟
اون frame از stack پاپ میشه(یا دقیق ترش stack pointer کم میشه)
و نکته اینجاس که هرچی که توی اون frame هست دیگه قابل دسترس نیست و اگه استفادشون کنیم undefined behavior هست. چرا؟ چون توی "مموری استک" این frame قرار داده شده بود و اون فضا الان آزاد شده و قابل استفاده هست برای بقیه(توی پرانتز، تو C که مدیریت حافظه نداره، باید آبجکت هایی که توی heap میسازیم رو خودمون مدیریت کنیم نه استک):
int *returnArray() {
int arr[3] = {11, 22, 33};
printf("%p\n", arr);
printf("%d\n", arr[1]);
return &arr;
}
int main(void) {
int *arr;
arr = returnArray();
printf("%p\n", arr);
printf("%d\n", arr[1]); // ???
}
با اینکه آدرسش رو return کردیم ولی باز نمیتونیم به آیتم های لیست دسترسی داشته باشیم.
حالا اینارو گفتم که موضوع مهمی رو بگم اونم اینکه تو پایتون هم همین call stack و اینا هست ولی اون frame object توی heap ساخته میشه. این به این معناس که اگه بخوایم میتونیم ذخیرش داشته باشیمش و همیشه بمونه! مثلا مانع از نابود شدن خودش و آبجکت های درونش بشیم. تو مثال زیر global f رو اگه از کامنت در بیارید obj از بین نمیره چون frame رو ذخیره کردیم:
from gc import collect
from sys import _getframe
class A:
def __del__(self):
print("del called")
def fn():
# global f
f = _getframe(0)
obj = A()
fn()
collect()
input()
خب حالا که اینو گفتیم بریم سراغ خود آبجکت فانکشن تو پایتون. وقتی فانکشن کال میشه یه frame object ساخته میشه. این frame object داخلش آبجکت های زیادی هست(مستقیم یا غیر مستقیم) از جمله رفرنسی داره به متغیر های داخل اون namespace و رفرنسی داره به code object که یک unit عه executable هست. داخل این code object ما bytecode ها رو داریم که همون instruction ها هستن.
درواقع instruction ها هستن که اجرا میشن و این state ذخیره میشه. تو کد زیر lasti یعنی last instruction. (توی cpu هم اتفاق مشابهی میفته. اینجا pvm میخواد بدونه چیو اجرا کرده و حالا نوبت چیه):
from sys import _getframe
def fn():
print(_getframe(0).f_lasti)
a = 10
print(_getframe(0).f_lasti)
fn()
خب حالا بخش جالب ماجرا اینجاس. ما به عنوان طراحان فرضی زبان پایتون، میدونیم که frame ما میتونه خارج از موقع کال شدن هم زنده بمونه + از طرفی به state هم که دسترسی داریم...( اینکه الان متغیر های local چیا هستن، اینکه الان تا instruction چندم اجرا شده و غیره)
فقط یه مشکلی هست، فانکشن های ما وقتی کال میشن از اولین instruction تا آخرینش رو اجرا میکنن و تموم میشن و همه ی آبجکت های داخل اون frame از بین میرن(اگه رفرنس دیگه ای نداشته باشن جای دیگه).
الان همه چیز محیا هست برای اینکه یه ساختار یا keyword جدیدی بیاریم تو زبان که هرجایی از execution فانکشن خواستیم بتونیم pause کنیم و اون رو با هر state ای که داره به حال خودش رها کنیم. بیایم yield رو معرفی کنیم! هروقت yield اومد، کافیه اجرا رو متوقف کنیم و مثل فانکشن ها(که بعد از تموم شدنشون، frame شون از stack frame جدا میشد) این generator ها رو هم frame شون رو جدا کنیم.
بعدا اگه خواسیم generator رو ادامه بدیم و روش next بزنیم(مستقیم خودمون یا غیر مستقیم توسط پایتون) تنها کاری که باید بکنیم اینه که frame ش رو برداریم بچسبونیم به stack frame ممون و از اون state ای که بودیم ادامه بدیم.
def gen():
a = 1
yield
b = 1
yield
g = gen()
next(g)
print(g.gi_frame.f_lasti, g.gi_frame.f_locals)
next(g)
print(g.gi_frame.f_lasti, g.gi_frame.f_locals)
این call stack با linkedlist پیاده سازی شده و frame ها نود های اون هستن. با f_back به frame قبلی اشاره میکنن به راحتی وصل میشن و جدا میشن.
جنریتور ها با وجود سرعت خوبی که دارن، برای سرعت بیشتر ساخته نشدن بلکه برای استفاده ی بهینه تر از مموری ساخته شدن. داشتن همچین آبجکتی(به اضافه ی ساختار هایی مثل yield from) میتونه زمینه ی خیلی چیز ها رو فراهم کنه. از جمله فریموورک هایی مثل asyncio :)
✒️ @AmirSoroushh
درود. میخواستم درباره ی آبجکت معروف و شناخته شده ی generator حرف بزنیم ولی با نگاه کمی متفاوت تر و به این برسیم که دقیقا چطور کار میکنه و چطور پیداش شد. نیاز هست که کمی حرف های پیش نیاز بزنیم صبور باشید.
قبل از هر چیزی درباره ی خود فانکشن حرف بزنیم ولی نه تو پایتون بلکه تو C:
وقتی یه فانکشنی کال میشه، توی call stack یک frame جدید میاد که برای اون فانکشن هست. این frame شامل تمام متغیر های لوکال و پارامتر های اون فانکشن هست. وقتی فانکشن تموم میشه چه اتفاقی میفته؟
اون frame از stack پاپ میشه(یا دقیق ترش stack pointer کم میشه)
و نکته اینجاس که هرچی که توی اون frame هست دیگه قابل دسترس نیست و اگه استفادشون کنیم undefined behavior هست. چرا؟ چون توی "مموری استک" این frame قرار داده شده بود و اون فضا الان آزاد شده و قابل استفاده هست برای بقیه(توی پرانتز، تو C که مدیریت حافظه نداره، باید آبجکت هایی که توی heap میسازیم رو خودمون مدیریت کنیم نه استک):
int *returnArray() {
int arr[3] = {11, 22, 33};
printf("%p\n", arr);
printf("%d\n", arr[1]);
return &arr;
}
int main(void) {
int *arr;
arr = returnArray();
printf("%p\n", arr);
printf("%d\n", arr[1]); // ???
}
با اینکه آدرسش رو return کردیم ولی باز نمیتونیم به آیتم های لیست دسترسی داشته باشیم.
حالا اینارو گفتم که موضوع مهمی رو بگم اونم اینکه تو پایتون هم همین call stack و اینا هست ولی اون frame object توی heap ساخته میشه. این به این معناس که اگه بخوایم میتونیم ذخیرش داشته باشیمش و همیشه بمونه! مثلا مانع از نابود شدن خودش و آبجکت های درونش بشیم. تو مثال زیر global f رو اگه از کامنت در بیارید obj از بین نمیره چون frame رو ذخیره کردیم:
from gc import collect
from sys import _getframe
class A:
def __del__(self):
print("del called")
def fn():
# global f
f = _getframe(0)
obj = A()
fn()
collect()
input()
خب حالا که اینو گفتیم بریم سراغ خود آبجکت فانکشن تو پایتون. وقتی فانکشن کال میشه یه frame object ساخته میشه. این frame object داخلش آبجکت های زیادی هست(مستقیم یا غیر مستقیم) از جمله رفرنسی داره به متغیر های داخل اون namespace و رفرنسی داره به code object که یک unit عه executable هست. داخل این code object ما bytecode ها رو داریم که همون instruction ها هستن.
درواقع instruction ها هستن که اجرا میشن و این state ذخیره میشه. تو کد زیر lasti یعنی last instruction. (توی cpu هم اتفاق مشابهی میفته. اینجا pvm میخواد بدونه چیو اجرا کرده و حالا نوبت چیه):
from sys import _getframe
def fn():
print(_getframe(0).f_lasti)
a = 10
print(_getframe(0).f_lasti)
fn()
خب حالا بخش جالب ماجرا اینجاس. ما به عنوان طراحان فرضی زبان پایتون، میدونیم که frame ما میتونه خارج از موقع کال شدن هم زنده بمونه + از طرفی به state هم که دسترسی داریم...( اینکه الان متغیر های local چیا هستن، اینکه الان تا instruction چندم اجرا شده و غیره)
فقط یه مشکلی هست، فانکشن های ما وقتی کال میشن از اولین instruction تا آخرینش رو اجرا میکنن و تموم میشن و همه ی آبجکت های داخل اون frame از بین میرن(اگه رفرنس دیگه ای نداشته باشن جای دیگه).
الان همه چیز محیا هست برای اینکه یه ساختار یا keyword جدیدی بیاریم تو زبان که هرجایی از execution فانکشن خواستیم بتونیم pause کنیم و اون رو با هر state ای که داره به حال خودش رها کنیم. بیایم yield رو معرفی کنیم! هروقت yield اومد، کافیه اجرا رو متوقف کنیم و مثل فانکشن ها(که بعد از تموم شدنشون، frame شون از stack frame جدا میشد) این generator ها رو هم frame شون رو جدا کنیم.
بعدا اگه خواسیم generator رو ادامه بدیم و روش next بزنیم(مستقیم خودمون یا غیر مستقیم توسط پایتون) تنها کاری که باید بکنیم اینه که frame ش رو برداریم بچسبونیم به stack frame ممون و از اون state ای که بودیم ادامه بدیم.
def gen():
a = 1
yield
b = 1
yield
g = gen()
next(g)
print(g.gi_frame.f_lasti, g.gi_frame.f_locals)
next(g)
print(g.gi_frame.f_lasti, g.gi_frame.f_locals)
این call stack با linkedlist پیاده سازی شده و frame ها نود های اون هستن. با f_back به frame قبلی اشاره میکنن به راحتی وصل میشن و جدا میشن.
جنریتور ها با وجود سرعت خوبی که دارن، برای سرعت بیشتر ساخته نشدن بلکه برای استفاده ی بهینه تر از مموری ساخته شدن. داشتن همچین آبجکتی(به اضافه ی ساختار هایی مثل yield from) میتونه زمینه ی خیلی چیز ها رو فراهم کنه. از جمله فریموورک هایی مثل asyncio :)
✒️ @AmirSoroushh
How to Create a Responsive Data Entry form with | Python GUI project
https://morioh.com/a/83cf81fd894c/how-to-create-a-responsive-data-entry-form-with-or-python-gui-project
https://morioh.com/a/83cf81fd894c/how-to-create-a-responsive-data-entry-form-with-or-python-gui-project
Morioh
How to Create a Responsive Data Entry form with | Python GUI project
Learn how to create a responsive data entry form with Tkinter. Use buttons, labels, and entries. Position with the tkinter grid system. Add error popups.
Forwarded from 🐍 Python & Raspberry 🐍 (DailyProjects)
چرا باید دیزاین پترنها و کاربردهای آن آشنا شویم؟
یادگیری و همچنین بهکار بردن دیزاین پترنها مفید است. در ادامه، دلایلی را در این مورد بیان کردهایم.
- دیزاین پترنها، ایدههای بیشتر و بهتری را در مورد نحوه مدلسازی مسائل فنی خاص، عرضه میکنند.
- امکان استفاده مجدد و بهکارگیری ایدههای طراحی که مؤثر بودن آنها ثابت شدهاست، وجود دارد.
- میتوانیم جزئیات مناسبتری از کلاسهایمان بهدست آوریم که حوزه خاصی را مدلسازی میکنند.
یک پلی لیست در خصوص دیزاین پترن دارم که هر هفته داخلش ویدیو منتشر میشه و تا الان ۹ قسمت منتشر شده و تمام مثال ها برعکس کتاب های gang of four و دیزاین پترن های دیگه با پایتونه با مثال کاربردی 😍
https://www.youtube.com/playlist?list=PLEQ3RnweNGA5XLLANrPl5erS90EREs0F0
فقط هم دیزاین پترن gang of four نیست در واقع کلی دیزاین پترن کاربردی هم داریم که میتونید به صورت روزانه استفاده کنید.مثلا در قسمت نهم پلی لیست دیزاین پترن و مهم ترین قسمت این پلی لیست, پرداختم به دیزاین پترن Type State. پترنی که سبک کد نویسی من رو به شدت تغییر داد و هر روز ازش استفاده میکنم
مفاهیم زیر رو ابتدا توضیح دادم:
- Don't validate, parse!
- Type safe operations
و توضیح دادم چطور به صورت غریزی و ابتدایی از type state استفاده میکنیم. همینطور یوزکیس های خیلی بهتر و advance تر هم توضیح دادم و دلیل محبوبیت Pydantic هم توضیح دادم.
با Type state pattern کد هاتون به شدت باگ کمتری خواهند داشت پس اگه دوست دارین کمتر با باگ سروکله بزنید این ویدیو رو از دست ندید. حتما توصیه میشه قبل از دیدن این ویدیو, ویدیو قبلی راجب state pattern هم ببینید که ۱۰ دقیقه هست.
لینک ویدیو:
https://youtu.be/DwAQ6dm-Vn8
لینک گیتهاب دوره دیزاین پترن; جزوه و مثال های دوره همه اینجا ذخیره خواهند شد:
https://github.com/ManiMozaffar/design-101
@Raspberry_Python
یادگیری و همچنین بهکار بردن دیزاین پترنها مفید است. در ادامه، دلایلی را در این مورد بیان کردهایم.
- دیزاین پترنها، ایدههای بیشتر و بهتری را در مورد نحوه مدلسازی مسائل فنی خاص، عرضه میکنند.
- امکان استفاده مجدد و بهکارگیری ایدههای طراحی که مؤثر بودن آنها ثابت شدهاست، وجود دارد.
- میتوانیم جزئیات مناسبتری از کلاسهایمان بهدست آوریم که حوزه خاصی را مدلسازی میکنند.
یک پلی لیست در خصوص دیزاین پترن دارم که هر هفته داخلش ویدیو منتشر میشه و تا الان ۹ قسمت منتشر شده و تمام مثال ها برعکس کتاب های gang of four و دیزاین پترن های دیگه با پایتونه با مثال کاربردی 😍
https://www.youtube.com/playlist?list=PLEQ3RnweNGA5XLLANrPl5erS90EREs0F0
فقط هم دیزاین پترن gang of four نیست در واقع کلی دیزاین پترن کاربردی هم داریم که میتونید به صورت روزانه استفاده کنید.مثلا در قسمت نهم پلی لیست دیزاین پترن و مهم ترین قسمت این پلی لیست, پرداختم به دیزاین پترن Type State. پترنی که سبک کد نویسی من رو به شدت تغییر داد و هر روز ازش استفاده میکنم
مفاهیم زیر رو ابتدا توضیح دادم:
- Don't validate, parse!
- Type safe operations
و توضیح دادم چطور به صورت غریزی و ابتدایی از type state استفاده میکنیم. همینطور یوزکیس های خیلی بهتر و advance تر هم توضیح دادم و دلیل محبوبیت Pydantic هم توضیح دادم.
با Type state pattern کد هاتون به شدت باگ کمتری خواهند داشت پس اگه دوست دارین کمتر با باگ سروکله بزنید این ویدیو رو از دست ندید. حتما توصیه میشه قبل از دیدن این ویدیو, ویدیو قبلی راجب state pattern هم ببینید که ۱۰ دقیقه هست.
لینک ویدیو:
https://youtu.be/DwAQ6dm-Vn8
لینک گیتهاب دوره دیزاین پترن; جزوه و مثال های دوره همه اینجا ذخیره خواهند شد:
https://github.com/ManiMozaffar/design-101
@Raspberry_Python
YouTube
دیزاین پترن Type State - مهم ترین ویدیو دوره!
در قسمت نهم پلی لیست دیزاین پترن و مهم ترین قسمت این پلی لیست, پرداختم به دیزاین پترن Type State
مفاهیم زیر رو ابتدا توضیح دادم:
- Don't validate, parse!
- Type safe operations
و توضیح دادم چطور به صورت غریزی و ابتدایی از type state استفاده میکنیم. همینطور…
مفاهیم زیر رو ابتدا توضیح دادم:
- Don't validate, parse!
- Type safe operations
و توضیح دادم چطور به صورت غریزی و ابتدایی از type state استفاده میکنیم. همینطور…
در قسمت دهم پلی لیست دیزاین پترن
تو این قسمتChain of Responsibility رو بررسی کردیم. یک مثال پروداکشنی با کد بویلرپلیت هم نمایش دادم که نسبتا مثال پیچیده ای بود تا واقعا یوزکیس این دیزاین پترن رو درک کنید. در نهایت به نقاط ضعف و قوت این دیزاین پترن پرداختیم. اگه سوالی داشتین حتما زیره ویدیو کامنت کنید. برای حمایت ممنون میشم سابسکرایب کنید و داخل گیتهاب استار بدین به ریپو.
لینک ویدیو:
https://youtu.be/F0YyisF7Hq4
لینک گیتهاب دوره دیزاین پترن; جزوه و مثال های دوره همه اینجا ذخیره خواهند شد:
https://github.com/ManiMozaffar/design-101
@Raspberry_Python
تو این قسمتChain of Responsibility رو بررسی کردیم. یک مثال پروداکشنی با کد بویلرپلیت هم نمایش دادم که نسبتا مثال پیچیده ای بود تا واقعا یوزکیس این دیزاین پترن رو درک کنید. در نهایت به نقاط ضعف و قوت این دیزاین پترن پرداختیم. اگه سوالی داشتین حتما زیره ویدیو کامنت کنید. برای حمایت ممنون میشم سابسکرایب کنید و داخل گیتهاب استار بدین به ریپو.
لینک ویدیو:
https://youtu.be/F0YyisF7Hq4
لینک گیتهاب دوره دیزاین پترن; جزوه و مثال های دوره همه اینجا ذخیره خواهند شد:
https://github.com/ManiMozaffar/design-101
@Raspberry_Python
“… Because the problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle. “ —Joe Armstrong, creator of Erlang progamming language
وقتی به یک موز نیاز دارین تو یک تابعی , یک گوریلا با موز ندین به اون تابع! 😁 مقاله مدیوم:
https://medium.com/codemonday/banana-gorilla-jungle-oop-5052b2e4d588
یک مثال خیلی قشنگ. اشتباهی که خیلیا انجام میدن
مثلا شما به آیدی یوزر نیاز داری تو یک فانکشن. به جای اینکه یوزر رو بذاری تو signature و ایدی رو ازش بگیری سعی کن یوزر آیدی رو فقط بگیری. اینو به دلیل پرفومنس نمیگم چون تاثیری نداره ولی به این دلیل میگم که کدتون رو به شدت reusable تر میکنه. حالا میتونه اون فانکشن رو صدا بزنی بدون اینکه اطلاعات دیگه ای از یوزر داشته باشی یا بدون اینکه هیت بزنی به دیتابیس پس حتی میشه گفت پرفومنس رو بهتر هم میکنه.
به این قانون law of demeter هم میگن. هدفشم چیزی جز بهتر شدن reusability کدتون و راحت تر تست نوشتن نیست.
@Raspberry_Python
وقتی به یک موز نیاز دارین تو یک تابعی , یک گوریلا با موز ندین به اون تابع! 😁 مقاله مدیوم:
https://medium.com/codemonday/banana-gorilla-jungle-oop-5052b2e4d588
یک مثال خیلی قشنگ. اشتباهی که خیلیا انجام میدن
مثلا شما به آیدی یوزر نیاز داری تو یک فانکشن. به جای اینکه یوزر رو بذاری تو signature و ایدی رو ازش بگیری سعی کن یوزر آیدی رو فقط بگیری. اینو به دلیل پرفومنس نمیگم چون تاثیری نداره ولی به این دلیل میگم که کدتون رو به شدت reusable تر میکنه. حالا میتونه اون فانکشن رو صدا بزنی بدون اینکه اطلاعات دیگه ای از یوزر داشته باشی یا بدون اینکه هیت بزنی به دیتابیس پس حتی میشه گفت پرفومنس رو بهتر هم میکنه.
# BAD
def activate_user(user: User, session) -> None
session.execute(sa.update(User).where(User.id==user.id).values(is_active=True)
# GOOD
def activate_user(user_id: UserId, session) -> None
session.execute(sa.update(User).where(User.id==user_id).values(is_active=True)
به این قانون law of demeter هم میگن. هدفشم چیزی جز بهتر شدن reusability کدتون و راحت تر تست نوشتن نیست.
@Raspberry_Python
Medium
Banana Gorilla Jungle — OOP
From the famous quote,
✔️ الگوریتم Timsort
بیاید تا یکی از سریعترین الگوریتمهای مرتبسازی که حدود ۲۲ ساله زندهست و از پایتون 2.3 الگوریتم مرتب سازی استاندارد پایتونه و همچنین توی جاوا و Rust و Android و GNU Octave و انجین V8 هم حضور داره رو کاملا مفصل بررسیش کنیم 😁
🔗 https://virgool.io/@liewpl/timsort-algorithm-u41h0wv0jnax
〰〰〰〰〰〰〰
✒️@pyeafp
©@raspberry_python
بیاید تا یکی از سریعترین الگوریتمهای مرتبسازی که حدود ۲۲ ساله زندهست و از پایتون 2.3 الگوریتم مرتب سازی استاندارد پایتونه و همچنین توی جاوا و Rust و Android و GNU Octave و انجین V8 هم حضور داره رو کاملا مفصل بررسیش کنیم 😁
🔗 https://virgool.io/@liewpl/timsort-algorithm-u41h0wv0jnax
〰〰〰〰〰〰〰
✒️@pyeafp
©@raspberry_python
Forwarded from 🐍 Python & Raspberry 🐍 (DailyProjects)
Forwarded from 🐍 Python & Raspberry 🐍 (DailyProjects)