Python Coding Academy
135 subscribers
7 photos
3 files
4 links
🐍 Learn Python. Build Skills. Create the Future.

📚 Python lessons from beginner to advanced
💻 Clear explanations & real-world examples
🚀 Learn to code. Learn to build.
Download Telegram
🐍 آموزش جامع Python — پست ۱۶۵
اعتبارسنجی شرطی و وابسته در JSON
در پست قبل یاد گرفتیم چند خطای اعتبارسنجی را هم‌زمان جمع کنیم.
اما گاهی معتبر بودن یک فیلد به مقدار فیلد دیگری وابسته است.
مثلاً اگر کاربر حالت اعلان‌ها را فعال کند، باید یک email معتبر هم داشته باشد.
🔹 یک قانون وابسته
user = {
"notifications": True,
"email": "ali@example.com"
}

قانون ما:
notifications = True
→ email باید وجود داشته باشد و معتبر باشد

می‌توانیم بنویسیم:
if user.get("notifications") is True:

if "email" not in user:
print("Email is required")

elif not isinstance(user["email"], str):
print("Invalid email")

elif not user["email"].strip():
print("Email cannot be empty")

🔹 اگر اعلان‌ها خاموش باشند
اگر:
user = {
"notifications": False
}

دیگر email اجباری نیست.
if user.get("notifications") is True:
print("Email is required")
else:
print("Email is optional")

نکته مهم این است که برای مقایسه Boolean بهتر است از:
is True

و:
is False

استفاده کنیم.
🔹 چند شرط وابسته
فرض کنیم یک محصول داریم:
product = {
"has_discount": True,
"discount": 20
}

قوانین:
has_discount = True
→ discount اجباری است
→ discount باید عدد باشد
→ discount باید بین 0 تا 100 باشد

has_discount = product.get("has_discount")
discount = product.get("discount")

if has_discount is True:

if "discount" not in product:
print("Discount is required")

elif (
not isinstance(discount, (int, float))
or isinstance(discount, bool)
):
print("Invalid discount")

elif not 0 <= discount <= 100:
print("Invalid discount range")

🔥 جمع‌آوری خطاهای وابسته
می‌توانیم این قوانین را با Validator قبلی ترکیب کنیم:
def validate_product(product):

errors = []

if not isinstance(product, dict):
return ["Product must be a dictionary"]

if "name" not in product:
errors.append("Missing name")

elif not isinstance(product["name"], str) or not product["name"].strip():
errors.append("Invalid name")

if "price" not in product:
errors.append("Missing price")

elif (
not isinstance(product["price"], (int, float))
or isinstance(product["price"], bool)
):
errors.append("Invalid price")

elif not 1 <= product["price"] <= 10000:
errors.append("Invalid price range")

if product.get("has_discount") is True:

if "discount" not in product:
errors.append("Missing discount")

elif (
not isinstance(product["discount"], (int, float))
or isinstance(product["discount"], bool)
):
errors.append("Invalid discount")

elif not 0 <= product["discount"] <= 100:
errors.append("Invalid discount range")

return errors

🔹 مثال
product = {
"name": "Laptop",
"price": 1200,
"has_discount": True
}

errors = validate_product(product)

for error in errors:
print(error)

خروجی:
Missing discount

چون:
has_discount → True

پس discount باید وجود داشته باشد.
⚠️ نکته مهم
این نوع اعتبارسنجی را Conditional Validation می‌نامیم.
یعنی:
اگر A درست بود
→ B اجباری شود

مثلاً:
has_discount = True
↓
discount required

یا:
notifications = True
↓
email required

🧠 خلاصه
در اعتبارسنجی واقعی فقط قوانین مستقل نداریم.
ممکن است یک فیلد بر اساس فیلد دیگر:
اجباری شود.
نوع مشخصی داشته باشد.
محدوده مشخصی داشته باشد.
اصلاً نباید وجود داشته باشد.
الگوی کلی:
شرط اصلی
↓
بررسی فیلد وابسته
↓
بررسی نوع
↓
بررسی مقدار

🎯 تمرین
تابع زیر را کامل کن:
def validate_user(user):

errors = []

# قوانین

return errors

قوانین:
username → اجباری و str و غیرخالی

has_phone → اجباری و bool

اگر has_phone == True:
phone → اجباری و str و غیرخالی

برای هر خطا یک پیام جداگانه به errors اضافه کن.
برای این داده:
user = {
"username": "Ali",
"has_phone": True
}

باید خطای مربوط به نبودن phone گزارش شود.
پست ۱۶۵ از دوره جامع Python 🐍
1
🔐 آموزش امنیت Telegram — پست ویژه
ربات‌هایی که با @username اطلاعات زیادی پیدا می‌کنند
احتمالاً بعضی ربات‌های Telegram را دیده‌اید که فقط با دادن:
@username

اطلاعات زیادی درباره یک کاربر نمایش می‌دهند؛ مثلاً:
نام و اطلاعات عمومی حساب
گروه‌ها و کانال‌هایی که کاربر در آن‌ها دیده شده
پیام‌های عمومی منتسب به کاربر
فعالیت‌های قبلی
اطلاعات مرتبط دیگری که درباره آن حساب جمع‌آوری شده است
این سرویس‌ها واقعاً وجود دارند و ممکن است اطلاعات قابل‌توجهی نمایش دهند.
اما سؤال مهم این است:
این اطلاعات دقیقاً از کجا آمده‌اند؟

🔹 اطلاعات چگونه جمع‌آوری می‌شود؟
یک سرویس می‌تواند اطلاعات را از منابع مختلف جمع کند:
اطلاعات عمومی Telegram
↓
گروه‌ها و کانال‌های قابل دسترسی
↓
پیام‌ها و فعالیت‌های قابل مشاهده
↓
داده‌های جمع‌آوری‌شده در گذشته
↓
منابع و دیتابیس‌های دیگر

مثلاً ممکن است یک سرویس قبلاً اطلاعات تعداد زیادی گروه و کانال را جمع‌آوری کرده باشد.
بعد وقتی شما:
@username

را وارد می‌کنید، سرویس در دیتابیس خودش جست‌وجو می‌کند و اطلاعاتی را که قبلاً درباره آن کاربر جمع شده نمایش می‌دهد.
بنابراین همیشه به این معنی نیست که اطلاعات همین لحظه از حساب کاربر گرفته شده است.
🔹 آیا Bot می‌تواند همه گروه‌های یک کاربر را پیدا کند؟
اینجا یک تفاوت مهم وجود دارد.
یک Bot معمولی صرفاً با داشتن username نمی‌تواند آزادانه فهرست تمام گروه‌هایی را که یک شخص عضو آن‌هاست دریافت کند.
Telegram برای دسترسی به اطلاعات اعضای Chat محدودیت‌هایی دارد؛ برای مثال getChatMember برای سایر کاربران به‌طور تضمینی زمانی در دسترس است که Bot در آن Chat ادمین باشد.
اما اگر یک Bot در یک گروه حضور داشته باشد و دسترسی لازم به پیام‌ها را داشته باشد، می‌تواند فعالیت‌های همان گروه را مشاهده کند.
بنابراین یک سرویس می‌تواند با جمع‌آوری اطلاعات از مکان‌های مختلف، یک پروفایل بزرگ‌تر ایجاد کند.
🔥 اما Private Chat چطور؟
این قسمت خیلی مهم است.
اگر رباتی بگوید:
«فقط username بده تا تمام Private Chatهای این شخص را نشان بدهم.»

این موضوع با قابلیت معمول Bot API فرق دارد.
یک username به‌تنهایی رمز ورود یا مجوز دسترسی به Private Chatهای شخص نیست.
Bot معمولی پیام‌هایی را که برای خودش ارسال می‌شوند و بسته به شرایط پیام‌های Chatهایی را که به آن‌ها دسترسی دارد دریافت می‌کند؛ این با دسترسی آزاد به تمام Private Chatهای یک حساب کاملاً متفاوت است.
پس اگر سرویسی اطلاعاتی از Private Chat نشان می‌دهد، باید منشأ آن اطلاعات را جداگانه بررسی کرد؛ ممکن است داده از تعاملات قبلی، منابع شخص ثالث، دیتابیس‌های جمع‌آوری‌شده یا منابع دیگری آمده باشد.
⚠️ Username با اطلاعات ورود فرق دارد
این دو مورد را با هم اشتباه نگیرید:
@username

با:
Login Code
2FA Password
Session
API Credentials

کاملاً متفاوت است.
داشتن username به معنی دسترسی به حساب نیست.
بنابراین برای ربات‌های ناشناس هرگز این اطلاعات را ارسال نکن:
❌ کد ورود Telegram
❌ رمز Two-Step Verification
❌ Session String
❌ فایل Session
❌ API ID / API Hash
❌ تأیید QR Login ناشناس

🔹 چرا این موضوع مهم است؟
حتی اگر هر اطلاعات به‌تنهایی عمومی باشد، کنار هم قرار گرفتن آن‌ها می‌تواند تصویر نسبتاً دقیقی از فعالیت آنلاین یک شخص ایجاد کند:
Username
↓
گروه‌های قابل مشاهده
↓
پیام‌های عمومی
↓
کانال‌ها و لینک‌های مرتبط
↓
فعالیت‌های قبلی
↓
ساخت یک پروفایل کامل‌تر

به این فرایند در حوزه امنیت و OSINT، تجمیع اطلاعات از منابع مختلف گفته می‌شود.
🛡 برای محافظت از خودمان
✅ اطلاعات حساس را در گروه‌های عمومی منتشر نکنیم.
✅ به Botهای ناشناس اعتماد نکنیم.
✅ کد ورود را برای هیچ Botی ارسال نکنیم.
✅ Session و اطلاعات احراز هویت را در اختیار دیگران قرار ندهیم.
✅ قبل از اضافه کردن Bot به گروه، دسترسی‌های آن را بررسی کنیم.
✅ روی لینک‌های ناشناس ارسال‌شده توسط Botها کلیک نکنیم.

🧠 نکته نهایی
اگر یک ربات با دادن @username اطلاعات زیادی درباره یک شخص نشان می‌دهد، این موضوع می‌تواند واقعی باشد؛ اما لزوماً به معنی این نیست که ربات مستقیماً وارد حساب Telegram شده است.
سؤال اصلی این است:
این اطلاعات از کجا جمع شده، چه مدت ذخیره شده و چه بخش‌هایی عمومی یا قابل‌دسترسی بوده‌اند؟

شناخت این موضوع یکی از بخش‌های مهم امنیت و حریم خصوصی در Telegram است.
آموزش امنیت Telegram — پست ویژه 🔐
1
🐍 آموزش جامع Python — پست ۱۶۶
کار با فایل‌های CSV در Python
تا اینجا با فایل‌های JSON کار کردیم.
حالا یکی از فرمت‌های بسیار رایج برای ذخیره داده‌های جدولی را یاد می‌گیریم:
CSV

CSV مخفف Comma-Separated Values است.
در CSV، اطلاعات معمولاً به شکل سطر و ستون ذخیره می‌شوند.
مثلاً فایل:
users.csv

می‌تواند این محتوا را داشته باشد:
name,age,city
Ali,25,Baku
Sara,22,Tehran
Reza,30,Tabriz

هر خط یک رکورد و هر مقدار بین جداکننده‌ها یک فیلد است.
🔹 خواندن CSV
Python برای کار با CSV یک ماژول داخلی به نام csv دارد:
import csv

with open("users.csv", "r", encoding="utf-8") as file:
reader = csv.reader(file)

for row in reader:
print(row)

خروجی:
['name', 'age', 'city']
['Ali', '25', 'Baku']
['Sara', '22', 'Tehran']
['Reza', '30', 'Tabriz']

دقت کن که هر row یک لیست است.
🔹 دسترسی به ستون‌ها
مثلاً می‌توانیم نام و سن را جدا کنیم:
import csv

with open("users.csv", "r", encoding="utf-8") as file:
reader = csv.reader(file)

for row in reader:
print(row[0], row[1])

خروجی:
name age
Ali 25
Sara 22
Reza 30

🔹 Header چیست؟
در بسیاری از فایل‌های CSV، اولین سطر شامل نام ستون‌هاست:
name,age,city

این سطر را Header می‌نامیم.
می‌توانیم آن را جداگانه دریافت کنیم:
import csv

with open("users.csv", "r", encoding="utf-8") as file:
reader = csv.reader(file)

header = next(reader)

print(header)

for row in reader:
print(row)

خروجی:
['name', 'age', 'city']
['Ali', '25', 'Baku']
['Sara', '22', 'Tehran']
['Reza', '30', 'Tabriz']

next(reader) اولین سطر را مصرف می‌کند؛ بنابراین حلقه از سطر بعدی شروع می‌شود.
⚠️ نکته مهم
مقادیر CSV معمولاً به صورت رشته (str) خوانده می‌شوند.
مثلاً:
print(type(row[1]))

خروجی:
<class 'str'>

پس اگر بخواهیم سن را به‌عنوان عدد استفاده کنیم، باید آن را تبدیل کنیم:
age = int(row[1])

🧠 خلاصه
csv.reader() → خواندن CSV
row → یک سطر از CSV
next(reader) → دریافت سطر بعدی
Header → نام ستون‌ها

CSV برای داده‌های جدولی ساده بسیار کاربردی است؛ در پست بعدی یاد می‌گیریم چگونه CSV را با نام ستون‌ها و به شکل Dictionary بخوانیم.
🎯 تمرین
فایل زیر را بساز:
students.csv

محتوای آن:
name,score
Ali,18
Sara,20
Reza,15

سپس برنامه‌ای بنویس که نام و نمره هر دانش‌آموز را چاپ کند.
خروجی مورد انتظار:
Ali 18
Sara 20
Reza 15

پست ۱۶۶ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۶۷
خواندن CSV به صورت Dictionary با DictReader
در پست قبل با csv.reader() آشنا شدیم.
مشکل reader این است که برای دسترسی به ستون‌ها باید از Index استفاده کنیم:
row[0]
row[1]

در فایل‌های بزرگ، استفاده از نام ستون‌ها خواناتر است.
برای این کار از:
csv.DictReader

استفاده می‌کنیم.
🔹 مثال ساده
فرض کنیم فایل users.csv این محتوا را دارد:
name,age,city
Ali,25,Baku
Sara,22,Tehran
Reza,30,Tabriz

حالا:
import csv

with open("users.csv", "r", encoding="utf-8") as file:
reader = csv.DictReader(file)

for row in reader:
print(row["name"], row["age"], row["city"])

خروجی:
Ali 25 Baku
Sara 22 Tehran
Reza 30 Tabriz

🔹 row چیست؟
هر row یک Dictionary است:
{
"name": "Ali",
"age": "25",
"city": "Baku"
}

بنابراین به‌جای:
row[0]

می‌توانیم بنویسیم:
row["name"]

این روش مخصوصاً برای فایل‌های CSV با ستون‌های زیاد خواناتر است.
🔹 تبدیل مقدارها
همان‌طور که در csv.reader() دیدیم، مقدارها معمولاً str هستند.
مثلاً:
age = int(row["age"])

حالا می‌توانیم عملیات عددی انجام دهیم:
import csv

with open("users.csv", "r", encoding="utf-8") as file:
reader = csv.DictReader(file)

for row in reader:
age = int(row["age"])

if age >= 25:
print(row["name"])

خروجی:
Ali
Reza

🔹 چرا DictReader مفید است؟
مقایسه کن:
row[0]
row[1]
row[2]

با:
row["name"]
row["age"]
row["city"]

روش دوم مشخص‌تر است و اگر ترتیب ستون‌ها تغییر کند، کار با داده‌ها ساده‌تر می‌شود.
⚠️ نکته مهم
اگر نام ستونی را اشتباه بنویسیم:
print(row["username"])

و چنین ستونی در CSV وجود نداشته باشد، با خطای:
KeyError

مواجه می‌شویم.
پس نام ستون‌ها باید با Header فایل مطابقت داشته باشد.
🧠 خلاصه
csv.reader()      → هر سطر به صورت List
csv.DictReader() → هر سطر به صورت Dictionary

row[0] → دسترسی با Index
row["name"] → دسترسی با نام ستون

🎯 تمرین
فایل زیر را بساز:
products.csv

محتوا:
name,price,stock
Laptop,1200,5
Mouse,25,20
Keyboard,70,0

برنامه‌ای بنویس که فقط محصولاتی را چاپ کند که موجودی آن‌ها بیشتر از 0 است.
خروجی مورد انتظار:
Laptop 1200
Mouse 25

پست ۱۶۷ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۶۸
نوشتن داده در CSV با csv.writer و DictWriter
تا اینجا یاد گرفتیم چگونه فایل CSV را بخوانیم.
حالا می‌خواهیم اطلاعات جدید را در یک فایل CSV ایجاد و ذخیره کنیم.
برای این کار می‌توانیم از:
csv.writer

یا:
csv.DictWriter

استفاده کنیم.
🔹 نوشتن با csv.writer
import csv

with open("users.csv", "w", newline="", encoding="utf-8") as file:
writer = csv.writer(file)

writer.writerow(["name", "age", "city"])
writer.writerow(["Ali", 25, "Baku"])
writer.writerow(["Sara", 22, "Tehran"])

فایل users.csv:
name,age,city
Ali,25,Baku
Sara,22,Tehran

در این روش هر سطر را به صورت List می‌نویسیم.
🔹 writerow()
با:
writer.writerow(...)

یک سطر به فایل اضافه می‌کنیم.
مثلاً:
writer.writerow(["Reza", 30, "Tabriz"])

🔹 writerows()
برای نوشتن چند سطر:
users = [
["Ali", 25, "Baku"],
["Sara", 22, "Tehran"],
["Reza", 30, "Tabriz"]
]

with open("users.csv", "w", newline="", encoding="utf-8") as file:
writer = csv.writer(file)

writer.writerow(["name", "age", "city"])
writer.writerows(users)

🔹 DictWriter
اگر داده‌ها را به صورت Dictionary داشته باشیم، DictWriter خواناتر است:
import csv

users = [
{"name": "Ali", "age": 25, "city": "Baku"},
{"name": "Sara", "age": 22, "city": "Tehran"}
]

with open("users.csv", "w", newline="", encoding="utf-8") as file:
fieldnames = ["name", "age", "city"]

writer = csv.DictWriter(
file,
fieldnames=fieldnames
)

writer.writeheader()
writer.writerows(users)

خروجی فایل:
name,age,city
Ali,25,Baku
Sara,22,Tehran

اینجا:
writer.writeheader()

نام ستون‌ها را می‌نویسد.
و:
writer.writerows(users)

Dictionaryها را به سطرهای CSV تبدیل می‌کند.
🔥 تفاوت writer و DictWriter
با csv.writer:
writer.writerow(["Ali", 25, "Baku"])

داده‌ها به صورت List نوشته می‌شوند.
با csv.DictWriter:
writer.writerow({
"name": "Ali",
"age": 25,
"city": "Baku"
})

داده‌ها به صورت Dictionary نوشته می‌شوند.
پس:
csv.writer
→ مناسب داده‌های List

csv.DictWriter
→ مناسب داده‌های Dictionary

اگر داده‌های برنامه‌ات از قبل به شکل Dictionary باشند، DictWriter معمولاً خواناتر و مدیریت آن راحت‌تر است.
🔹 چرا newline=""؟
هنگام کار با csv بهتر است فایل را با:
newline=""

باز کنیم.
این کار باعث می‌شود ماژول csv مدیریت خطوط فایل را به شکل صحیح انجام دهد و از ایجاد خطوط خالی اضافی در بعضی محیط‌ها جلوگیری شود.
⚠️ w و a را اشتباه نکن
"w"

محتوای قبلی فایل را هنگام نوشتن جایگزین می‌کند.
اما:
"a"

برای اضافه کردن داده به انتهای فایل است.
مثلاً:
with open("users.csv", "a", newline="", encoding="utf-8") as file:
writer = csv.writer(file)
writer.writerow(["Reza", 30, "Tabriz"])

🧠 خلاصه
csv.writer()       → نوشتن List
csv.DictWriter() → نوشتن Dictionary

writerow() → یک سطر
writerows() → چند سطر

writeheader() → نوشتن Header

"w" → جایگزینی محتوا
"a" → اضافه کردن به انتهای فایل

🎯 تمرین
فایل زیر را ایجاد کن:
products.csv

و اطلاعات زیر را با DictWriter ذخیره کن:
name,price,stock
Laptop,1200,5
Mouse,25,20
Keyboard,70,10

سعی کن از:
writeheader()
writerows()

استفاده کنی.
پست ۱۶۸ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۶۹
اضافه کردن داده به CSV با DictWriter
در پست قبل یاد گرفتیم با DictWriter اطلاعات را در CSV ذخیره کنیم.
حالا می‌خواهیم داده جدید را به فایل موجود اضافه کنیم؛ بدون اینکه اطلاعات قبلی پاک شوند.
🔹 مشکل حالت w
اگر فایل را با حالت:
open("users.csv", "w")

باز کنیم، محتوای قبلی هنگام نوشتن جایگزین می‌شود.
پس برای اضافه کردن اطلاعات از:
a → append

استفاده می‌کنیم.
🔹 اضافه کردن یک کاربر
فرض کنیم فایل users.csv از قبل این محتوا را دارد:
name,age,city
Ali,25,Baku
Sara,22,Tehran

حالا می‌خواهیم Reza را اضافه کنیم:
import csv

with open("users.csv", "a", newline="", encoding="utf-8") as file:
writer = csv.DictWriter(
file,
fieldnames=["name", "age", "city"]
)

writer.writerow({
"name": "Reza",
"age": 30,
"city": "Tabriz"
})

فایل حالا:
name,age,city
Ali,25,Baku
Sara,22,Tehran
Reza,30,Tabriz

⚠️ Header را دوباره ننویسیم
وقتی از حالت a استفاده می‌کنیم، معمولاً فایل از قبل Header دارد.
بنابراین نباید هر بار این را اجرا کنیم:
writer.writeheader()

وگرنه ممکن است نتیجه‌ای شبیه این ایجاد شود:
name,age,city
Ali,25,Baku
name,age,city
Reza,30,Tabriz

🔹 بررسی وجود فایل
اگر برنامه ممکن است برای اولین بار اجرا شود، بهتر است ابتدا بررسی کنیم فایل وجود دارد یا نه:
from pathlib import Path
import csv

file_path = Path("users.csv")

file_exists = file_path.exists()

with file_path.open(
"a",
newline="",
encoding="utf-8"
) as file:

writer = csv.DictWriter(
file,
fieldnames=["name", "age", "city"]
)

if not file_exists:
writer.writeheader()

writer.writerow({
"name": "Reza",
"age": 30,
"city": "Tabriz"
})

در این حالت:
فایل وجود ندارد → Header ساخته می‌شود
فایل وجود دارد → فقط داده جدید اضافه می‌شود

🔹 اضافه کردن چند رکورد
می‌توانیم چند Dictionary را هم‌زمان اضافه کنیم:
users = [
{"name": "Reza", "age": 30, "city": "Tabriz"},
{"name": "Mina", "age": 27, "city": "Baku"}
]

with file_path.open(
"a",
newline="",
encoding="utf-8"
) as file:

writer = csv.DictWriter(
file,
fieldnames=["name", "age", "city"]
)

if not file_exists:
writer.writeheader()

writer.writerows(users)

🧠 خلاصه
"w" → ایجاد/بازنویسی فایل
"a" → اضافه کردن به انتهای فایل

writeheader()
→ فقط زمانی که Header وجود ندارد

writerow()
→ اضافه کردن یک رکورد

writerows()
→ اضافه کردن چند رکورد

🎯 تمرین
برنامه‌ای بنویس که فایل:
products.csv

را بررسی کند.
اگر فایل وجود نداشت، Header زیر را ایجاد کند:
name,price,stock

سپس محصول زیر را به فایل اضافه کند:
Laptop,1200,5

اگر برنامه را چند بار اجرا کردی، Header نباید هر بار تکرار شود.
پست ۱۶۹ از دوره جامع Python 🐍
1
🐍 آموزش جامع Python — پست ۱۷۰
جست‌وجو و فیلتر داده‌ها در CSV
تا اینجا یاد گرفتیم:
csv.reader       → خواندن CSV به صورت List
csv.DictReader → خواندن CSV به صورت Dictionary
csv.writer → نوشتن List
csv.DictWriter → نوشتن Dictionary

حالا می‌توانیم روی اطلاعات CSV جست‌وجو و فیلتر انجام دهیم.
🔹 مثال ساده
فرض کنیم products.csv این محتوا را دارد:
name,price,stock
Laptop,1200,5
Mouse,25,20
Keyboard,70,0
Monitor,300,8

می‌خواهیم فقط محصولاتی را پیدا کنیم که موجود هستند:
import csv

with open("products.csv", "r", encoding="utf-8") as file:
reader = csv.DictReader(file)

for product in reader:
if int(product["stock"]) > 0:
print(product["name"])

خروجی:
Laptop
Mouse
Monitor

🔹 فیلتر بر اساس قیمت
مثلاً محصولاتی که قیمت آن‌ها کمتر از 100 است:
with open("products.csv", "r", encoding="utf-8") as file:
reader = csv.DictReader(file)

for product in reader:
if float(product["price"]) < 100:
print(product["name"])

خروجی:
Mouse
Keyboard

دقت کن که مقدار CSV رشته است؛ بنابراین برای مقایسه عددی از:
int()
float()

استفاده کردیم.
🔹 ترکیب چند شرط
می‌توانیم چند شرط را هم‌زمان بررسی کنیم:
with open("products.csv", "r", encoding="utf-8") as file:
reader = csv.DictReader(file)

for product in reader:
price = float(product["price"])
stock = int(product["stock"])

if price < 500 and stock > 0:
print(product["name"])

خروجی:
Mouse
Monitor

چون هر دو شرط باید درست باشند.
🔹 ذخیره نتایج فیلترشده
گاهی فقط چاپ کردن کافی نیست و می‌خواهیم نتایج را در یک لیست ذخیره کنیم:
import csv

available_products = []

with open("products.csv", "r", encoding="utf-8") as file:
reader = csv.DictReader(file)

for product in reader:
if int(product["stock"]) > 0:
available_products.append(product)

print(available_products)

حالا available_products شامل Dictionaryهای محصولات موجود است.
⚠️ نکته مهم
قبل از مقایسه عددی، مقدار CSV را به نوع مناسب تبدیل کن:
int(product["stock"])

یا:
float(product["price"])

چون:
"100" > "20"

یک مقایسه رشته‌ای است و نتیجه آن با مقایسه عددی متفاوت است.
🧠 خلاصه
DictReader
↓
خواندن هر سطر به صورت Dictionary
↓
تبدیل مقدارهای عددی
↓
بررسی شرط
↓
فیلتر کردن داده‌ها

🎯 تمرین
فایل زیر را در نظر بگیر:
name,price,stock
Laptop,1200,5
Mouse,25,20
Keyboard,70,0
Monitor,300,8

برنامه‌ای بنویس که فقط محصولاتی را نمایش دهد که:
price < 500
stock > 0

خروجی مورد انتظار:
Mouse
Monitor

پست ۱۷۰ از دوره جامع Python 🐍
1
🐍 آموزش جامع Python — پست ۱۷۱
ویرایش داده‌های CSV
در پست‌های قبل یاد گرفتیم چطور داده‌های CSV را بخوانیم و رکورد جدید اضافه کنیم.
حالا می‌خواهیم یک رکورد موجود را ویرایش کنیم.
مثلاً قیمت یک محصول تغییر کرده است.
🔹 چرا نمی‌توانیم مستقیماً یک سطر را ویرایش کنیم؟
CSV یک فایل متنی ساده است و مثل Database امکان تغییر مستقیم یک رکورد مشخص را ندارد.
روش معمول این است:
خواندن فایل
↓
تغییر داده در Python
↓
نوشتن دوباره فایل

🔹 مثال
فرض کنیم products.csv:
name,price,stock
Laptop,1200,5
Mouse,25,20
Keyboard,70,10

می‌خواهیم قیمت Mouse را از 25 به 30 تغییر دهیم.
ابتدا داده‌ها را می‌خوانیم:
import csv

with open("products.csv", "r", newline="", encoding="utf-8") as file:
reader = csv.DictReader(file)
products = list(reader)

حالا داخل لیست، محصول موردنظر را پیدا می‌کنیم:
for product in products:
if product["name"] == "Mouse":
product["price"] = "30"

در این مرحله داده داخل Python تغییر کرده است.
🔹 نوشتن دوباره فایل
حالا باید اطلاعات جدید را دوباره در CSV ذخیره کنیم:
with open("products.csv", "w", newline="", encoding="utf-8") as file:
fieldnames = ["name", "price", "stock"]

writer = csv.DictWriter(
file,
fieldnames=fieldnames
)

writer.writeheader()
writer.writerows(products)

فایل حالا:
name,price,stock
Laptop,1200,5
Mouse,30,20
Keyboard,70,10

🔹 یک مثال کامل
import csv

file_path = "products.csv"

with open(file_path, "r", newline="", encoding="utf-8") as file:
reader = csv.DictReader(file)
products = list(reader)

for product in products:
if product["name"] == "Mouse":
product["price"] = "30"

with open(file_path, "w", newline="", encoding="utf-8") as file:
fieldnames = ["name", "price", "stock"]

writer = csv.DictWriter(
file,
fieldnames=fieldnames
)

writer.writeheader()
writer.writerows(products)

⚠️ نکته مهم
در CSV، مقدارها هنگام خواندن معمولاً str هستند.
بنابراین:
product["price"] = "30"

در اینجا یک رشته است.
اگر داده را به عدد تبدیل کنیم:
price = float(product["price"])

برای انجام محاسبات مناسب است؛ اما هنگام ذخیره CSV، csv می‌تواند مقدار عددی را نیز به شکل متنی در فایل بنویسد.
🔹 اگر محصول پیدا نشود چه؟
می‌توانیم یک متغیر برای بررسی این موضوع داشته باشیم:
updated = False

for product in products:
if product["name"] == "Mouse":
product["price"] = "30"
updated = True

if updated:
print("Product updated")
else:
print("Product not found")

این روش در برنامه‌های واقعی کاربردی‌تر است.
🧠 خلاصه
برای ویرایش CSV معمولاً:
CSV
↓
DictReader
↓
list
↓
تغییر رکورد
↓
DictWriter
↓
CSV جدید

CSV برای داده‌های ساده و جدولی مناسب است، اما اگر تعداد داده‌ها زیاد شود یا عملیات پیچیده‌ای مثل جست‌وجو، تراکنش و هم‌زمانی داشته باشیم، معمولاً Database انتخاب مناسب‌تری است.
🎯 تمرین
فایل زیر را در نظر بگیر:
name,price,stock
Laptop,1200,5
Mouse,25,20
Keyboard,70,10

برنامه‌ای بنویس که:
محصول Keyboard را پیدا کند.
قیمت آن را از 70 به 80 تغییر دهد.
فایل CSV را دوباره ذخیره کند.
اگر محصول وجود نداشت، عبارت زیر را چاپ کند:
Product not found

پست ۱۷۱ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۷۲
حذف داده از CSV
در پست قبل یاد گرفتیم چگونه یک رکورد CSV را ویرایش کنیم.
حالا می‌خواهیم یک رکورد را حذف کنیم.
چون CSV مثل Database نیست، برای حذف معمولاً این مراحل را انجام می‌دهیم:
خواندن CSV
↓
حذف رکورد از داده‌های Python
↓
نوشتن دوباره CSV

🔹 مثال
فرض کنیم products.csv شامل این اطلاعات است:
name,price,stock
Laptop,1200,5
Mouse,25,20
Keyboard,70,10

می‌خواهیم Mouse را حذف کنیم.
ابتدا فایل را می‌خوانیم:
import csv

with open("products.csv", "r", newline="", encoding="utf-8") as file:
reader = csv.DictReader(file)
products = list(reader)

حالا محصول موردنظر را حذف می‌کنیم:
products = [
product
for product in products
if product["name"] != "Mouse"
]

در نتیجه Mouse از لیست حذف می‌شود.
🔹 ذخیره دوباره فایل
with open("products.csv", "w", newline="", encoding="utf-8") as file:
fieldnames = ["name", "price", "stock"]

writer = csv.DictWriter(
file,
fieldnames=fieldnames
)

writer.writeheader()
writer.writerows(products)

فایل نهایی:
name,price,stock
Laptop,1200,5
Keyboard,70,10

🔹 بررسی اینکه رکورد وجود داشته است
می‌توانیم قبل و بعد از حذف، تعداد رکوردها را مقایسه کنیم:
old_count = len(products)

products = [
product
for product in products
if product["name"] != "Mouse"
]

if len(products) < old_count:
print("Product deleted")
else:
print("Product not found")

اگر محصول وجود داشته باشد:
Product deleted

و اگر وجود نداشته باشد:
Product not found

🔥 مثال کامل
import csv

file_path = "products.csv"

with open(file_path, "r", newline="", encoding="utf-8") as file:
reader = csv.DictReader(file)
products = list(reader)

old_count = len(products)

products = [
product
for product in products
if product["name"] != "Mouse"
]

if len(products) < old_count:

with open(
file_path,
"w",
newline="",
encoding="utf-8"
) as file:

fieldnames = ["name", "price", "stock"]

writer = csv.DictWriter(
file,
fieldnames=fieldnames
)

writer.writeheader()
writer.writerows(products)

print("Product deleted")

else:
print("Product not found")

⚠️ نکته مهم
در این روش ابتدا کل فایل را در حافظه می‌خوانیم:
products = list(reader)

برای فایل‌های کوچک مشکلی نیست.
اما برای فایل‌های بسیار بزرگ، بهتر است معماری مناسب‌تری استفاده کنیم یا از Database استفاده کنیم.
🧠 خلاصه
ویرایش CSV:
خواندن → تغییر → بازنویسی

حذف CSV:
خواندن → حذف → بازنویسی

یعنی CSV امکانات مستقیم UPDATE و DELETE مانند Database ندارد.
🎯 تمرین
فایل زیر را در نظر بگیر:
name,price,stock
Laptop,1200,5
Mouse,25,20
Keyboard,70,10

برنامه‌ای بنویس که:
محصول Keyboard را حذف کند.
فایل را دوباره ذخیره کند.
اگر محصول وجود نداشت، چاپ کند:
Product not found

بعد از اجرای موفق، فایل باید شامل این موارد باشد:
Laptop,1200,5
Mouse,25,20

پست ۱۷۲ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۷۳
جداکننده‌ها در CSV | delimiter
تا اینجا همه فایل‌های CSV ما با کاما جدا می‌شدند:
name,age,city
Ali,25,Baku
Sara,22,Tehran

اما در دنیای واقعی ممکن است فایل‌ها از جداکننده‌های دیگری استفاده کنند.
مثلاً:
name;age;city
Ali;25;Baku
Sara;22;Tehran

یا:
name|age|city
Ali|25|Baku

برای مشخص کردن جداکننده از پارامتر:
delimiter

استفاده می‌کنیم.
🔹 خواندن CSV با ;
اگر فایل این‌طور باشد:
name;age;city
Ali;25;Baku
Sara;22;Tehran

باید بنویسیم:
import csv

with open("users.csv", "r", encoding="utf-8") as file:
reader = csv.DictReader(
file,
delimiter=";"
)

for row in reader:
print(row["name"], row["city"])

خروجی:
Ali Baku
Sara Tehran

🔹 نوشتن CSV با جداکننده دلخواه
همین موضوع برای DictWriter هم وجود دارد:
import csv

users = [
{"name": "Ali", "age": 25},
{"name": "Sara", "age": 22}
]

with open(
"users.csv",
"w",
newline="",
encoding="utf-8"
) as file:

writer = csv.DictWriter(
file,
fieldnames=["name", "age"],
delimiter=";"
)

writer.writeheader()
writer.writerows(users)

فایل ایجادشده:
name;age
Ali;25
Sara;22

🔹 delimiter فقط برای کاما نیست
می‌توانیم از جداکننده‌های مختلف استفاده کنیم:
delimiter=","

یا:
delimiter=";"

یا حتی:
delimiter="|"

البته باید فایل را مطابق همان فرمت بخوانیم.
⚠️ نکته مهم
اگر جداکننده فایل ; باشد ولی ما از حالت پیش‌فرض , استفاده کنیم، داده‌ها درست به ستون‌های مختلف تقسیم نمی‌شوند.
مثلاً:
name;age;city

اگر با delimiter="," بخوانیم، Python این خط را عملاً یک فیلد در نظر می‌گیرد.
پس هنگام خواندن CSV باید ساختار واقعی فایل را بدانیم.
🔹 جداکننده با داده داخل متن
فرض کنیم یک مقدار خودش شامل کاما باشد:
name,description
Laptop,"Fast, powerful computer"

ماژول csv می‌تواند این مقدار را به‌درستی مدیریت کند:
import csv

with open(
"products.csv",
"r",
encoding="utf-8"
) as file:

reader = csv.DictReader(file)

for row in reader:
print(row["description"])

خروجی:
Fast, powerful computer

یعنی نباید CSV را با split(",") به‌صورت دستی تجزیه کنیم؛ چون CSV می‌تواند قوانین مربوط به Quote و delimiter را داشته باشد.
🧠 خلاصه
delimiter="," → جداکننده کاما
delimiter=";" → جداکننده نقطه‌ویرگول
delimiter="|" → جداکننده Pipe

و:
csv.reader / DictReader
↓
خواندن CSV با ساختار صحیح

csv.writer / DictWriter
↓
نوشتن CSV با ساختار صحیح

🎯 تمرین
فایل زیر را در نظر بگیر:
name;price;stock
Laptop;1200;5
Mouse;25;20
Keyboard;70;10

برنامه‌ای بنویس که:
فایل را با DictReader بخواند.
از delimiter=";" استفاده کند.
نام و قیمت محصولات را چاپ کند.
خروجی:
Laptop 1200
Mouse 25
Keyboard 70

پست ۱۷۳ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۷۴
مدیریت Quote و Escape در CSV
در پست قبل با delimiter آشنا شدیم.
اما یک سؤال مهم وجود دارد:
اگر خود داده شامل کاما یا جداکننده باشد، Python چطور تشخیص می‌دهد که آن کاما بخشی از متن است یا جداکننده ستون‌ها؟
برای این کار CSV از Quote استفاده می‌کند.
🔹 مشکل بدون Quote
فرض کنیم اطلاعات یک محصول این باشد:
name,description
Laptop,Fast, powerful computer

اینجا مشخص نیست:
Fast, powerful computer

یک مقدار است یا دو ستون جدا.
🔹 استفاده از Quote
در CSV می‌توانیم مقدار را داخل " " قرار دهیم:
name,description
Laptop,"Fast, powerful computer"

حالا Python می‌فهمد که کامای داخل " " بخشی از مقدار description است.
🔹 خواندن با csv
import csv

with open(
"products.csv",
"r",
encoding="utf-8"
) as file:

reader = csv.DictReader(file)

for row in reader:
print(row["name"])
print(row["description"])

خروجی:
Laptop
Fast, powerful computer

🔹 نوشتن داده‌ای که کاما دارد
اگر با csv.writer یا csv.DictWriter بنویسیم، Python خودش Quote مناسب را مدیریت می‌کند:
import csv

products = [
{
"name": "Laptop",
"description": "Fast, powerful computer"
},
{
"name": "Mouse",
"description": "Small, wireless mouse"
}
]

with open(
"products.csv",
"w",
newline="",
encoding="utf-8"
) as file:

writer = csv.DictWriter(
file,
fieldnames=["name", "description"]
)

writer.writeheader()
writer.writerows(products)

فایل CSV به شکل مناسب ذخیره می‌شود:
name,description
Laptop,"Fast, powerful computer"
Mouse,"Small, wireless mouse"

🔹 اگر خود متن شامل " باشد چه؟
مثلاً:
He said "Hello"

در CSV برای نمایش " داخل یک مقدار، معمولاً از دو Quote استفاده می‌شود:
"He said ""Hello"""

ماژول csv این جزئیات را هنگام خواندن و نوشتن مدیریت می‌کند.
⚠️ نکته مهم
به همین دلیل بهتر است CSV را با:
csv.reader()
csv.writer()
csv.DictReader()
csv.DictWriter()

مدیریت کنیم.
استفاده از:
line.split(",")

برای CSVهای واقعی قابل اعتماد نیست؛ چون ممکن است داده‌ها شامل:
کاما
Quote
جداکننده‌های مختلف
باشند.
🧠 خلاصه
delimiter → جداکننده ستون‌ها

"..." → مشخص کردن یک مقدار شامل delimiter

"" داخل مقدار → با Quote اضافی مدیریت می‌شود

csv module → مدیریت صحیح قوانین CSV

🎯 تمرین
داده زیر را در نظر بگیر:
name,description
Phone,"Large screen, fast processor"
Laptop,"Lightweight, powerful"

برنامه‌ای بنویس که با DictReader فایل را بخواند و فقط description هر محصول را چاپ کند.
خروجی:
Large screen, fast processor
Lightweight, powerful

پست ۱۷۴ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۷۵
کنترل Quote در CSV با quoting
در پست قبل دیدیم که Python چگونه داده‌هایی را که شامل کاما یا " هستند، در CSV مدیریت می‌کند.
حالا می‌توانیم مشخص کنیم چه زمانی مقدارها داخل Quote قرار بگیرند.
برای این کار از پارامتر:
quoting

استفاده می‌کنیم.
🔹 csv.QUOTE_MINIMAL
حالت پیش‌فرض csv است.
Python فقط زمانی از Quote استفاده می‌کند که لازم باشد.
import csv

with open(
"products.csv",
"w",
newline="",
encoding="utf-8"
) as file:

writer = csv.writer(
file,
quoting=csv.QUOTE_MINIMAL
)

writer.writerow(["Laptop", 1200])
writer.writerow(["Mouse", "Fast, wireless"])

خروجی:
Laptop,1200
Mouse,"Fast, wireless"

چون ردیف اول به Quote نیاز ندارد، اما ردیف دوم شامل کاماست.
🔹 csv.QUOTE_ALL
با این حالت، تمام مقدارها داخل Quote نوشته می‌شوند:
import csv

with open(
"products.csv",
"w",
newline="",
encoding="utf-8"
) as file:

writer = csv.writer(
file,
quoting=csv.QUOTE_ALL
)

writer.writerow(["Laptop", 1200])
writer.writerow(["Mouse", "Fast, wireless"])

خروجی:
"Laptop","1200"
"Mouse","Fast, wireless"

🔹 csv.QUOTE_NONNUMERIC
در این حالت مقدارهای متنی Quote می‌شوند و مقدارهای عددی بدون Quote نوشته می‌شوند:
import csv

with open(
"products.csv",
"w",
newline="",
encoding="utf-8"
) as file:

writer = csv.writer(
file,
quoting=csv.QUOTE_NONNUMERIC
)

writer.writerow(["Laptop", 1200])

خروجی:
"Laptop",1200

🔹 csv.QUOTE_NONE
در این حالت Python به‌صورت معمول Quote اضافه نمی‌کند.
اگر داده شامل delimiter باشد، باید آن را به شکل مناسب Escape کنیم؛ در غیر این صورت ممکن است خطا ایجاد شود.
برای CSVهای معمولی، معمولاً نیازی به استفاده از این حالت نداریم.
🧠 مقایسه
QUOTE_MINIMAL
→ فقط وقتی لازم باشد Quote می‌گذارد.

QUOTE_ALL
→ همه مقدارها را Quote می‌کند.

QUOTE_NONNUMERIC
→ مقدارهای غیرعددی را Quote می‌کند.

QUOTE_NONE
→ Quote خودکار را غیرفعال می‌کند.

⚠️ نکته مهم
در بیشتر پروژه‌ها لازم نیست quoting را دستی تنظیم کنیم.
حالت پیش‌فرض:
csv.QUOTE_MINIMAL

برای بسیاری از فایل‌های CSV کافی است.
تنظیم quoting زمانی مفید است که فرمت خروجی CSV مشخص و اجباری باشد.
🎯 تمرین
کد زیر را تغییر بده تا تمام مقدارهای CSV داخل Quote نوشته شوند:
import csv

with open(
"products.csv",
"w",
newline="",
encoding="utf-8"
) as file:

writer = csv.writer(file)

writer.writerow(["Laptop", 1200])
writer.writerow(["Mouse", 25])

فایل خروجی باید شبیه این باشد:
"Laptop","1200"
"Mouse","25"

پست ۱۷۵ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۷۶
مدیریت فایل‌های CSV با DictReader و DictWriter در یک برنامه کامل
تا اینجا یاد گرفتیم:
CSV را بخوانیم.
داده جدید اضافه کنیم.
داده‌ها را فیلتر کنیم.
رکوردها را ویرایش و حذف کنیم.
delimiter و quoting را مدیریت کنیم.
حالا یک برنامه کوچک می‌سازیم که چند عملیات را روی یک فایل CSV انجام دهد.
🔹 ساخت فایل اولیه
ابتدا یک فایل به نام:
products.csv

می‌سازیم:
import csv

products = [
{"name": "Laptop", "price": 1200, "stock": 5},
{"name": "Mouse", "price": 25, "stock": 20},
{"name": "Keyboard", "price": 70, "stock": 10}
]

with open(
"products.csv",
"w",
newline="",
encoding="utf-8"
) as file:

writer = csv.DictWriter(
file,
fieldnames=["name", "price", "stock"]
)

writer.writeheader()
writer.writerows(products)

🔹 خواندن اطلاعات
حالا فایل را می‌خوانیم:
with open(
"products.csv",
"r",
encoding="utf-8"
) as file:

reader = csv.DictReader(file)

for product in reader:
print(product)

هر ردیف به شکل یک Dictionary در اختیار ما قرار می‌گیرد.
مثلاً:
{
'name': 'Laptop',
'price': '1200',
'stock': '5'
}

⚠️ توجه کن که مقدارهای CSV هنگام خواندن معمولاً str هستند.
🔹 تبدیل مقدارهای عددی
اگر بخواهیم روی قیمت محاسبه انجام دهیم:
with open(
"products.csv",
"r",
encoding="utf-8"
) as file:

reader = csv.DictReader(file)

for product in reader:
price = float(product["price"])
stock = int(product["stock"])

print(
product["name"],
price,
stock
)

🔹 فیلتر کردن محصولات
مثلاً فقط محصولاتی را نمایش دهیم که موجود هستند:
with open(
"products.csv",
"r",
encoding="utf-8"
) as file:

reader = csv.DictReader(file)

for product in reader:
if int(product["stock"]) > 0:
print(product["name"])

خروجی:
Laptop
Mouse
Keyboard

🔹 یک نکته مهم درباره reader
این دو روش را با هم اشتباه نکن:
csv.reader()

هر ردیف را به شکل List می‌دهد:
["Laptop", "1200", "5"]

اما:
csv.DictReader()

هر ردیف را به شکل Dictionary می‌دهد:
{
"name": "Laptop",
"price": "1200",
"stock": "5"
}

برای فایل‌هایی که ستون‌های مشخص دارند، DictReader معمولاً خواندن و کار با داده‌ها را واضح‌تر می‌کند.
🧠 خلاصه
DictReader
↓
CSV → Dictionary

DictWriter
↓
Dictionary → CSV

و اگر مقدار عددی باشد:
int(product["stock"])
float(product["price"])

چون CSV خودش نوع داده‌های Python را حفظ نمی‌کند و مقادیر را هنگام خواندن معمولاً به صورت متن در اختیار ما قرار می‌دهد.
🎯 تمرین
برنامه‌ای بنویس که:
فایل products.csv را با DictReader بخواند.
فقط محصولاتی را نمایش دهد که:
قیمت کمتر از 100 دارند.
موجودی بیشتر از 0 دارند.
قیمت را با float() و موجودی را با int() تبدیل کند.
با این داده‌ها:
name,price,stock
Laptop,1200,5
Mouse,25,20
Keyboard,70,10
Monitor,300,0

خروجی باید شامل:
Mouse
Keyboard

باشد.
پست ۱۷۶ از دوره جامع Python 🐍
👍1
🐍 آموزش جامع Python — پست ۱۷۷
مدیریت خطاهای تبدیل داده در CSV
در CSV تقریباً همه مقدارها هنگام خواندن به شکل str در اختیار ما قرار می‌گیرند.
مثلاً:
name,price,stock
Laptop,1200,5
Mouse,25,20
Keyboard,unknown,10

اگر بخواهیم price را به float تبدیل کنیم:
price = float(product["price"])

برای مقدار:
unknown

با خطای:
ValueError

مواجه می‌شویم.
🔹 استفاده از try و except
می‌توانیم تبدیل داده را داخل try قرار دهیم:
import csv

with open(
"products.csv",
"r",
encoding="utf-8"
) as file:

reader = csv.DictReader(file)

for product in reader:

try:
price = float(product["price"])
stock = int(product["stock"])

print(
product["name"],
price,
stock
)

except ValueError:
print(
f"Invalid data: {product['name']}"
)

اگر یکی از مقدارها قابل تبدیل نباشد، برنامه متوقف نمی‌شود و except اجرا می‌شود.
🔹 مثال با داده نامعتبر
فرض کنیم CSV این باشد:
name,price,stock
Laptop,1200,5
Mouse,25,20
Keyboard,unknown,10
Monitor,300,0

خروجی:
Laptop 1200.0 5
Mouse 25.0 20
Invalid data: Keyboard
Monitor 300.0 0

پس فقط رکورد نامعتبر رد می‌شود و پردازش بقیه داده‌ها ادامه پیدا می‌کند.
🔹 مدیریت جداگانه قیمت و موجودی
گاهی بهتر است بدانیم کدام ستون مشکل دارد:
try:
price = float(product["price"])
except ValueError:
print(f"Invalid price: {product['name']}")
continue

try:
stock = int(product["stock"])
except ValueError:
print(f"Invalid stock: {product['name']}")
continue

در اینجا:
continue

باعث می‌شود پردازش همین رکورد متوقف شود و حلقه سراغ رکورد بعدی برود.
🔹 بررسی مقدار خالی
ممکن است مقدار یک ستون کاملاً خالی باشد:
name,price,stock
Laptop,,5

در این حالت:
float("")

باعث ValueError می‌شود.
می‌توانیم قبل از تبدیل بررسی کنیم:
price_text = product["price"].strip()

if not price_text:
print(f"Price is missing: {product['name']}")
continue

try:
price = float(price_text)
except ValueError:
print(f"Invalid price: {product['name']}")
continue

⚠️ نکته مهم
برای داده‌های CSV فقط این کافی نیست:
price = float(product["price"])

چون داده ممکن است:
خالی
متنی
اشتباه

باشد.
بهتر است هنگام ورود داده به برنامه، آن را اعتبارسنجی و تبدیل کنیم.
🧠 الگوی پیشنهادی
برای CSV می‌توانیم این الگو را داشته باشیم:
CSV
↓
خواندن داده
↓
بررسی وجود مقدار
↓
تبدیل نوع
↓
مدیریت ValueError
↓
استفاده از داده معتبر

مثلاً:
try:
price = float(product["price"])
except ValueError:
print("Invalid price")
continue

🎯 تمرین
فایل زیر را در نظر بگیر:
name,price,stock
Laptop,1200,5
Mouse,25,20
Keyboard,unknown,10
Monitor,,15
Phone,800,invalid

برنامه‌ای بنویس که:
CSV را با DictReader بخواند.
price را به float تبدیل کند.
stock را به int تبدیل کند.
خطاهای ValueError را مدیریت کند.
رکوردهای نامعتبر را رد کند.
فقط محصولات معتبر را چاپ کند.
خروجی معتبر باید شامل:
Laptop
Mouse

باشد.
پست ۱۷۷ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۷۸
تشخیص خودکار ساختار CSV با csv.Sniffer
گاهی نمی‌دانیم یک فایل CSV با چه جداکننده‌ای ساخته شده است.
ممکن است فایل با:
,

یا:
;

یا:
|

جدا شده باشد.
در چنین شرایطی می‌توانیم از:
csv.Sniffer

استفاده کنیم.
🔹 تشخیص delimiter
فرض کنیم فایل ما این باشد:
name;price;stock
Laptop;1200;5
Mouse;25;20
Keyboard;70;10

اما نمی‌دانیم جداکننده ; است.
می‌توانیم از Sniffer استفاده کنیم:
import csv

with open(
"products.csv",
"r",
encoding="utf-8"
) as file:

sample = file.read(1024)

dialect = csv.Sniffer().sniff(
sample,
delimiters=",;|"
)

print(dialect.delimiter)

خروجی:
;

Python توانسته جداکننده را از محتوای فایل تشخیص دهد.
🔹 استفاده از جداکننده تشخیص‌داده‌شده
حالا می‌توانیم همان dialect را به DictReader بدهیم:
import csv

with open(
"products.csv",
"r",
encoding="utf-8"
) as file:

sample = file.read(1024)

dialect = csv.Sniffer().sniff(
sample,
delimiters=",;|"
)

file.seek(0)

reader = csv.DictReader(
file,
dialect=dialect
)

for product in reader:
print(product["name"])

خروجی:
Laptop
Mouse
Keyboard

🔹 چرا file.seek(0)؟
در این قسمت:
sample = file.read(1024)

ما ۱۰۲۴ کاراکتر از فایل را می‌خوانیم.
مکان فعلی فایل دیگر ابتدای فایل نیست.
بنابراین:
file.seek(0)

مکان خواندن را به ابتدای فایل برمی‌گرداند.
بعد می‌توانیم فایل را کامل با DictReader بخوانیم.
🔹 تشخیص Header
Sniffer قابلیت دیگری هم دارد.
می‌توانیم از:
has_header()

استفاده کنیم:
import csv

with open(
"products.csv",
"r",
encoding="utf-8"
) as file:

sample = file.read(1024)

has_header = csv.Sniffer().has_header(sample)

print(has_header)

ممکن است خروجی:
True

باشد.
یعنی Sniffer تشخیص داده که احتمالاً فایل دارای Header است.
⚠️ نکته مهم
Sniffer همیشه نمی‌تواند با اطمینان کامل ساختار فایل را تشخیص دهد.
مثلاً اگر فایل خیلی کوچک یا نامنظم باشد، ممکن است تشخیص اشتباه انجام شود.
پس:
csv.Sniffer()

یک ابزار تشخیص احتمالی است، نه تضمینی.
اگر ساختار CSV را از قبل می‌دانیم، بهتر است مستقیماً بنویسیم:
reader = csv.DictReader(
file,
delimiter=";"
)

🧠 خلاصه
csv.Sniffer().sniff()
↓
تشخیص Dialect / delimiter

file.seek(0)
↓
بازگشت به ابتدای فایل

csv.Sniffer().has_header()
↓
تشخیص احتمالی وجود Header

🎯 تمرین
فایل زیر را در نظر بگیر:
name|price|stock
Laptop|1200|5
Mouse|25|20
Keyboard|70|10

برنامه‌ای بنویس که:
فایل را باز کند.
با csv.Sniffer().sniff() جداکننده را تشخیص دهد.
فایل را با seek(0) به ابتدا برگرداند.
با DictReader اطلاعات را بخواند.
نام محصولات را چاپ کند.
خروجی:
Laptop
Mouse
Keyboard

پست ۱۷۸ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۷۹
مثال کامل و مقاوم در برابر خطا برای CSV
حالا چند مفهوم CSV را در یک برنامه واقعی ترکیب می‌کنیم:
بررسی وجود فایل
تشخیص delimiter
بررسی Header
تبدیل price و stock
مدیریت خطاهای تبدیل
رد کردن رکوردهای نامعتبر
🔹 فایل نمونه
name;price;stock
Laptop;1200;5
Mouse;25;20
Keyboard;unknown;10
Monitor;300;invalid
Phone;800;15

🔹 برنامه کامل
import csv
from pathlib import Path


file_path = Path("products.csv")

try:
if not file_path.exists():
raise FileNotFoundError("File not found")

with file_path.open(
"r",
encoding="utf-8",
newline=""
) as file:

sample = file.read(1024)

if not sample.strip():
raise ValueError("CSV file is empty")

try:
dialect = csv.Sniffer().sniff(
sample,
delimiters=",;|"
)
except csv.Error:
print("Could not detect delimiter")
raise SystemExit

file.seek(0)

reader = csv.DictReader(
file,
dialect=dialect
)

required = {"name", "price", "stock"}

if not required.issubset(
set(reader.fieldnames or [])
):
print("Required columns are missing")
raise SystemExit

for row_number, product in enumerate(
reader,
start=2
):
try:
name = product["name"].strip()
price = float(product["price"])
stock = int(product["stock"])

if not name or price < 0 or stock < 0:
raise ValueError("Invalid data")

print(
f"{name} - ${price} - Stock: {stock}"
)

except (ValueError, TypeError):
print(
f"Invalid row: {row_number}"
)

except FileNotFoundError:
print("File not found")

except PermissionError:
print("Permission denied")

except UnicodeDecodeError:
print("Invalid file encoding")

except csv.Error as error:
print(f"CSV error: {error}")

🔹 نتیجه
رکوردهای معتبر پردازش می‌شوند:
Laptop - $1200.0 - Stock: 5
Mouse - $25.0 - Stock: 20
Phone - $800.0 - Stock: 15

و رکوردهای خراب فقط گزارش می‌شوند:
Invalid row: 4
Invalid row: 5

برنامه به خاطر یک رکورد خراب متوقف نمی‌شود.
🧠 الگوی کلی
فایل
↓
بررسی ساختار
↓
خواندن CSV
↓
تبدیل نوع داده
↓
اعتبارسنجی
↓
مدیریت خطا
↓
استفاده از داده معتبر

⚠️ اگر delimiter را از قبل می‌دانیم، بهتر است به‌جای Sniffer مستقیماً آن را مشخص کنیم:
csv.DictReader(file, delimiter=";")

🎯 تمرین
کد را تغییر بده تا ستون category را هم بررسی کند و اگر خالی بود، رکورد را نامعتبر اعلام کند.
پست ۱۷۹ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۸۰
تبدیل CSV به JSON
تا اینجا با خواندن، نوشتن، ویرایش، حذف و اعتبارسنجی داده‌های CSV آشنا شدیم.
حالا می‌خواهیم داده‌های CSV را به JSON تبدیل کنیم.
این کار زمانی مفید است که داده را از یک فایل جدولی به ساختاری مناسب برای برنامه‌ها و APIها منتقل کنیم.
🔹 فایل CSV
فرض کنیم products.csv این باشد:
name,price,stock
Laptop,1200,5
Mouse,25,20
Keyboard,70,10

ابتدا CSV را با DictReader می‌خوانیم:
import csv

with open(
"products.csv",
"r",
encoding="utf-8"
) as file:

reader = csv.DictReader(file)

products = list(reader)

حالا:
print(products)

تقریباً:
[
{'name': 'Laptop', 'price': '1200', 'stock': '5'},
{'name': 'Mouse', 'price': '25', 'stock': '20'},
{'name': 'Keyboard', 'price': '70', 'stock': '10'}
]

⚠️ توجه کن که مقدارها هنوز str هستند.
🔹 تبدیل نوع داده
قبل از تبدیل به JSON بهتر است نوع داده‌های عددی را اصلاح کنیم:
for product in products:
product["price"] = float(product["price"])
product["stock"] = int(product["stock"])

حالا می‌توانیم داده را به JSON تبدیل کنیم:
import json

json_data = json.dumps(
products,
indent=4,
ensure_ascii=False
)

print(json_data)

خروجی:
[
{
"name": "Laptop",
"price": 1200.0,
"stock": 5
},
{
"name": "Mouse",
"price": 25.0,
"stock": 20
}
]

🔹 ذخیره JSON در فایل
می‌توانیم نتیجه را مستقیماً در یک فایل ذخیره کنیم:
with open(
"products.json",
"w",
encoding="utf-8"
) as file:

json.dump(
products,
file,
indent=4,
ensure_ascii=False
)

حالا یک فایل به نام:
products.json

داریم.
⚠️ مدیریت خطا
اگر CSV شامل مقدار نامعتبر باشد:
name,price,stock
Laptop,unknown,5

تبدیل:
float("unknown")

باعث ValueError می‌شود.
پس در برنامه واقعی بهتر است:
try:
product["price"] = float(product["price"])
product["stock"] = int(product["stock"])

except ValueError:
print("Invalid product data")

را در نظر بگیریم.
🧠 خلاصه
CSV
↓
DictReader
↓
Dictionary
↓
تبدیل نوع داده
↓
JSON
↓
json.dump()

🎯 تمرین
فایل products.csv را به products.json تبدیل کن.
شرایط:
name به صورت str
price به صورت float
stock به صورت int
رکوردهای دارای داده نامعتبر نادیده گرفته شوند.
پست ۱۸۰ از دوره جامع Python 🐍
🤖 معرفی چند پروژه و ابزار جالب در حوزه AI
اگر به دنبال پروژه‌های جدید و متن‌باز در حوزه هوش مصنوعی هستید، این دو مورد را هم می‌توانید بررسی کنید:
🔹 JEV
🌐 وب‌سایت:
typesafe.ai
JEV یک پروژه/پلتفرم در حوزه AI است که می‌توانید برای آشنایی بیشتر با قابلیت‌ها و نحوه استفاده از آن، وب‌سایت رسمی آن را بررسی کنید.
🔗 لینک:
https://typesafe.ai
🔹 LAYA
یک پروژه متن‌باز مرتبط با اجرای مدل‌های هوش مصنوعی و اکوسیستم MLX.
💻 GitHub:
Laya — GitHub
🤗 Hugging Face:
Laya — Hugging Face
اگر به مدل‌های AI، اجرای مدل‌ها و پروژه‌های متن‌باز علاقه دارید، بررسی Repository و فایل‌های پروژه می‌تواند اطلاعات بیشتری درباره نحوه استفاده و قابلیت‌های آن ارائه دهد.
📌 لینک‌ها
🔹 JEV:
typesafe.ai
🔹 LAYA — GitHub:
mizorewww/laya-mlx
🔹 LAYA — Hugging Face:
aac6fef
اگر پروژه‌های AI متن‌باز و ابزارهای جدید هوش مصنوعی را دنبال می‌کنید، این موارد می‌توانند برای بررسی و یادگیری جالب باشند. 🤖
🐍 آموزش جامع Python — پست ۱۸۱
آشنایی با دیتابیس SQLite در Python
تا اینجا اطلاعات را در فایل‌هایی مثل:
CSV
JSON

ذخیره و مدیریت کردیم.
اما وقتی حجم داده بیشتر شود، جست‌وجو، ویرایش و حذف اطلاعات در فایل‌ها می‌تواند سخت‌تر شود.
اینجاست که Database وارد می‌شود.
یکی از ساده‌ترین دیتابیس‌ها برای شروع در Python، SQLite است.
🔹 SQLite چیست؟
SQLite یک دیتابیس سبک و فایل‌محور است.
برخلاف بعضی دیتابیس‌ها، برای شروع نیاز نداریم یک Server جداگانه نصب و اجرا کنیم.
Python نیز ماژول استاندارد:
sqlite3

را در اختیارمان قرار می‌دهد.
🔹 ساخت اولین دیتابیس
import sqlite3

connection = sqlite3.connect("users.db")

print("Database created")

connection.close()

با اجرای این کد، فایل:
users.db

ایجاد می‌شود.
اگر فایل از قبل وجود داشته باشد، SQLite همان دیتابیس را باز می‌کند.
🔹 Connection چیست؟
این خط:
connection = sqlite3.connect("users.db")

یک Connection به دیتابیس ایجاد می‌کند.
از طریق این Connection می‌توانیم:
دستور SQL اجرا کنیم
داده اضافه کنیم
داده بخوانیم
داده تغییر دهیم
داده حذف کنیم

در پایان نیز بهتر است Connection را ببندیم:
connection.close()

🔹 ساخت Table
برای ذخیره اطلاعات، ابتدا یک جدول ایجاد می‌کنیم.
import sqlite3

connection = sqlite3.connect("users.db")

cursor = connection.cursor()

cursor.execute("""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT,
age INTEGER
)
""")

connection.commit()
connection.close()

در اینجا جدول:
users

ساخته می‌شود.
و سه ستون دارد:
id    → INTEGER
name → TEXT
age → INTEGER

🔹 cursor چیست؟
با:
cursor = connection.cursor()

یک Cursor ایجاد می‌کنیم.
Cursor برای اجرای دستورات SQL استفاده می‌شود:
cursor.execute(...)

مثلاً:
cursor.execute("SELECT * FROM users")

⚠️ commit() را فراموش نکن
بعد از تغییرات دیتابیس معمولاً باید تغییرات را ثبت کنیم:
connection.commit()

مثلاً هنگام:
INSERT
UPDATE
DELETE

استفاده از commit() اهمیت دارد.
🧠 خلاصه
sqlite3.connect()
↓
Connection
↓
Cursor
↓
cursor.execute()
↓
connection.commit()
↓
connection.close()

در پست بعد یاد می‌گیریم چگونه با INSERT اطلاعات را داخل SQLite ذخیره کنیم.
🎯 تمرین
برنامه‌ای بنویس که:
یک دیتابیس به نام school.db ایجاد کند.
جدولی به نام students بسازد.
جدول شامل این ستون‌ها باشد:
id     → INTEGER PRIMARY KEY
name → TEXT
score → REAL

از:
CREATE TABLE IF NOT EXISTS

استفاده کن.
پست ۱۸۱ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۸۲
درج چند رکورد با executemany()
در پست قبل یاد گرفتیم با INSERT یک رکورد را داخل SQLite ذخیره کنیم.
اما اگر بخواهیم چند رکورد را هم‌زمان اضافه کنیم، استفاده از چندین execute() کار چندان مناسبی نیست.
برای این کار می‌توانیم از:
executemany()

استفاده کنیم.
🔹 مثال ساده
فرض کنیم جدول زیر را داریم:
import sqlite3

connection = sqlite3.connect("users.db")
cursor = connection.cursor()

cursor.execute("""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT,
age INTEGER
)
""")

حالا چند کاربر داریم:
users = [
("Ali", 25),
("Sara", 22),
("Reza", 30)
]

می‌توانیم همه را با یک دستور درج کنیم:
cursor.executemany(
"INSERT INTO users (name, age) VALUES (?, ?)",
users
)

connection.commit()

🔹 executemany() چگونه کار می‌کند؟
این کد:
cursor.executemany(
"INSERT INTO users (name, age) VALUES (?, ?)",
users
)

عبارت SQL را برای هر عضو users اجرا می‌کند:
("Ali", 25)
("Sara", 22)
("Reza", 30)

یعنی تقریباً مثل این است:
cursor.execute(
"INSERT INTO users (name, age) VALUES (?, ?)",
("Ali", 25)
)

cursor.execute(
"INSERT INTO users (name, age) VALUES (?, ?)",
("Sara", 22)
)

cursor.execute(
"INSERT INTO users (name, age) VALUES (?, ?)",
("Reza", 30)
)

اما executemany() برای درج مجموعه‌ای از رکوردها مناسب‌تر و خواناتر است.
🔹 مثال کامل
import sqlite3

connection = sqlite3.connect("users.db")
cursor = connection.cursor()

cursor.execute("""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT,
age INTEGER
)
""")

users = [
("Ali", 25),
("Sara", 22),
("Reza", 30)
]

cursor.executemany(
"INSERT INTO users (name, age) VALUES (?, ?)",
users
)

connection.commit()
connection.close()

بعد از اجرای برنامه، سه رکورد به جدول اضافه می‌شود.
🔹 استفاده از ?
همانند execute() بهتر است مقدارها را با Parameterized Query ارسال کنیم:
"INSERT INTO users (name, age) VALUES (?, ?)"

و داده‌ها جداگانه قرار بگیرند:
users = [
("Ali", 25),
("Sara", 22)
]

این روش هم خواناتر است و هم از قرار دادن مستقیم مقدارها داخل SQL جلوگیری می‌کند.
🔹 executemany() با lastrowid
یک نکته مهم:
cursor.lastrowid

برای درج چند رکورد، روش مناسبی برای دریافت ID همه رکوردهای جدید نیست.
اگر به ID رکوردهای ایجادشده نیاز دارید، بهتر است بعداً آن‌ها را با یک Query مناسب از دیتابیس دریافت کنید.
⚠️ نکته مهم
ساختار داده‌ها باید با تعداد ?ها هماهنگ باشد.
مثلاً:
"VALUES (?, ?)"

یعنی هر رکورد باید دو مقدار داشته باشد:
("Ali", 25)

اما این اشتباه است:
("Ali", 25, "Extra")

چون تعداد مقادیر با Placeholderها هماهنگ نیست.
🧠 خلاصه
execute()      → اجرای یک عملیات
executemany() → اجرای یک عملیات برای چند مجموعه داده

الگوی اصلی:
cursor.executemany(
"INSERT INTO table_name (column1, column2) VALUES (?, ?)",
data
)

🎯 تمرین
جدول زیر را در نظر بگیر:
students

با ستون‌های:
id     → INTEGER PRIMARY KEY
name → TEXT
score → REAL

با استفاده از executemany() این سه دانش‌آموز را اضافه کن:
students = [
("Ali", 18.5),
("Sara", 19.0),
("Reza", 17.25)
]

در پایان commit() را اجرا کن.
پست ۱۸۲ از دوره جامع Python 🐍