پرسش‌های متداول درباره‌ی کتابخانه و افزونه

پرسش‌های عمومی کتابخانه

چگونه می‌توانم یک ماژول یا برنامه برای انجام کار X پیدا کنم؟

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

برای بسته‌های شخص ثالث، در فهرست بسته‌های پایتون جستجو کنید یا Google یا موتور جستجوی وب دیگری را امتحان کنید. جستجوی «Python» به‌همراه یک یا دو کلیدواژه برای موضوع مورد نظر شما معمولاً به پیدا کردن موردی مفید منجر می‌شود.

پرونده منبع math.py (socket.py، regex.py و غیره) کجاست؟

اگر نمی‌توانید پرونده منبعی برای یک ماژول پیدا کنید، ممکن است آن ماژول توکار باشد یا ماژولی باشد که به‌صورت پویا بارگذاری می‌شود و در C، C++ یا زبان کامپایل‌شده دیگری پیاده‌سازی شده است. در این حالت ممکن است پرونده منبع را نداشته باشید یا ممکن است چیزی مانند mathmodule.c باشد، در جایی از یک پوشه‌ی منبع C (نه در مسیر پایتون).

در پایتون (دست‌کم) ۳ نوع ماژول وجود دارد:

  1. ماژول‌های نوشته‌شده با پایتون (.py)؛

  2. ماژول‌های نوشته‌شده با C و بارگذاری‌شده به‌صورت پویا (.dll، .pyd، .so، .sl و غیره)؛

  3. ماژول‌هایی که به زبان C نوشته شده‌اند و با مفسر پیوند داده شده‌اند؛ برای دریافت فهرستی از این موارد، تایپ کنید:

    import sys
    print(sys.builtin_module_names)
    

چگونه یک اسکریپت پایتون را در یونیکس قابل‌اجرا کنم؟

شما باید دو کار انجام دهید: حالت پرونده اسکریپت باید اجرایی باشد و خط اول باید با #! آغاز شود و پس از آن مسیر مفسر پایتون قرار گیرد.

مورد اول با اجرای chmod +x scriptfile یا شاید chmod 755 scriptfile انجام می‌شود.

دومی را می‌توان به روش‌های مختلفی انجام داد. مستقیم‌ترین روش این است که بنویسید

#!/usr/local/bin/python

به‌عنوان نخستین خط پرونده شما، با استفاده از مسیر محل نصب مفسر پایتون در پلتفرم شما.

اگر می‌خواهید اسکریپت مستقل از محل قرارگیری مفسر پایتون باشد، می‌توانید از برنامه‌ی env استفاده کنید. تقریباً همه‌ی گونه‌های یونیکس از دستور زیر پشتیبانی می‌کنند، با فرض اینکه مفسر پایتون در پوشه‌ای در PATH کاربر قرار داشته باشد:

#!/usr/bin/env python

این کار را برای اسکریپت‌های CGI انجام ندهید. متغیر PATH برای اسکریپت‌های CGI معمولاً بسیار محدود است، بنابراین باید از مسیر مطلق واقعی مفسر استفاده کنید.

گاهی اوقات، محیط یک کاربر آن‌قدر پر است که برنامه‌ی /usr/bin/env شکست می‌خورد؛ یا اصلاً برنامه env وجود ندارد. در این صورت، می‌توانید ترفند زیر را امتحان کنید (از الکس رزینسکی):

#! /bin/sh
""":"
exec python $0 ${1+"$@"}
"""

عیب جزئی این است که این کار رشته‌ی __doc__ اسکریپت را تعریف می‌کند. با این حال، می‌توانید با افزودن این علامت آن را برطرف کنید

__doc__ = """...Whatever..."""

آیا بسته‌ای برای curses/termcap در پایتون وجود دارد؟

برای انواع یونیکس: توزیع کد منبع استاندارد پایتون شامل ماژول curses در زیرپوشه‌ی Modules است، اگرچه به‌طور پیش‌فرض کامپایل نمی‌شود. (توجه داشته باشید که این در توزیع ویندوز در دسترس نیست — ماژول curses برای ویندوز وجود ندارد.)

ماژول curses از ویژگی‌های پایه‌ای curses و نیز بسیاری از توابع اضافی ncurses و SYSV curses مانند رنگ، پشتیبانی از مجموعه نویسه‌های جایگزین، پدها (pads) و پشتیبانی از ماوس پشتیبانی می‌کند. این بدان معناست که این ماژول با سیستم‌عامل‌هایی که فقط دارای BSD curses هستند، سازگار نیست، اما به نظر نمی‌رسد در حال حاضر هیچ سیستم‌عاملی که نگهداری می‌شود، در این دسته قرار داشته باشد.

آیا در پایتون معادلی برای onexit() در C وجود دارد؟

ماژول atexit یک تابع register فراهم می‌کند که مشابه onexit() در C است.

چرا هندلرهای سیگنال من کار نمی‌کنند؟

رایج‌ترین مشکل این است که هندلر سیگنال با فهرست آرگومان نادرست تعریف شده باشد. این تابع به‌صورت زیر فراخوانی می‌شود

handler(signum, frame)

بنابراین باید با دو پارامتر تعریف شود:

def handler(signum, frame):
    ...

وظایف رایج

چگونه یک برنامه یا کامپوننت پایتون را آزمون کنم؟

پایتون با دو چارچوب آزمون ارائه می‌شود. ماژول doctest مثال‌هایی را در رشته مستندات یک ماژول پیدا می‌کند، آن‌ها را اجرا می‌کند و خروجی را با خروجی مورد انتظاری که در رشته مستندات آمده است مقایسه می‌کند.

ماژول unittest یک چارچوب آزمون پیشرفته‌تر است که بر اساس چارچوب‌های آزمون Java و Smalltalk الگوبرداری‌شده است.

برای آسان‌تر کردن آزمون، باید از طراحی ماژولار خوبی در برنامه خود استفاده کنید. برنامه شما باید تقریباً تمام قابلیت‌ها را در قالب توابع یا متدهای کلاس کپسوله کند -- و این گاهی اثر غافلگیرکننده و دلپذیری دارد که باعث می‌شود برنامه سریع‌تر اجرا شود (زیرا دسترسی به متغیرهای محلی سریع‌تر از دسترسی به متغیرهای سراسری است). علاوه بر این، برنامه باید از وابستگی به تغییر متغیرهای سراسری پرهیز کند، زیرا این کار آزمون را بسیار دشوارتر می‌کند.

«منطق اصلی سراسری» برنامه شما ممکن است به‌سادگی زیر باشد

if __name__ == "__main__":
    main_logic()

در انتهای ماژول اصلی برنامه‌تان.

هنگامی که برنامه شما به‌صورت مجموعه‌ای قابل‌مدیریت از رفتارهای توابع و کلاس‌ها سازمان‌دهی شد، باید توابع آزمونی بنویسید که این رفتارها را آزمایش کنند. برای هر ماژول می‌توان یک بدنه آزمون در نظر گرفت که دنباله‌ای از آزمون‌ها را خودکار می‌کند. این کار ممکن است زیاد به نظر برسد، اما از آنجا که پایتون بسیار مختصر و انعطاف‌پذیر است، به‌طرز شگفت‌آوری آسان است. شما می‌توانید با نوشتن توابع آزمون خود به‌موازات «کد تولیدی»، کدنویسی را بسیار لذت‌بخش‌تر و سرگرم‌کننده‌تر کنید، زیرا این کار یافتن باگ‌ها و حتی نقص‌های طراحی را زودتر آسان می‌کند.

«ماژول‌های پشتیبانی» که به‌عنوان ماژول اصلی یک برنامه در نظر گرفته نشده‌اند، ممکن است شامل خودآزمایی (self-test) ماژول باشند.

if __name__ == "__main__":
    self_test()

حتی برنامه‌هایی که با رابط‌های خارجی پیچیده تعامل دارند، می‌توانند هنگامی که رابط‌های خارجی در دسترس نیستند، با استفاده از رابط‌های «جعلی» پیاده‌سازی‌شده در پایتون آزمایش شوند.

چگونه از رشته مستندات، مستندات بسازم؟

ماژول pydoc می‌تواند از رشته مستندات در کد منبع پایتون شما HTML تولید کند. یک جایگزین برای ایجاد مستندات API صرفاً از رشته مستندات، epydoc است. Sphinx نیز می‌تواند محتوای رشته مستندات را شامل شود.

چگونه می‌توانم هر بار یک کلید را به‌صورت تکی دریافت کنم؟

برای گونه‌های یونیکس چندین راه‌حل وجود دارد. انجام این کار با استفاده از curses ساده است، اما curses ماژول نسبتاً بزرگی برای یادگیری است.

نخ‌ها

چگونه با استفاده از نخ‌ها برنامه‌نویسی کنم؟

حتماً از ماژول threading استفاده کنید، نه از ماژول _thread. ماژول threading انتزاع‌های مناسبی بر پایه‌ی اولیه‌های سطح پایینِ ارائه‌شده توسط ماژول _thread ایجاد می‌کند.

به نظر می‌رسد هیچ‌کدام از نخ‌های من اجرا نمی‌شوند: چرا؟

به محض اینکه نخ اصلی خارج می‌شود، همه نخ‌ها از بین می‌روند. نخ اصلی شما بیش از حد سریع اجرا می‌شود و هیچ زمانی برای انجام کار به نخ‌ها نمی‌دهد.

یک راه‌حل ساده این است که یک توقف (sleep) به پایان برنامه اضافه کنید که به اندازه کافی طولانی باشد تا همه نخ‌ها تمام شوند:

import threading, time

def thread_task(name, n):
    for i in range(n):
        print(name, i)

for i in range(10):
    T = threading.Thread(target=thread_task, args=(str(i), i))
    T.start()

time.sleep(10)  # <---------------------------!

اما اکنون (در بسیاری از پلتفرم‌ها) نخ‌ها به‌صورت موازی اجرا نمی‌شوند، بلکه به نظر می‌رسد به‌صورت ترتیبی، هر بار یک نخ، اجرا می‌شوند! دلیل آن این است که زمان‌بند نخ‌های سیستم‌عامل تا زمانی که نخ قبلی مسدود نشده باشد، نخ جدیدی را شروع نمی‌کند.

یک راه‌حل ساده، افزودن یک توقف بسیار کوتاه به ابتدای تابع run است:

def thread_task(name, n):
    time.sleep(0.001)  # <--------------------!
    for i in range(n):
        print(name, i)

for i in range(10):
    T = threading.Thread(target=thread_task, args=(str(i), i))
    T.start()

time.sleep(10)

به‌جای تلاش برای حدس زدن یک مقدار تأخیر مناسب برای time.sleep()، بهتر است از نوعی سازوکار سمافور استفاده کنید. یک ایده این است که از ماژول queue برای ایجاد یک شیء صف استفاده کنید، به هر نخ اجازه دهید پس از پایان کار یک توکن به صف اضافه کند و نخ اصلی به تعداد نخ‌ها توکن از صف بخواند.

چگونه کار را میان دسته‌ای از نخ‌های کارگر تقسیم کنم؟

ساده‌ترین راه، استفاده از ماژول concurrent.futures، به‌ویژه کلاس ThreadPoolExecutor است.

یا، اگر می‌خواهید کنترل دقیقی بر الگوریتم توزیع داشته باشید، می‌توانید منطق خود را به‌صورت دستی بنویسید. از ماژول queue برای ایجاد یک صف حاوی فهرستی از کارها استفاده کنید. کلاس Queue یک فهرست از شیء‌ها را نگهداری می‌کند و دارای یک متد .put(obj) است که آیتم‌ها را به صف اضافه می‌کند و یک متد .get() برای برگرداندن آن‌ها دارد. این کلاس قفل‌گذاری لازم را برای اطمینان از اینکه هر کار دقیقاً یک بار تحویل داده شود، مدیریت می‌کند.

این یک مثال ساده است:

import threading, queue, time

# The worker thread gets jobs off the queue.  When the queue is empty, it
# assumes there will be no more work and exits.
# (Realistically workers will run until terminated.)
def worker():
    print('Running worker')
    time.sleep(0.1)
    while True:
        try:
            arg = q.get(block=False)
        except queue.Empty:
            print('Worker', threading.current_thread(), end=' ')
            print('queue empty')
            break
        else:
            print('Worker', threading.current_thread(), end=' ')
            print('running with argument', arg)
            time.sleep(0.5)

# Create queue
q = queue.Queue()

# Start a pool of 5 workers
for i in range(5):
    t = threading.Thread(target=worker, name='worker %i' % (i+1))
    t.start()

# Begin adding work to the queue
for i in range(50):
    q.put(i)

# Give threads time to run
print('Main thread sleeping')
time.sleep(5)

هنگام اجرا، خروجی زیر تولید خواهد شد:

Running worker
Running worker
Running worker
Running worker
Running worker
Main thread sleeping
Worker <Thread(worker 1, started 130283832797456)> running with argument 0
Worker <Thread(worker 2, started 130283824404752)> running with argument 1
Worker <Thread(worker 3, started 130283816012048)> running with argument 2
Worker <Thread(worker 4, started 130283807619344)> running with argument 3
Worker <Thread(worker 5, started 130283799226640)> running with argument 4
Worker <Thread(worker 1, started 130283832797456)> running with argument 5
...

برای جزئیات بیشتر، به مستندات ماژول مراجعه کنید؛ کلاس Queue رابطی پرامکانات ارائه می‌دهد.

چه انواعی از تغییر مقادیر سراسری نخ‌ایمن هستند؟

یک قفل سراسری مفسر (GIL) به‌صورت داخلی استفاده می‌شود تا تضمین کند که در هر لحظه تنها یک نخ در ماشین مجازی پایتون اجرا می‌شود. به‌طور کلی، پایتون تنها بین دستورالعمل‌های بایت‌کد امکان جابه‌جایی میان نخ‌ها را فراهم می‌کند؛ میزان دفعات جابه‌جایی آن را می‌توان از طریق sys.setswitchinterval() تنظیم کرد. هر دستورالعمل بایت‌کد، و بنابراین تمام کد پیاده‌سازی C که از هر دستورالعمل قابل دسترسی است، از این رو از دیدگاه یک برنامه پایتون اتمی محسوب می‌شود.

از نظر تئوری، این بدان معناست که یک محاسبه‌ی دقیق نیازمند درک دقیق از پیاده‌سازی بایت‌کد PVM است. در عمل، به این معناست که عملیات روی متغیرهای مشترک از انواع داده‌ی توکار (اعداد صحیح، فهرست‌ها، دیکشنری‌ها و غیره) که «اتمی به نظر می‌رسند»، واقعاً اتمی هستند.

برای مثال، عملیات‌های زیر همگی اتمی هستند (L، L1 و L2 فهرست هستند، D، D1 و D2 دیکشنری هستند، x و y شیء هستند، i و j عدد صحیح هستند):

L.append(x)
L1.extend(L2)
x = L[i]
x = L.pop()
L1[i:j] = L2
L.sort()
x = y
x.field = y
D[x] = y
D1.update(D2)
D.keys()

این‌ها چنین نیستند:

i = i+1
L.append(L[-1])
L[i] = L[j]
D[x] = D[x] + 1

عملیاتی که اشیاء دیگر را جایگزین می‌کنند، ممکن است هنگامی که شمار ارجاع آن اشیاء دیگر به صفر می‌رسد، متد __del__() آن‌ها را فراخوانی کنند، و این می‌تواند بر مواردی اثر بگذارد. این موضوع به‌ویژه برای به‌روزرسانی‌های انبوه دیکشنری‌ها و فهرست‌ها صادق است. در صورت تردید، از یک قفل (mutex) استفاده کنید!

آیا نمی‌توانیم قفل سراسری مفسر را حذف کنیم؟

global interpreter lock (GIL) اغلب به‌عنوان مانعی برای استقرار پایتون روی ماشین‌های سرور چندپردازنده‌ای رده‌بالا در نظر گرفته می‌شود، زیرا یک برنامه چندنخی پایتون عملاً تنها از یک CPU استفاده می‌کند، به دلیل این الزام که (تقریباً) تمام کد پایتون تنها زمانی می‌تواند اجرا شود که GIL در اختیار گرفته شده باشد.

با تصویب PEP 703، اکنون کار برای حذف GIL از پیاده‌سازی CPython از پایتون در جریان است. در ابتدا، این کار به‌صورت یک پرچم اختیاری کامپایلر هنگام ساخت مفسر پیاده‌سازی خواهد شد، بنابراین ساخت‌های جداگانه‌ای با GIL و بدون GIL در دسترس خواهند بود. در بلندمدت، امید است پس از آنکه پیامدهای عملکردی حذف GIL به‌طور کامل درک شوند، به یک ساخت واحد برسیم. احتمالاً پایتون 3.13 اولین نسخه‌ای خواهد بود که شامل این کار می‌شود، اگرچه ممکن است در این نسخه کاملاً کاربردی نباشد.

کار جاری برای حذف GIL بر پایه‌ی انشعاب Python 3.9 با GIL حذف‌شده از Sam Gross است. پیش از آن، در دوران Python 1.5، Greg Stein در واقع مجموعه‌ای جامع از وصله‌ها (وصله‌های «free threading») را پیاده‌سازی کرد که GIL را حذف می‌کرد و آن را با قفل‌بندی ریزدانه جایگزین می‌نمود. Adam Olsen آزمایش مشابهی را در پروژه‌ی python-safethread خود انجام داد. متأسفانه، هر دوی این آزمایش‌های پیشین افت شدیدی را در عملکرد تک‌نخی (حداقل ۳۰٪ کندتر) نشان دادند، که به دلیل میزان قفل‌بندی ریزدانه‌ای بود که برای جبران حذف GIL لازم بود. انشعاب Python 3.9 نخستین تلاش برای حذف GIL با تأثیر قابل‌قبول بر عملکرد است.

وجود GIL در نسخه‌های فعلی پایتون به این معنا نیست که نمی‌توانید از پایتون روی ماشین‌های چندپردازنده به‌خوبی استفاده کنید! شما فقط باید در تقسیم کار میان چندین فرآیند به‌جای چندین نخ خلاقانه عمل کنید. کلاس ProcessPoolExecutor در ماژول جدید concurrent.futures راه آسانی برای انجام این کار فراهم می‌کند؛ ماژول multiprocessing یک API سطح پایین‌تر را در صورتی که بخواهید کنترل بیشتری بر اعزام وظایف داشته باشید، فراهم می‌کند.

استفاده سنجیده از افزونه‌های C نیز کمک خواهد کرد؛ اگر از یک افزونه C برای انجام یک کار زمان‌بر استفاده کنید، افزونه می‌تواند در حالی که نخ اجرا در کد C است، GIL را آزاد کند و به نخ‌های دیگر اجازه دهد تا مقداری کار انجام دهند. برخی از ماژول‌های کتابخانه استاندارد مانند zlib و hashlib از قبل این کار را انجام می‌دهند.

یک رویکرد جایگزین برای کاهش تأثیر GIL این است که GIL به‌جای کاملاً سراسری بودن، به قفلی به‌ازای هر وضعیت مفسر تبدیل شود. این مورد برای نخستین بار در Python 3.12 پیاده‌سازی شد و در C API در دسترس است. انتظار می‌رود یک رابط پایتون برای آن در Python 3.13 ارائه شود. در حال حاضر محدودیت اصلی آن احتمالاً ماژول‌های توسعه‌ای شخص ثالث هستند، زیرا این ماژول‌ها برای قابل‌استفاده بودن باید با در نظر گرفتن چند مفسر نوشته شوند، بنابراین بسیاری از ماژول‌های توسعه‌ای قدیمی‌تر قابل‌استفاده نخواهند بود.

ورودی و خروجی

چگونه یک پرونده را حذف کنم؟ (و دیگر پرسش‌های مربوط به پرونده...)

از os.remove(filename) یا os.unlink(filename) استفاده کنید؛ برای مستندات، ماژول os را ببینید. این دو تابع یکسان هستند؛ unlink() صرفاً نام فراخوانی سیستمی یونیکس برای این تابع است.

برای حذف یک پوشه، از os.rmdir() استفاده کنید؛ برای ایجاد یک پوشه، از os.mkdir() استفاده کنید. os.makedirs(path) هر پوشه میانی در path را که وجود نداشته باشد ایجاد می‌کند. os.removedirs(path) پوشه‌های میانی را تا زمانی که خالی باشند حذف می‌کند؛ اگر می‌خواهید کل درخت پوشه و محتویات آن را حذف کنید، از shutil.rmtree() استفاده کنید.

برای تغییر نام یک پرونده، از os.rename(old_path, new_path) استفاده کنید.

برای بریدن یک پرونده، آن را با استفاده از f = open(filename, "rb+") باز کنید و از f.truncate(offset) استفاده کنید؛ مقدار پیش‌فرض offset، موقعیت فعلی seek است. همچنین os.ftruncate(fd, offset) برای پرونده‌هایی که با os.open() باز شده‌اند نیز وجود دارد، که در آن fd توصیف‌گر پرونده (یک عدد صحیح کوچک) است.

ماژول shutil همچنین شامل تعدادی تابع برای کار بر روی پرونده‌ها، از جمله copyfile()، copytree() و rmtree() است.

چگونه یک پرونده را کپی کنم؟

ماژول shutil شامل یک تابع copyfile() است. توجه داشته باشید که این تابع در حجم‌های NTFS در ویندوز، جریان‌های داده جایگزین (alternate data streams) و در حجم‌های HFS+ در macOS، فورک‌های منبع (resource forks) را کپی نمی‌کند، اگرچه امروزه هر دو به‌ندرت استفاده می‌شوند. همچنین مجوزها و فراداده‌های پرونده را کپی نمی‌کند، اگرچه استفاده از shutil.copy2() به‌جای آن، بیشتر آن‌ها را (هرچند نه همه) حفظ می‌کند.

چگونه داده‌های دودویی را بخوانم (یا بنویسم)؟

برای خواندن یا نوشتن قالب‌های داده دودویی پیچیده، بهتر است از ماژول struct استفاده کنید. این ماژول به شما امکان می‌دهد رشته‌ای حاوی داده دودویی (معمولاً اعداد) را بگیرید و آن را به اشیای پایتون تبدیل کنید؛ و برعکس.

برای مثال، کد زیر دو عدد صحیح ۲ بایتی و یک عدد صحیح ۴ بایتی را در قالب بزرگ‌اندیان (big-endian) از یک پرونده می‌خواند:

import struct

with open(filename, "rb") as f:
    s = f.read(8)
    x, y, z = struct.unpack(">hhl", s)

'>' در رشته قالب، داده‌های بزرگ‌اندیان (big-endian) را تحمیل می‌کند؛ حرف 'h' یک «عدد صحیح کوتاه» (۲ بایت) و 'l' یک «عدد صحیح بلند» (۴ بایت) را از رشته می‌خواند.

برای داده‌هایی که منظم‌تر هستند (مثلاً فهرستی همگن از اعداد صحیح یا اعشاری)، همچنین می‌توانید از ماژول array استفاده کنید.

توجه

برای خواندن و نوشتن داده‌های دودویی، باز کردن پرونده در حالت دودویی الزامی است (در اینجا، با ارسال "rb" به open()). اگر به‌جای آن از "r" استفاده کنید (پیش‌فرض)، پرونده در حالت متنی باز خواهد شد و f.read() به‌جای اشیای bytes، اشیای str را برمی‌گرداند.

به نظر می‌رسد نمی‌توانم از os.read() روی یک پایپ ایجادشده با os.popen() استفاده کنم؛ چرا؟

os.read() یک تابع سطح پایین است که یک توصیف‌گر پرونده، یعنی یک عدد صحیح کوچک که پرونده باز شده را نشان می‌دهد، می‌گیرد. os.popen() یک شیء پرونده سطح بالا ایجاد می‌کند، همان نوعی که تابع توکار open() برمی‌گرداند. بنابراین، برای خواندن n بایت از پایپ p که با os.popen() ایجاد شده است، باید از p.read(n) استفاده کنید.

چگونه به درگاه سریال (RS232) دسترسی پیدا کنم؟

برای Win32، OSX، Linux، BSD، Jython، IronPython:

برای یونیکس، یک پست یوزنت از میچ چپمن را ببینید:

چرا بستن sys.stdout (stdin, stderr) واقعاً آن را نمی‌بندد؟

اشیای پرونده در پایتون، یک لایه انتزاعی سطح بالا بر روی توصیف‌گرهای پرونده سطح پایین C هستند.

برای بیشتر اشیای پرونده‌ای که در پایتون از طریق تابع توکار open() ایجاد می‌کنید، f.close() شیء پرونده پایتون را از دید پایتون به‌عنوان بسته‌شده علامت‌گذاری می‌کند و همچنین مقدمات بستن توصیف‌گر پرونده زیربنایی C را فراهم می‌کند. این اتفاق نیز به‌طور خودکار در تخریب‌کننده‌ی f، هنگامی که f به زباله تبدیل می‌شود، رخ می‌دهد.

اما پایتون stdin، stdout و stderr را به‌طور ویژه مدیریت می‌کند، زیرا C نیز وضعیت ویژه‌ای به آن‌ها داده است. اجرای sys.stdout.close() شیء پرونده در سطح پایتون را به‌عنوان بسته‌شده علامت‌گذاری می‌کند، اما توصیف‌گر پرونده C مرتبط را نمی‌بندد.

برای بستن توصیف‌گر پرونده C زیربنایی برای یکی از این سه مورد، ابتدا باید مطمئن شوید که واقعاً همین کار را می‌خواهید انجام دهید (برای مثال، ممکن است ماژول‌های توسعه‌ای را که سعی در انجام I/O دارند، دچار سردرگمی کنید). اگر چنین است، از os.close() استفاده کنید:

os.close(stdin.fileno())
os.close(stdout.fileno())
os.close(stderr.fileno())

یا می‌توانید به‌ترتیب از ثابت‌های عددی 0، 1 و 2 استفاده کنید.

برنامه‌نویسی شبکه/اینترنت

چه ابزارهای WWW برای پایتون وجود دارد؟

به فصل‌هایی با عنوان‌های پروتکل‌های اینترنتی و پشتیبانی و مدیریت داده‌های اینترنتی در راهنمای مرجع کتابخانه مراجعه کنید. پایتون ماژول‌های بسیاری دارد که به شما در ساخت سیستم‌های وب سمت سرور و سمت کاربر کمک خواهند کرد.

خلاصه‌ای از چارچوب‌های موجود توسط Paul Boddie در https://wiki.python.org/moin/WebProgrammingنگهداری می‌شود.

برای کمک به تولید HTML از چه ماژولی باید استفاده کنم؟

می‌توانید مجموعه‌ای از پیوندهای مفید را در صفحه‌ی ویکی برنامه‌نویسی وب بیابید.

چگونه از یک اسکریپت پایتون ایمیل ارسال کنم؟

از ماژول کتابخانه استاندارد smtplib استفاده کنید.

در اینجا یک فرستنده‌ی تعاملی بسیار ساده‌ی ایمیل آمده است که از آن استفاده می‌کند. این روش روی هر میزبانی که از یک شنونده‌ی SMTP پشتیبانی کند کار خواهد کرد.

import sys, smtplib

fromaddr = input("From: ")
toaddrs  = input("To: ").split(',')
print("Enter message, end with ^D:")
msg = ''
while True:
    line = sys.stdin.readline()
    if not line:
        break
    msg += line

# The actual mail send
server = smtplib.SMTP('localhost')
server.sendmail(fromaddr, toaddrs, msg)
server.quit()

یک جایگزین مختص یونیکس از sendmail استفاده می‌کند. مکان برنامه‌ی sendmail در سیستم‌های مختلف متفاوت است؛ گاهی /usr/lib/sendmail و گاهی /usr/sbin/sendmail است. صفحه‌ی راهنمای sendmail به شما کمک خواهد کرد. در ادامه یک نمونه کد آمده است:

import os

SENDMAIL = "/usr/sbin/sendmail"  # sendmail location
p = os.popen("%s -t -i" % SENDMAIL, "w")
p.write("To: receiver@example.com\n")
p.write("Subject: test\n")
p.write("\n")  # blank line separating headers from body
p.write("Some text\n")
p.write("some more text\n")
sts = p.close()
if sts != 0:
    print("Sendmail exit status", sts)

چگونه از مسدود شدن در متد connect() یک سوکت جلوگیری کنم؟

ماژول select معمولاً برای کمک به ورودی/خروجی ناهمگام روی سوکت‌ها استفاده می‌شود.

برای جلوگیری از مسدود شدن اتصال TCP، می‌توانید سوکت را در حالت غیرمسدودکننده قرار دهید. سپس وقتی connect() را فراخوانی می‌کنید، یا بلافاصله متصل می‌شوید (که بعید است) یا استثنایی دریافت می‌کنید که حاوی شماره خطا در .errno است. errno.EINPROGRESS نشان می‌دهد که اتصال در حال انجام است، اما هنوز تمام نشده است. سیستم‌عامل‌های مختلف مقادیر متفاوتی برمی‌گردانند، بنابراین باید بررسی کنید که در سیستم شما چه مقداری برگردانده می‌شود.

می‌توانید از متد connect_ex() برای جلوگیری از ایجاد یک استثنا استفاده کنید. این متد فقط مقدار errno را برمی‌گرداند. برای پایش، می‌توانید بعداً دوباره connect_ex() را فراخوانی کنید — 0 یا errno.EISCONN نشان می‌دهند که شما متصل هستید — یا می‌توانید این سوکت را به select.select() بدهید تا قابل نوشتن بودن آن را بررسی کنید.

توجه

ماژول asyncio یک کتابخانه همه‌منظوره، ناهمگام، تک‌نخی و همروند ارائه می‌دهد که می‌توان از آن برای نوشتن کد شبکه غیرمسدودکننده استفاده کرد. کتابخانه شخص ثالث Twisted یک جایگزین محبوب و پرامکانات است.

پایگاه‌های داده

آیا در پایتون رابط‌هایی برای بسته‌های پایگاه داده وجود دارد؟

بله.

رابط‌هایی برای هش‌های مبتنی بر دیسک مانند DBM و GDBM نیز در پایتون استاندارد گنجانده شده‌اند. همچنین ماژول sqlite3 وجود دارد که یک پایگاه داده‌ی رابطه‌ای سبک مبتنی بر دیسک فراهم می‌کند.

پشتیبانی از بیشتر پایگاه‌داده‌های رابطه‌ای در دسترس است. برای جزئیات، صفحه‌ی ویکی DatabaseProgramming را ببینید.

چگونه اشیاء پایا را در پایتون پیاده‌سازی می‌کنید؟

ماژول کتابخانه‌ای pickle این مسئله را به‌شکلی بسیار عمومی حل می‌کند (هرچند هنوز نمی‌توانید چیزهایی مانند پرونده‌های باز، سوکت‌ها یا پنجره‌ها را ذخیره کنید)، و ماژول کتابخانه‌ای shelve از pickle و (g)dbm برای ایجاد نگاشت‌های پایا شامل اشیاء پایتون دلخواه استفاده می‌کند.

ریاضیات و محاسبات عددی

چگونه در پایتون اعداد تصادفی تولید کنم؟

ماژول استاندارد random یک تولیدگر عدد تصادفی را پیاده‌سازی می‌کند. نحوه استفاده ساده است:

import random
random.random()

این یک عدد ممیز شناور تصادفی در بازه‌ی [۰، ۱) برمی‌گرداند.

در این ماژول، تولیدگرهای تخصصی بسیاری نیز وجود دارند، مانند:

  • randrange(a, b) یک عدد صحیح را در بازه‌ی [a, b) انتخاب می‌کند.

  • uniform(a, b) یک عدد ممیز شناور در بازه [a, b) انتخاب می‌کند.

  • normalvariate(mean, sdev) از توزیع نرمال (گاوسی) نمونه‌گیری می‌کند.

برخی از توابع سطح‌بالا مستقیماً روی دنباله‌ها عمل می‌کنند، از جمله:

  • choice(S) یک المان تصادفی را از یک دنباله داده‌شده انتخاب می‌کند.

  • shuffle(L) یک فهرست را درجا جابه‌جا می‌کند، یعنی آن را به‌صورت تصادفی جایگشت می‌دهد.

همچنین یک کلاس Random وجود دارد که می‌توانید نمونه‌ای از آن بسازید تا چندین تولیدگر عدد تصادفی مستقل ایجاد کنید.