۹ قابلیت پایتون که اتوماسیون رو شیک و تمیز می‌کنه

۹ قابلیت مخفی پایتون که کدنویسی اتوماسیون رو ساده‌تر، تمیزتر و سریع‌تر می‌کنن. برای برنامه‌نویس‌ها و علاقه‌مندان اتوماسیون.

۹ قابلیت پایتون که اتوماسیون رو شیک و تمیز می‌کنه

اگه مدتیه با پایتون کارهای تکراری و روزمره رو اتومات کردی، احتمالاً کلی اسکریپت نوشتی که می‌شه گفت: «کار می‌کنه، ولی دست بهش نزن!» 😅
این اسکریپت‌ها کار رو راه میندازن، اما یک سال بعد که برگردی سراغشون، بیشتر شبیه به یه بشقاب ماکارونی به‌هم‌ریخته شدن تا یه کد خوشگل و مرتب.

راز اینکه اسکریپت‌هات هم تمیز بمونه و هم قابل نگهداری باشه، همیشه نصب کردن یه کتابخونه جدید نیست. خیلی وقتا همون قابلیت‌های کمتر دیده‌شده‌ی خود پایتون، نجات‌دهنده هستن.
اینجا ۹ تا از اون قابلیت‌ها رو آوردم که باعث می‌شن کدهای اتوماسیونت سریع‌تر، قابل اعتمادتر و از همه مهم‌تر تمیزتر باشن.

1. عملیات اتمیک با pathlib

دیگه فراموش کن os.path و رشته‌سازی دستی مسیرها رو. با pathlib همه‌چیز شی‌ءگرا می‌شه و حتی عملیات اتمیک هم داری که جلوی فایل‌های نصفه‌نیمه رو می‌گیره.

from pathlib import Path

data = Path('reports') / 'daily.csv'
data.parent.mkdir(parents=True, exist_ok=True)  # auto-create dirs
tmp = data.with_suffix('.tmp')

tmp.write_text('some,data,here')
tmp.replace(data)  # atomic move to final file

چرا جذابه؟
هیچ‌وقت فایل ناقص نمی‌ذاره اگه اسکریپت وسط کار کرش کنه. برای کرون‌جاب‌ها خیلی عالیه.

2. functools.cached_property (پایتون 3.8 به بعد)

یه محاسبه سنگین یا عملیات I/O داری که فقط یک‌بار لازمش داری؟ دیگه لازم نیست خودت منطق Cache رو پیاده‌سازی کنی.

from functools import cached_property
import requests

class WeatherClient:
    def __init__(self, city):
        self.city = city

    @cached_property
    def data(self):
        return requests.get(f'https://wttr.in/{self.city}?format=j1').json()

client = WeatherClient('London')
print(client.data['current_condition'])

چرا جذابه؟
یه بار اجرا می‌شه و بعدش همیشه آماده‌ست. هیچ ساختار Cache اضافه هم لازم نداری.

3. مدیریت داینامیک منابع با contextlib.ExitStack

تا حالا شده بخوای تعدادی فایل همزمان رو باز کنی؟ با with‌های تو در تو کد خیلی زشت می‌شه. اینجا ExitStack به کمکت میاد.

from contextlib import ExitStack

files = ['a.txt', 'b.txt', 'c.txt']
with ExitStack() as stack:
    handles = [stack.enter_context(open(f)) for f in files]
    data = [h.read() for h in handles]

چرا جذابه؟
یه with کافیه برای هر تعداد منبع. کدت تمیز می‌مونه و نیاز به with تو در تو نیست.

4. موازی‌سازی با فیدبک لحظه‌ای

خیلیا ThreadPoolExecutor رو می‌شناسن، ولی کمتر کسی می‌دونه as_completed می‌تونه نتایج رو همون لحظه‌ای که آماده شدن بهت برگردونه.

from concurrent.futures import ThreadPoolExecutor, as_completed
import requests

urls = ['https://example.com', 'https://python.org', 'https://pypi.org']

with ThreadPoolExecutor(max_workers=5) as ex:
    futures = [ex.submit(requests.get, url) for url in urls]
    for future in as_completed(futures):
        print(f"{future.result().url} done")

چرا جذابه؟
فیدبک فوری می‌گیری. برای مثال در کد بالا لازم نیست تا آخرین URL صبر کنی.

5. پاکسازی خودکار - tempfile.TemporaryDirectory

خیلی وقتا وسط اتوماسیون باید فایل موقت بسازی. چرا بذاری یه عالمه فایل بی استفاده روی سیستم بمونه؟

import tempfile, shutil, pathlib

with tempfile.TemporaryDirectory() as tmpdir:
    path = pathlib.Path(tmpdir) / 'data.txt'
    path.write_text('temporary data')
    print(path.read_text())

# directory gone automatically here

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

6. زمان‌بندی ساده - sched

همه سریع می‌رن سراغ cron یا APScheduler، ولی پایتون یه سیستم ساده برای خودش داره.

import sched, time

s = sched.scheduler(time.time, time.sleep)

def job(name):
    print(f"Running {name} at {time.ctime()}")

s.enter(5, 1, job, argument=('task1',))
s.enter(10, 1, job, argument=('task2',))
s.run()

چرا جذابه؟
برای کارهای کوچک، بدون هیچ سرویس خارجی، عالیه.

7. خاتمه‌ی تمیز اسکریپت با signal و atexit

اسکریپت ۲۴/۷ داری؟ می‌خوای مطمئن بشی حتی با Ctrl+C هم تمیز و مرتب به اتمام می‌رسه؟

import signal, atexit

def cleanup():
    print("Cleaning up before exit…")

atexit.register(cleanup)
signal.signal(signal.SIGTERM, lambda s,f: exit(0))
signal.signal(signal.SIGINT, lambda s,f: exit(0))

print("Running forever. Press Ctrl+C.")
while True:
    time.sleep(1)

چرا جذابه؟
حتی وقتی وسط کار قطع بشه، مطمئن میشی فایل‌های موقت یا کانکشن‌ها درست بسته بشن.

8. آبجکت سبک و بهینه - dataclasses و slots=True

وقتی هزاران رکورد کوچیک داری، کلاس‌های معمولی سنگین میشن. dataclasses با slots خیلی سبک‌تر عمل میکنه.

from dataclasses import dataclass

@dataclass(slots=True)
class Job:
    id: int
    name: str
    status: str = 'pending'

jobs = [Job(i, f'task-{i}') for i in range(10_000)]
print(jobs[0])

چرا جذابه؟
کمتر رم مصرف میکنه و کدت هم تمیزتره.

9. پکیج کردن فایل‌های جانبی - importlib.resources

اسکریپت های اتومیشن مهمولا همراه با کد SQL یا متن ایمیل میان. به‌جای هاردکد کردن مسیر فایل ها، همه‌چیز رو داخل یک پکیج بذار و باهم استفاده کن.

import importlib.resources as res

with res.files('my_package').joinpath('templates/email.txt').open() as f:
    template = f.read()
    print(template)

چرا جذابه؟
اسکریپتت خودکفا می‌شه. دیگه مشکل «روی سیستم من کار می‌کنه» نداری.


جمع‌بندی

همین چند تا قابلیت کوچیک می‌تونن تفاوت بزرگی بسازن. اسکریپت‌هایی که قبلاً شلوغ و سخت بودن، الان تمیز، سبک و قابل نگهداری می‌شن. دفعه بعدی که خواستی یه کار رو اتومات کنی، یکی از این ترفندها رو امتحان کن 😉