یکی از امکانات جالب در پایتون ۳.۷ به بعد اضافه شدن dataclass هست. امروز و در این پست نگاهی به این کتابخوانه میکنیم و از ماژول مورد علاقه خودم برای مدلسازی pydantic هم خواهم گفت.
کلاس داده (Dataclass)
در بسیاری از پروژه ها قالب های داده داریم مثلا شخصی که در سیستم ثبت میشود دارای فیلد های داده مانند نام، نشانی، سن، آدرس ایمیل و … است (جداً برای فیلد هیچ معادل فارسی درستی پیدا نکردم!). یکی از روش های نگهداری و استفاده از این داده ها که ساختار و فیلد های مشخصی دارند استفاده از dataclass است.
در واقع dataclass یک decorator از کتابخانهی dataclasses است. کلاس داده تفاوت یا محدودیتی نسبت به یک کلاس معمولی پایتون ندارد اما میتواند کار را سادهتر کند چون که این دکوریتور خودش توابع __init__()
و __repr__()
را ایجاد میکند.
from dataclasses import dataclass, field
@dataclass
class Person:
name:str
lastname:str
age:int = 0
address:str = ""
children: list["person"] = field(default_factory=list)
کد بالا یک مدل داده برای یک فرد را میسازد. دکوریتور dataclass همراه با توابع دیگر یک تابع init مانند زیر ایجاد میکند:
def __init__(self, name:str, lastname:str, age:int = 0, address="", children=[]):
self.name = name
self.lastname = lastname
self.age = age
...
دقت کنید که هنگام ایجاد کلاس داده استفاده از typehint ضروری است. typehint (راهنمای نوع؟!) یک شیوه نوشتار در پایتون برای اشاره به نوع داده یک متغیر است. مثلا:
age:int
فاروق در همین مورد این مطلب رو نوشته:
استفاده از تابع field در کلاس های داده
همونطور که در مثال بالا آمده برخی فیلدها میتوانند داده پیشفرض داشته باشند (در مثال age, address و children) اما باید دقت کنید که برای داده هایی که اسطلاحاً mutable هستند مانند list, dict ,… برای این که مشکلی پیش نیاد باید از تابع field استفاده کنید تا یک تابع مثلا list()
را هنگام ایجاد یک نمونه صدا بزند و خروجی را در فیلد ذخیره کند (در غیر این صورت یک لیست مشترک بین همه نمونه ها خواهید داشت که میتواند برایتان ایجاد مشکل کند).
from datetime import datetime
@dataclass
class book:
name:str
author:str
was_added_at:datetime = field(default_factory=datetime.now)
owners:list[Person] = field(default_factory=list)
در کد بالا برای فیلد «تاریخ اضافه شدن» هنگام ایجاد یک نمونه تابع now()
صدا زده میشود که تاریخ فعلی را باز میگرداند (البته اگه در ورودی ها تاریخ دیگری داده شد جایگزین میشود)
ماژول pydantic
اگر امکانات بیشتری نیاز داشتید حتما نگاهی به ماژول pydantic بیاندازید. این ماژول کامل با هدف مدلسازی داده و اعتبارسنجی داده هاست. این ماژول امکانات زیادی داره مثل خواندن و خروجی به فرمت های مختلف مثل json، تولید schema و …
جدا از این که با linter
ها و ویرایشگر های کد به خوبی کار میکند در بسیاری از ماژول های دیگر مانند FastAPI, Beanie و … استفاده شده.
from datetime import datetime
from pydantic import BaseModel, PositiveInt
class User(BaseModel):
id: int
name: str = 'John Doe'
signup_ts: datetime | None
tastes: dict[str, PositiveInt]
این ماژول علاوه بر این که همانند یک dataclass به شما امکان دسترسی به فیلد ها مختلف با نوشتار نقطهای میدهد (dot notation) و ویرایشگر کد شما نیز به خوبی شما را راهنمایی میکند، صحت داده ها را میسنجد، مثلا نمیتوانید برای فیلد id که از جنس عدد است یه متن وارد کنید. (البته pydantic دوست داشتنی، رشته "12"
را به عدد تبدیل میکنه و گیر نمیده ولی اجازه نمیده که مثلا "foobar"
ذخیره بشه)
مقایسه pydantic با dataclass
ماژول pydantic تمام نیاز هایی که هنگام استفاده از dataclass دارید را به خوبی پاسخگو هست و به شما بسیاری امکانات بهتر و مفیدتر می دهد، برای مثال تبدیل یک نمونه به JSON و بلعکس به همراه اعتبارسنجی داده ها به سادگی انجام میشود و نوع داده های مختلفی مثل آدرس ایمیل، عدد مثبت و حتی نوع داده سفارشی شما را پشتیبانی میکند. کلی امکانات دیگر نیز هستند که همهی آن ها را در مستندات کامل این ماژول در سایتشون میتونید بخونید.
الگوریتم کولهپشتی، یک الگوریتم از نوع حریصانه هست. در این مطلب در مورد الگوریتم کولهپشتی یک و صفر (0/1 knapsack algorithm) مینویسم. برای مثال فرض کنید یک کوله پشتی با حجم ۹۰ لیتر دارید؛ و وسایلی که دارید علاوه بر حجم برای شما یک ارزش یا اهمیت دارند و احتمالا همه آنها جا نمیشوند. حال به چه صورت وسایل را انتخاب میکنید تا بیشترین ارزش را در کوله پشتی خود داشته باشید؟ در الگوریتم کولهپشتی یک و صفر یا یک شی انتخاب میشود و یا خیر! امکان برش و تکه کردن نیست.
سلام! به مسئلهای برخوردم که نیاز داشت یه آرایه با طول نامعلوم رو از کاربر بگیریم. اینطوری که کاربر شروع میکنه به وارد کردن ورودیها تا زمانی که کلمه end رو بزنه و تموم کنه. مسئله سادهای هست و در کل زیاد چیز شاخی نیست!!
چالشش اینه که ما تعداد اعضا رو نمیدونیم و طول آرایه هم ثابته کنه، پس در حالت عادی مجبوریم ورودیها رو بریزیم تو یه لیست تا آخرش که کار کاربر تموم شد همه رو مثلا منتقل کنیم به یه آرایه با طول لیسته، یعنی داریم دو بار هر عضو رو بررسی میکنیم که هزینه زمانی اینجا میشه 2n(معادل O(n)) از طرفی توی زبانی مثل C که اصلا لیست نیست و باید مثلا از SLL(به انگلیسی: Singly Linked List و به فارسی: فهرست پیوندی یکطرفه) استفاده کرد.
#include <stdio.h>
#include <stdlib.h>
double* rec(int i) {
char input[100]; // Adjust the input string size as needed
fgets(input, sizeof(input), stdin);
if (strcmp(input, "end\n") == 0) {
double* result = (double*)malloc(i * sizeof(double));
return result;
}
double* arr = rec(i + 1);
sscanf(input, "%lf", &arr[i]);
return arr;
}
int main() {
double* result = rec(0);
// Printing the result
for (int i = 0; result[i] != 0.0; ++i) {
printf("%lf ", result[i]);
}
free(result); // Free the allocated memory
return 0;
}
مشابه این کد در پایتون به این شکل نوشته میشود(برای آرایه از numpy استفاده شده).
from numpy import np
def rec(i=0):
inp = input()
if inp == "end":
return np.zeros(i)
arr = rec(i + 1)
arr[i] = int(inp)
return arr
در واقع این شیوه به شکلی هوشمندانه از پشته(به انگلیسی: stack) خود سیستم برای ذخیره موقتی اعضا و شمارش آن ها استفاده میکنه. اما باید دقت کنید که این روش نامحدود هم نیست چون به اندازه پشته محدود میشه.
روبوکد یک بازی برنامهنویسی است که در آن با زبان جاوا، اقدام به برنامهنویسی کردن روباتهای کوچکی میکنید که با بقیهٔ روباتها باید بجنگند. مبارزه میتواند به صورت تکبهتک با یک روبات دیگر یا به صورت گروهی با مثلاً ۹ روبات دیگر باشد. هرچند که باید روباتهای خود را به زبان جاوا بنویسید، اما دانش عمیقی از این زبان مورد نیاز نیست و در صورتی برنامهنویس یکی از زبانها از همین خانواده باشید، میتوانید بهراحتی یک روبات بسازید.
اینکه برای یادگیری برنامهنویسی دانستن زبان انگلیسی لازم هست یا نه، پرسش بسیاری از کسانی هست که میخواهند برنامهنویسی را شروع به یادگیری کنند. در این پست بنده با توجه به تجربهی خودم سعی میکنم به این پرسش جواب دهم. اگر نمیخواهید کل مطلب را بخوانید، جواب کوتاه این پرسش در یک جمله این است که «بله، برای یادگیری برنامهنویسی باید حتما انگلیسی هم یاد بگیرید»