CodeCrafters
778 subscribers
90 photos
50 videos
41 files
170 links
Download Telegram
Forwarded from Pythonic Dev (  Sadegh)
📢 Understanding the Callstack in Programming! 📚

Welcome, fellow developers, to another insightful post on our Telegram channel! Today, we dive into an important concept in programming - the "Callstack." 🔄

💡 What is a Callstack?
A callstack, also known as an execution stack, is a fundamental concept in computer science that helps us understand how programs execute and keep track of function calls. When a function is called, its execution context is added to the top of the callstack, and when that function completes, it is removed from the stack. Essentially, the callstack keeps track of where we are in the execution of a program.

🧮 How does the Callstack work?
Imagine you have a Python program that calls multiple functions. Each time a function is called, its execution context is added to the callstack. This includes variables, parameters, and the return address of the calling function. When the called function completes, its execution context is removed from the stack, and the program continues from where it left off in the calling function.

🔍 Why is the Callstack important?
Understanding the callstack is crucial for debugging, as it helps us trace the flow of our program, identify the order in which functions are executed, and identify any potential issues such as infinite recursion or stack overflow. By examining the callstack, we can gain valuable insight into how our program behaves and find the root cause of any unexpected behavior or errors.

📝 Key points about the Callstack:
1️⃣ The callstack follows the Last-In-First-Out (LIFO) principle, meaning the most recently called function is at the top of the stack.
2️⃣ Recursion occurs when a function calls itself, adding multiple instances of the same function to the callstack.
3️⃣ If the callstack becomes too large, it can result in a stack overflow, causing the program to terminate unexpectedly.

🔧 How can we use the Callstack to our advantage?
1️⃣ By examining the callstack during debugging, we can better understand the sequence of function calls and potentially identify any missed or incorrect function invocations.
2️⃣ Understanding the callstack can help us optimize our code by avoiding unnecessary function calls or reducing recursion depth.
3️⃣ The callstack can be a useful tool for identifying and fixing memory-related issues in our programs.

Remember, as you delve deeper into your programming journey, always pay attention to the callstack. It holds the key to understanding the intricacies of function calls and program execution!

🌟 Stay curious, keep learning, and keep coding! Feel free to share your thoughts or ask any questions in the comments below. Happy coding, everyone! 🐍💻

#CallStack
#Python
@Pythonic_Dev
👍1
Property and Descriptor-Based Attributes

Property
پایتون به شما امکان می‌دهد رفتاری شبیه به تابع را بر روی اتریبیوت های موجود در کلاس اضافه کنید و آن‌ها را به اتریبیوت های مدیریت‌شده (managed attribute) تبدیل کنید. این نوع ویژگی از بروز تغییرات اساسی در APIیعنی همان اینترفیس عمومی های شما جلوگیری می‌کند.

به عبارت دیگر، با اتریبیوت های مدیریت شده، شما می‌توانید همزمان از رفتار شبیه به تابع و دسترسی شبیه به اتریبیوت بهره‌مند شوید. نیازی به تغییر APIهای خود با جایگزین کردن اتریبیوت ها با متدها نیست، که ممکن است کد کاربران‌تان را دچار مشکل کند.
برای ایجاد یک اتریبیوت مدیریت شده با رفتار شبیه به تابع در پایتون، شما می‌توانید از یک property یا یک descriptor استفاده کنید، بسته به نیازهای خاص خود.
به عنوان مثال، به کلاس Circle خود برگردید و فرض کنید که نیاز دارید شعاع را تایید کنید تا اطمینان حاصل شود که فقط اعداد مثبت ذخیره می‌شوند. چگونه این کار را بدون تغییر اینترفیس کلاس انجام می‌دهید؟ سریع‌ترین روش برای حل این مشکل استفاده از یک property و پیاده‌سازی منطق ولیدیشن( اعتبارسنجی) در متد setter است.


import math

class Circle:
def __init__(self, radius):
self.radius = radius

@property
def radius(self):
return self._radius

@radius.setter
def radius(self, value):
if not isinstance(value, int | float) or value <= 0:
raise ValueError("positive number expected")
self._radius = value

def calculate_area(self):
return round(math.pi * self._radius**2, 2)

برای تبدیل اتریبیوت radius به یک پراپرتی، از دکوریتور property استفاده میکنیم یک متد getter بنویسیم. این متد هنگامی اجرا میشه که میخواهیم مقدار اتریبیوت radius رو مشاهده کنیم، پس قطعا باید مقدار شعاع رو به ما ریترن(return) کنه.
برای اینکه یک متد setter برای پراپرتی شعاع مون بنویسم از دکوریتور @ attr_name.setter استفاده میکنیم.
حال داخل متد setter میایم و منطق اعتبارسنجی که نیاز داشتیم رو پیاده میکنیم و اگر عدد طبق چیزی که انتظار داشتیم نبود به ما خطا میدهد در غیر این صورت در یک اتریبیوت non-public به نام _radius ذخیره میکنیم. حالا اتریبیوت radius ما تبدیل به یک پراپرتی شده و هرموقع که نیاز به مشاهده مقدار یا تغییر مقدار ان بودیم خود پایتون اتومات، ابتدا با توجه به عملیات یکی از متد های getter یا setter رو کال میکنه.
نحوه کارکرد اون به شکل زیر هست.
>>> from circle import Circle

>>> circle_1 = Circle(100)
>>> circle_1.radius
100
>>> circle_1.radius = 500
>>> circle_1.radius = 0
Traceback (most recent call last):
...
ValueError: positive number expected

>>> circle_2 = Circle(-100)
Traceback (most recent call last):
...
ValueError: positive number expected

>>> circle_3 = Circle("300")
Traceback (most recent call last):
...
ValueError: positive number expected


میبینید که با اتریبیوت radius دارید به طور عادی رفتار میکنید اما در پشت قضیه، یک رفتار متد مانند دارد و اگر مقدار نامعتبر دهید خطا میدهد.
منبع
#Property #Python
@Code_Crafters
2🔥1👏1
Descriptor
استفاده از descriptor ها هم یک روش قوی برای اضافه کردن رفتار متد مانند به یک اتریبیوت بدون تغییر دادن اینترفیس یک کلاس است. فرض کنید یک برنامه طراحی نوشتید و دو تا کلاس به نام های دایره و مربع دارید. میخواهیم عددی را به عنوان شعاع/ طول بگیریم و قبل ان چک کنیم که عدد حتما مثبت باشد. خب طبق چیزی که تا الان یاد گرفتیم میدانیم که با property میشود همین کار را انجام داد اما این کار باعث کد تکراری زدن میشود و خوب نیست پس از descriptor استفاده میکنیم.
با استفاده از descriptor کدی مانند زیر خواهیم داشت.

import math

class PositiveNumber:
def __set_name__(self, owner, name):
self._name = name

def __get__(self, instance, owner):
return instance.__dict__[self._name]

def __set__(self, instance, value):
if not isinstance(value, int | float) or value <= 0:
raise ValueError("positive number expected")
instance.__dict__[self._name] = value

class Circle:
radius = PositiveNumber()

def __init__(self, radius):
self.radius = radius

def calculate_area(self):
return round(math.pi * self.radius**2, 2)

class Square:
side = PositiveNumber()

def __init__(self, side):
self.side = side

def calculate_area(self):
return round(self.side**2, 2)


در قطعه کد بالا میبینیم که یک کلاس به نام PositiveNumber داریم.
این همان descriptor ما هست. سه داندر متد داره که به ترتیب به توضیح انها میپردازم.
متد اولی توسط پایتون به صورت اتومات هنگامی که از ان یک اینستنس بسازید صدا زده میشود و نام ان اینستنس هرچه که باشد به عنوان ارگومان name به متد پاس داده میشود. ارگومان owner هم نام کلاسی است که descriptor در ان استفاده شده است. ( در مثال ما Circle یا Square)
متد دوم همان متد getter و متد سوم هم همان متد setter همانند کاری که در پراپرتی انجام دادیم.
ارگومان instance که در دو متد getter,setter وجود داره درواقع همون اینستنسی هست که از کلاس Circle یا Square ما ساخته شده.
توجه داشته باشید که برای ذخیره یا مشاهده از اتریبیوت
__dict__
استفاده میکنیم که جلوتر متوجه علت ان خواهید شد.
این متد ها، اتومات توسط خود پایتون صدا زده میشوند.
حال در کلاس دایره خود، یک اتریبیوت کلاس به نام radius داریم که مقدارش، یک اینستنس از کلاس descriptor ما هست.
حال از این بعد هروقت بخواهیم مقداری در اتریبیوت radius ذخیره کنیم یا مقدار ان را مشاهده کنیم، بجای انکه پایتون از اتریبیوت
__dict__
ان را بخواند یا ذخیره کند، متد های getter, setter از کلاس PositiveNumber با توجه به عملیات مورد نیاز صدا زده میشود و ارگومان های مورد نیاز پاس داده خواهد شد.
منبع
#Descriptor #Python
@Code_Crafters
👍42👏1
در این پست  قراره تمایز اغلب گیج کننده بین function  و  method  هارو  را بررسی  کنیم🥸
هر دو بلوک های اساسی در  پایتون هستند اما اهداف کمی تفاوت دارد. ما آنها را در کنار هم در قالب جدول با هم مقایسه خواهیم کرد و نمونه های کد واقعی را برای نشان دادن نحوه استفاده از هر کدام ارائه می دهیم. چه مبتدی باشید و چه به دنبال تقویت مهارت های پایتون خود باشید، این تفکیک دقیق به شما درک روشنی از زمان و نحوه استفاده موثر از function  ها و method  ها می دهد.                                                                                                                                                                                                                                                                                   

تابع(functios)در پایتون چیست؟                                                                                                                در پایتون، یک تابع یک بلوک از کد است که برای انجام یک کار خاص طراحی شده است. توابع به تقسیم برنامه ما به قطعات کوچکتر و ماژولار کمک می کنند. با ایجاد برنامه های پیچیده تر، توابع را می توان مجدداً مورد استفاده قرار داد و کد شما را سازماندهی و مدیریت کرد.                                                                                                                                                                                                                           مثالی از یک تابع:
def greet(name):
    return f"Hello, {name}!"

print(greet("ali"))  # Output: Hello, ali!



متد در پایتون چیست؟
متد
، به عکس تابع، یک تابع است که به یک شیء مرتبط است. در پایتون، متدها مستقل نیستند و باید بر روی یک شیء یا داخل یک کلاس فراخوانی شوند. متدها به طور ضمنی از یک شیء استفاده می‌کنند که برای آن فراخوانی شده‌اند.
برای درک بهتر به مثال زیر توجه کنید.
class Greeter:
    def __init__(self, name):
        self.name = name
   
    def greet(self):
        return f"Hello, {self.name}!"

g = Greeter("ali")
print(g.greet())  # Output: Hello, ali!

در اینجا، greet یک متد از کلاس Greeter است و بر روی نمونه g از آن کلاس فراخوانی می‌شود.

در ادامه چند مثال عملی رو باهم بررسی میکنیم.
Function:
def factorial(n):
    if n == 0:
        return 1
    else:
        return n * factorial(n-1)

print(factorial(5))  # Output: 120

در اینجا یک تابع ساده برای به دست اوردن فاکتوریل یک عدد داریم.(5!)

Method:
class Car:
    def __init__(self, make, model):
        self.make = make
        self.model = model

    def description(self):
        return f"{self.make} {self.model}"

my_car = Car("Toyota", "Corolla")
print(my_car.description())  # Output: Toyota Corolla

در اینجا تابع description  یک متود است که جزئیات مربوط به یک نمونه خودرو رو نشون میده.


درک تمایز بین توابع و متودها در پایتون برای نوشتن کد واضح و موثر بسیار مهم است. توابع ماژولار بودن و قابلیت استفاده مجدد را ارائه می دهند، در حالی که متود ها ما را قادر می سازند تا رفتارهای درون اشیاء را با رعایت اصول برنامه نویسی شی گرا محصور کنیم. اینکه یک تابع یا یک روش را انتخاب کنید تا حد زیادی به نیازهای خاص برنامه و ترجیحات طراحی شما بستگی دارد. با درک این مفاهیم، ​​می توانید از انعطاف پذیری و استحکام پایتون در پروژه های برنامه نویسی خود استفاده کنید و کد خود را سازماندهی و پویا تر کنید.
در قسمت کامنت ها جدولی رو برای اختلاف بین function و method میتونید مشاهده کنید
منبع

#python

@code_crafters
👍12
در این پست  نکات و ترفند های پیشرفته مدل های جنگو رو بررسی خواهیم کرد.🥸
از جمله: ...indexing, custom managers, inheritance

ارث بری مدل ها به شما امکان می دهد یک مدل پایه با اطلاعات رایج ایجاد کنید و آن را در مدل های دیگر گسترش دهید. جنگو از سه نوع model inheritance پشتیبانی می کند:
abstract base classes, multi-table inheritance, and proxy models

Using Abstract Models:
روشی فوق‌العاده برای جمع‌بندی اطلاعات و رفتار مشترک هستند. برای یک abstract model هیچ جدولی در دیتابیس نشان داده نمی شود. در عوض، فیلدها و متدهای آن توسط زیر کلاس‌ها به ارث می‌رسند.
Example:
class BaseProfile(models.Model):
bio = models.TextField()
avatar = models.ImageField(upload_to='avatars/')

class Meta:
abstract = True

class StudentProfile(BaseProfile):
graduation_year = models.IntegerField()

class TeacherProfile(BaseProfile):
office = models.CharField(max_length=100)

در اینجا BaseProfile مانند یک الگو عمل میکند.StudentProfile, TeacherProfile هر دو دارای فیلد های bio , avatar خواهند بود اما هر کدام در جدول های پایگاه داده خودشان ذخیره میشوند.


Custom Managers :
در جنگو Custom Managers به شما این امکان را می دهند که عملکردهای سطح جدول را به مدل های جنگو خود اضافه کنید. آنها را می توان برای کپسوله کردن و عملیات های crud پیچیده و ارائه یک API تمیزتر برای مدل استفاده کرد.
Example:
class ActiveProfileManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(deleted=False)

class Profile(models.Model):
name = models.CharField(max_length=100)
deleted = models.BooleanField(default=False)
objects = models.Manager() # The default manager.
active_objects = ActiveProfileManager() # Our custom manager.

# Usage:
active_profiles = Profile.active_objects.all()

این custom manager تمامی query های شمارو بر اساس "deleted" فیلتر میکند.


Models Migrations:
مدیریت
Migrations مدل‌ها
در جنگو migrations به شما امکان می‌دهند تا طی زمان، طرح پایگاه داده خود را تکامل دهید. مدیریت مناسب migrations ها برای حفظ یک پروژه سالم بسیار حیاتی است.

توصیه‌ها:

برنامه‌ریزی migrations خود: سعی کنید هنگام امکان‌پذیر بودن، مهاجرت‌ها را ترکیب کنید و آن‌ها را به کنترل نسخه منتقل کنید.
تست migrations: همیشه migrations را به صورت محلی و در محیط استیجینگ تست کنید، قبل از اعمال آن‌ها در محیط تولید.
استفاده از دستور makemigrations برای تولید فایل‌های migrations
استفاده از دستور migrate برای اعمال migrations ها
استفاده از دستور sqlmigrate برای پیش‌نمایش دستور sql


Proxy Models:
مدل‌های پروکسی برای تغییر رفتار یک مدل، مانند defualt ordering یا custom manager بدون ایجاد جدول پایگاه داده جدید استفاده می‌شوند.

Example:
class OrderedProfile(Profile):
class Meta:
proxy = True
ordering = ['name']

# Usage:
ordered_profiles = OrderedProfile.objects.all()

این پروکسی مدل تمامی profile هارا بر اساس نام نشان میدهد.

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

class Place(models.Model):
name = models.CharField(max_length=50)

class Restaurant(Place):
serves_pizza = models.BooleanField(default=False)

مدل
Restaurant از مدل Place ارث‌بری می‌کند. این بدان معنی است که همه فیلدهای Place به صورت اتوماتیک به Restaurant ارث می‌برده شده و Restaurant از همه ویژگی‌های Place استفاده می‌کند.
این الگو به شما امکان می‌دهد که یک مدل (در اینجا Restaurant) را برای ارث‌بری از ویژگی‌ها و رفتارهای یک مدل دیگر (در اینجا Place) استفاده کنید، در حالی که همچنان می‌توانید به آن فیلدها و ویژگی‌های جدیدی را اضافه کنید.

ادامه مطالب در پست بعد
#python

@code_crafters
👍92
CodeCrafters
در این پست  نکات و ترفند های پیشرفته مدل های جنگو رو بررسی خواهیم کرد.🥸 از جمله: ...indexing, custom managers, inheritance ارث بری مدل ها به شما امکان می دهد یک مدل پایه با اطلاعات رایج ایجاد کنید و آن را در مدل های دیگر گسترش دهید. جنگو از سه نوع model…
در ادامه پست قبلی:
Indexing:
ایندکس
ها برای بهبود عملکرد عملیات پایگاه داده، به ویژه برای مجموعه داده های بزرگ، ضروری هستند.
به عنوان مثال، فرض کنید شما یک جدول کاربران دارید و می‌خواهید بر اساس نام آن‌ها جستجو کنید. بدون ایندکس، پایگاه داده باید هر رکورد را از ابتدا تا انتها بررسی کند تا نام مورد نظر را پیدا کند. اما با ایجاد یک ایندکس بر روی فیلد نام، پایگاه داده می‌تواند به سرعت به رکوردهای مرتبط با نام مورد نظر دسترسی پیدا کند.

Example:
class User(models.Model):
username = models.CharField(max_length=100, db_index=True)
email = models.CharField(max_length=100)

class Meta:
indexes = [
models.Index(fields=['username'], name='username_idx'),
models.Index(fields=['email'], name='email_idx')
]


Overriding Model Methods:
وقتی در Django یک مدل ایجاد می‌کنید، می‌توانید رفتارهای خاصی را برای عملیات‌های مختلف مدل، مانند ذخیره‌سازی یا حذف، سفارشی‌سازی کنید. این کار به شما این امکان را می‌دهد که قبل یا بعد از انجام یک عملیات، کارهای خاصی انجام دهید. شما میتوانید عملیات save , delete ,.... رو بازنویسی کنید.

Example:
class MyModel(models.Model):
name = models.CharField(max_length=100)

def save(self, *args, **kwargs):
self.name = self.name.upper()
super().save(*args, **kwargs)

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


Soft Deletion:

استفاده از Soft Deletion به شما این امکان را می‌دهد که آیتم‌ها را به عنوان حذف شده علامت‌گذاری کنید، اما در واقع آن‌ها را از پایگاه داده حذف نکنید. به این تکنیک "حذف نرم" یا "حذف موقت" نیز گفته می‌شود. این روش برای نگهداری تاریخچه داده‌ها، امکان بازگردانی آیتم‌های حذف شده و همچنین حفظ ارتباطات بین آیتم‌های مختلف مفید است.
Example:
class SoftDeleteModel(models.Model):
is_deleted = models.BooleanField(default=False)

def delete(self, *args, **kwargs):
self.is_deleted = True
self.save()


هر یک از این تکنیک ها مجموعه ای از مزایای خاص خود را ارائه می دهد و می تواند به طور قابل توجهی بر کارایی و عملکرد پروژه های شما تأثیر بگذارد. با اجرای این استراتژی‌ها، می‌توانید از قابلیت‌های قدرتمند مدل‌سازی جنگو برای ساخت برنامه‌های کاربردی وب قوی‌تر و مقیاس‌پذیرتر بهره ببرید.
منبع
#python

@code_crafters
11
محاسبات موازی: یک عملیات روی چند هسته انجام می‌شود
محاسبات همزمان: یک هسته بین چند عملیات جابجا می‌شود

داریم راجب چی صحبت میکنیم؟؟؟
وقتی برنامه شما اجرا میشه، تبدیل به فرآیندهایی در سطح سیستم عامل میشه و سیستم عامل شروع میکنه به مدیریت اونها (به شکل پیشگیرانه) مطابق استاندارد خودش، اینکه چه منابعی رو و چقدر درگیر کنه یا نگه داره و یا از سر بگیره و به دیگری بده و ...


واسه جماعت برنامه نویس خبر خوب اینکه هیچی دست شما نیست، و خبر بد اینکه هیچی دست شما نیست😅😅😅
در واقع این مشکل شما نیست منتها نمی‌تونید کار زیادی هم انجام بدید

در پایتون دو کتابخانه داریم:
یکی تردها:
که بوسیله اون چندین نخ روی هسته اجرا میشه - کنترل اون رو سیستم عامل در دست میگیره - هرگاه یک نخ دچار مشکل بشه مابقی نخ‌ها توسط سیستم عامل اجرا و کار رو پیش می‌برند - مناسب کارهای ورودی خروجی هستش - پیچیدگی استفاده دارند (نمیدونیم چه اتفاقی داره میافته و اصلا نخ فعال داریم یا نه تا زمانیکه رخ دادی ازشون مشاهده کنیم مثه خونه جن زده تا اتفاقی نیافته متوجه حضورشون نمی‌شیم) - به سطح فرآیند برسند gil فعال شده و در واقع موازی سازی ندارید دلیل اون هم جلوگیری از شرایط مسابقه (race conditions) هستش ـ پر هزینه هم هستند

دومی مولتی پراسس:
هر فرایند روی یک هسته اجرا میشه - کنترل اون توسط سیستم عامل هست - مناسب پردازش‌های سنگین - پیچیدگی خاص خودش رو داره و اندکی کار خطرناک هستش - پر هزینه هم هستند

مشکل این دو کتابخانه پیچیدگی زیاد در استفاده هستش و هر کدام در یک کتابخانه جدا تهیه شده بود که استفاده ازش دردسر خاص خودش رو داشت

در نهایت کتابخانه concurrent.future اومد وسط که استخر تردها و پروسس هارو باهم داشت و در api سطح بالا بهمون کمک می‌کرد مشکلات gil در ترد سرجای خودش باقی موند منتها کار و مدیریت رو راحت‌تر میکنه برامون

تا اینجا تردها به رویکرد پیشگیرانه توسط سیستم عامل عمل میکردن

میرسیم به نخ‌های سبز:
این نوع نخ‌ها در سطح برنامه شما (مفسر پایتون) کار میکنن - در سطح سیستم‌عامل تنها بر روی یک نخ اجرا میشوند - دسترسی بیشتری بابت مدیریت و کنترل بهمون میدن و باید خودمون مدیریت کنیم - به روش مشارکتی کار میکنن (منابع رو بر اساس نقاطی که ما مشخص کردیم بهمدیگه پاس میدن) - هزینه کمتری دارن - اما یک اشتباه از سمت ما منجر به کرش برنامه خواهد شد (دیباگ سخت) - هزینه کمتر و سبک تر و اغلب سریع‌تر از تردهای سیستم عامل هستند - در صورت ترکیب با چند پردازنده موازی سازی رخ میده (در غیر این صورت چون در یک نخ در سیستم عامل اجرا میشود تحت کنترل gil است)

در موضوع بالا احتمال دیباگ و خطا منحر به کرش برنامه می‌شد بابت همین asyncio اومد وسط که کاملا از لحاظ کارایی شبیه نخ‌های سبز بود با این تفاوت که در نخ سبز نقاط پایانی و جابجایی توسط ما بود (همون جایی که ممکن بود خطا کنیم)، ناهمزمانی در یک حلقه رویداد رخ میداد و بدین ترتیب مشکل کرش بر طرف شد - اندکی سرعتش از نخ‌های سبز کمتره و نیاز به یادگیری داره

در نهایت برگردیم سر وب، در وب هر فریمورکی که بر پایه و اساس starlette نوشته بشه (یک ماژول برای http) از ناهمزمانی پشتیبانی میکنه و میتونه رقیب سر سختی برای go و nodejs محسوب بشه که نمونه بارز اون fastapi هستش

اما این مسائل بر علیه django خواهد بود؟
نه حقیقتا، جنگو بشدت برای برنامه‌های بزرگ و پیچیده مناسب است



سعی کردم خیلی ساده براتون بگم 😂😂😂

#python
#thread
#gil
#process

@code_crafters
9👍2