msgid"This tutorial will take you through creating a simple Python extension module written in C or C++."
msgstr"این خودآموز شما را با ساخت یک ماژول توسعهی سادهی پایتون که به زبان C یا C++ نوشته شده است، همراهی میکند."
msgid"We will use the low-level Python C API directly. For easier ways to create extension modules, see the :ref:`recommended third party tools <c-api-tools>`."
msgstr"ما مستقیماً از Python C API سطح پایین استفاده خواهیم کرد. برای راههای سادهتر جهت ساخت ماژولهای توسعه، به :ref:`ابزارهای شخص ثالث توصیهشده <c-api-tools>` مراجعه کنید."
msgid"The tutorial assumes basic knowledge about Python: you should be able to define functions in Python code before starting to write them in C. See :ref:`tutorial-index` for an introduction to Python itself."
msgstr"این خودآموز دانش پایهای دربارهی پایتون را فرض میگیرد: شما باید پیش از شروع نوشتن توابع در زبان C، قادر به تعریف تابع در کد پایتون باشید. برای آشنایی با خودِ پایتون به :ref:`tutorial-index` مراجعه کنید."
msgid"The tutorial should be approachable for anyone who can write a basic C library. While we will mention several concepts that a C beginner would not be expected to know, like ``static`` functions or linkage declarations, understanding these is not necessary for success."
msgstr"این خودآموز برای هر کسی که بتواند یک کتابخانهی پایهای C را بنویسد، قابل درک خواهد بود. با اینکه به مفاهیمی اشاره خواهیم کرد که انتظار نمیرود یک تازهکار C بداند، مانند توابع ``static`` یا اعلانهای پیوند (linkage)، درک آنها برای موفقیت ضروری نیست."
msgid"We will focus on giving you a \"feel\" of what Python's C API is like. It will not teach you important concepts, like error handling and reference counting, which are covered in later chapters."
msgstr"ما بر این تمرکز خواهیم کرد که «حسی» از چگونگی C API پایتون به شما بدهیم. این خودآموز مفاهیم مهمی مانند مدیریت خطا و شمارش ارجاع را به شما نخواهد آموخت که در فصول بعدی پوشش داده شدهاند."
msgid"We will assume that you use a Unix-like system (including macOS and Linux), or Windows. On other systems, you might need to adjust some details -- for example, a system command name."
msgstr"ما فرض میکنیم که شما از یک سیستم مشابه یونیکس (شامل macOS و لینوکس) یا ویندوز استفاده میکنید. در سایر سیستمها، ممکن است نیاز باشد برخی جزئیات -- به عنوان مثال، نام یک دستور سیستمی -- را تنظیم کنید."
msgid"You need to have a suitable C compiler and Python development headers installed. On Linux, headers are often in a package like ``python3-dev`` or ``python3-devel``."
msgstr"شما باید یک کامپایلر مناسب C و سرآیندهای توسعهی پایتون را نصب کرده باشید. در لینوکس، سرآیندها معمولاً در بستهای مانند ``python3-dev`` یا ``python3-devel`` قرار دارند."
msgid"You need to be able to install Python packages. This tutorial uses `pip <https://pip.pypa.io/>`__ (``pip install``), but you can substitute any tool that can build and install ``pyproject.toml``-based projects, like `uv <https://docs.astral.sh/uv/>`_ (``uv pip install``). Preferably, have a :ref:`virtual environment <venv-def>` activated."
msgstr"شما باید توانایی نصب بستههای پایتون را داشته باشید. این خودآموز از `pip <https://pip.pypa.io/>`__ (``pip install``) استفاده میکند، اما میتوانید هر ابزاری را که توانایی ساخت و نصب پروژههای مبتنی بر ``pyproject.toml`` را دارد جایگزین کنید، مانند `uv <https://docs.astral.sh/uv/>`_ (``uv pip install``). ترجیحاً، یک :ref:`محیط مجازی <venv-def>` را فعال کنید."
msgid"This tutorial uses APIs that were added in CPython 3.15. To create an extension that's compatible with earlier versions of CPython, please follow an earlier version of this documentation."
msgstr"این خودآموز از APIهایی استفاده میکند که در سیپایتون ۳.۱۵ اضافه شدهاند. برای ساخت بستهای که با نسخههای قبلی سیپایتون سازگار باشد، لطفاً نسخهی قبلی این مستندات را دنبال کنید."
msgid"This tutorial uses C syntax added in C11 and C++20. If your extension needs to be compatible with earlier standards, please follow tutorials in documentation for Python 3.14 or below."
msgstr"این خودآموز از نحو C اضافه شده در C11 و C++20 استفاده میکند. اگر افزونهی شما نیاز دارد با استانداردهای قدیمیتر سازگار باشد، لطفاً خودآموزهای موجود در مستندات پایتون ۳.۱۴ یا پایینتر را دنبال کنید."
msgid"What we'll do"
msgstr"آنچه انجام خواهیم داد"
msgid"Let's create an extension module called ``spam`` [#why-spam]_, which will include a Python interface to the C standard library function :c:func:`system`. This function is defined in ``stdlib.h``. It takes a C string as argument, runs the argument as a system command, and returns a result value as an integer. A manual page for :c:func:`system` might summarize it this way::"
msgstr"بیایید یک ماژول توسعهی به نام ``spam`` [#why-spam]_ بسازیم که شامل یک رابط پایتون به تابع کتابخانهی استاندارد C یعنی :c:func:`system` خواهد بود. این تابع در ``stdlib.h`` تعریف شده است. این تابع یک رشتهی C را به عنوان آرگومان میگیرد، آرگومان را به عنوان یک دستور سیستمی اجرا میکند و یک مقدار نتیجه را به صورت یک عدد صحیح برمیگرداند. یک صفحهی راهنما (man page) برای :c:func:`system` ممکن است آن را به این شکل خلاصه کند::"
msgid""
"#include <stdlib.h>\n"
"int system(const char *command);"
msgstr""
"#include <stdlib.h>\n"
"int system(const char *command);"
msgid"Note that like many functions in the C standard library, this function is already exposed in Python. In production, use :py:func:`os.system` or :py:func:`subprocess.run` rather than the module you'll write here."
msgstr"توجه داشته باشید که مانند بسیاری از توابع در کتابخانهی استاندارد C، این تابع از پیش در پایتون در معرض دید قرار گرفته است. در محیط تولید، به جای ماژولی که در اینجا خواهید نوشت، از :py:func:`os.system` یا :py:func:`subprocess.run` استفاده کنید."
msgid"We want this function to be callable from Python as follows:"
msgstr"ما میخواهیم این تابع به صورت زیر از پایتون قابل فراخوانی باشد:"
msgid""
">>> import spam\n"
">>> status = spam.system(\"whoami\")\n"
"User Name\n"
">>> status\n"
"0"
msgstr""
">>> import spam\n"
">>> status = spam.system(\"whoami\")\n"
"User Name\n"
">>> status\n"
"0"
msgid"The system command ``whoami`` prints out your username. It's useful in tutorials like this one because it has the same name on both Unix and Windows."
msgstr"دستور سیستمی ``whoami`` نام کاربری شما را چاپ میکند. این دستور در خودآموزهایی مانند این مفید است زیرا نام یکسانی در هر دو سیستم یونیکس و ویندوز دارد."
msgid"Start with the headers"
msgstr"شروع با سرآیندها"
msgid"Begin by creating a directory for this tutorial, and switching to it on the command line. Then, create a file named :file:`spammodule.c` in your directory. [#why-spammodule]_"
msgstr"با ساخت یک پوشه برای این خودآموز و رفتن به درون آن در خط فرمان شروع کنید. سپس، یک پرونده با نام :file:`spammodule.c` در پوشهی خود ایجاد کنید. [#why-spammodule]_"
msgid"In this file, we'll include two headers: :file:`Python.h` to pull in all declarations of the Python C API, and :file:`stdlib.h` for the :c:func:`system` function. [#stdlib-h]_"
msgstr"در این پرونده، دو سرآیند را اضافه میکنیم: :file:`Python.h` برای فراخوانی تمام تعاریف مربوط به API زبان C در پایتون، و :file:`stdlib.h` برای تابع :c:func:`system`. [#stdlib-h]_"
msgid"Add the following lines to :file:`spammodule.c`:"
msgstr"سطرهای زیر را به :file:`spammodule.c` اضافه کنید:"
msgid""
"#include <Python.h>\n"
"#include <stdlib.h> // for system()\n"
msgstr""
"#include <Python.h>\n"
"#include <stdlib.h> // for system()\n"
msgid"Be sure to put :file:`stdlib.h`, and any other standard library includes, *after* :file:`Python.h`. On some systems, Python may define some pre-processor definitions that affect the standard headers."
msgstr"مطمئن شوید که :file:`stdlib.h` و هر سرآیند استاندارد دیگری را *بعد* از :file:`Python.h` قرار دهید. در برخی سیستمها، پایتون ممکن است تعاریف پیشپردازندهای را تعیین کند که روی سرآیندهای استاندارد تأثیر میگذارند."
msgid"Running your build tool"
msgstr"اجرای ابزار ساخت"
msgid"With only the includes in place, your extension won't do anything. Still, it's a good time to compile it and try to import it. This will ensure that your build tool works, so that you can make and test incremental changes as you follow the rest of the text."
msgstr"با قرارگیری این سرآیندها، افزونهی شما کار خاصی انجام نخواهد داد. با این حال، زمان مناسبی است که آن را کامپایل کرده و تلاش کنید ایمپورتش کنید. این کار تضمین میکند که ابزار ساخت شما بهدرستی کار میکند، بهطوری که بتوانید در حین دنبال کردن ادامهی متن، تغییرات افزایشی ایجاد کرده و آنها را آزمون کنید."
msgid"CPython itself does not come with a tool to build extension modules; it is recommended to use a third-party project for this. In this tutorial, we'll use `meson-python`_. (If you want to use another one, see :ref:`first-extension-other-tools`.)"
msgstr"سیپایتون به خودی خود ابزاری برای ساخت ماژولهای توسعهای ندارد؛ توصیه میشود برای این کار از یک پروژهی شخص ثالث استفاده کنید. در این آموزش، از `meson-python`_ استفاده خواهیم کرد. (اگر میخواهید از ابزار دیگری استفاده کنید، به :ref:`first-extension-other-tools` مراجعه کنید.)"
msgid"``meson-python`` requires defining a \"project\" using two extra files."
msgstr"ابزار ``meson-python`` نیازمند تعریف یک «پروژه» با استفاده از دو پروندهی اضافی است."
msgid"First, add ``pyproject.toml`` with these contents:"
msgstr"ابتدا پروندهی ``pyproject.toml`` را با این محتوا اضافه کنید:"
msgid""
"[build-system]\n"
"build-backend = 'mesonpy'\n"
"requires = ['meson-python']\n"
"\n"
"[project]\n"
"# Placeholder project information\n"
"# (change this before distributing the module)\n"
"name = 'sampleproject'\n"
"version = '0'"
msgstr""
"[build-system]\n"
"build-backend = 'mesonpy'\n"
"requires = ['meson-python']\n"
"\n"
"[project]\n"
"# Placeholder project information\n"
"# (change this before distributing the module)\n"
"name = 'sampleproject'\n"
"version = '0'"
msgid"Then, create ``meson.build`` containing the following:"
msgstr"سپس، پروندهی ``meson.build`` را با محتوای زیر ایجاد کنید:"
" 'spam', # name of the importable Python module\n"
" 'spammodule.c', # the C source file\n"
" install: true,\n"
")"
msgid"See the `meson-python documentation <meson-python_>`_ for details on configuration."
msgstr"برای کسب اطلاعات بیشتر دربارهی پیکربندی، به `مستندات meson-python <meson-python_>`_ مراجعه کنید."
msgid"Now, build install the *project in the current directory* (``.``) via ``pip``:"
msgstr"اکنون، پروژهی موجود در پوشهی جاری (``.``) را از طریق ``pip`` ساخت و نصب کنید:"
msgid"python -m pip -v install ."
msgstr"python -m pip -v install ."
msgid"The ``-v`` (``--verbose``) option causes ``pip`` to show the output from the compiler, which is often useful during development."
msgstr"گزینهی ``-v`` (``--verbose``) باعث میشود ``pip`` خروجی کامپایلر را نمایش دهد، که اغلب در طول توسعه مفید است."
msgid"If you don't have ``pip`` installed, run ``python -m ensurepip``, preferably in a :ref:`virtual environment <venv-def>`. (Or, if you prefer another tool that can build and install ``pyproject.toml``-based projects, use that.)"
msgstr"اگر ``pip`` را نصب ندارید، دستور ``python -m ensurepip`` را اجرا کنید، ترجیحاً در یک :ref:`محیط مجازی <venv-def>` (یا اگر ابزار دیگری را ترجیح میدهید که بتواند پروژههای مبتنی بر ``pyproject.toml`` را ساخت و نصب کند، از آن استفاده کنید.)"
msgid"Note that you will need to run this command again every time you change your extension. Unlike Python, C has an explicit compilation step."
msgstr"توجه داشته باشید که هر بار افزونهی خود را تغییر میدهید، باید این دستور را دوباره اجرا کنید. برخلاف پایتون، زبان C دارای یک مرحلهی صریح کامپایل است."
msgid"When your extension is compiled and installed, start Python and try to import it. This should fail with the following exception:"
msgstr"هنگامی که افزونهی شما کامپایلشده و نصب شد، پایتون را اجرا کرده و تلاش کنید آن را ایمپورت کنید. این کار باید با خطای زیر مواجه شود:"
msgid""
">>> import spam\n"
"Traceback (most recent call last):\n"
" ...\n"
"ImportError: dynamic module does not define module export function (PyModExport_spam or PyInit_spam)"
msgstr""
">>> import spam\n"
"Traceback (most recent call last):\n"
" ...\n"
"ImportError: dynamic module does not define module export function (PyModExport_spam or PyInit_spam)"
msgid"Module export hook"
msgstr"قلاب اکسپورت ماژول"
msgid"The exception you got when you tried to import the module told you that Python is looking for a \"module export function\", also known as a :ref:`module export hook <extension-export-hook>`. Let's define one."
msgstr"استثنایی که هنگام تلاش برای ایمپورت کردن ماژول دریافت کردید به شما گفت که پایتون به دنبال یک «تابع اکسپورت ماژول» میگردد که با نام :ref:`قلاب اکسپورت ماژول <extension-export-hook>` نیز شناخته میشود. بیایید یکی را تعریف کنیم."
msgid"First, add a prototype below the ``#include`` lines:"
msgstr"ابتدا، یک پیشنمونه در زیر سطرهای ``#include`` اضافه کنید:"
msgid""
"\n"
"PyMODEXPORT_FUNC PyModExport_spam(void);\n"
"\n"
msgstr""
"\n"
"PyMODEXPORT_FUNC PyModExport_spam(void);\n"
"\n"
msgid"The prototype is not strictly necessary, but some modern compilers emit warnings without it. It's generally better to add the prototype than to disable the warning."
msgstr"پیشنمونه به طور دقیق ضروری نیست، اما برخی از کامپایلرهای مدرن بدون آن هشدارهایی صادر میکنند. اضافه کردن پیشنمونه عموماً بهتر از غیرفعال کردن هشدار است."
msgid"The :c:macro:`PyMODEXPORT_FUNC` macro declares the function's return type, and adds any special linkage declarations needed to make the function visible and usable when CPython loads it."
msgstr"کلاندستور :c:macro:`PyMODEXPORT_FUNC` نوع بازگشت تابع را اعلام میکند و هرگونه اعلام پیوند ویژهای را که برای قابل دیدن و قابل استفاده کردن تابع هنگام بارگذاری آن توسط سیپایتون لازم است، اضافه میکند."
msgid"After the prototype, add the function itself. For now, make it return ``NULL``:"
msgstr"پس از پیشنمونه، خود تابع را اضافه کنید. فعلاً کاری کنید که ``NULL`` را برگرداند:"
msgid""
"PyMODEXPORT_FUNC\n"
"PyModExport_spam(void)\n"
"{\n"
" return NULL;\n"
"}"
msgstr""
"PyMODEXPORT_FUNC\n"
"PyModExport_spam(void)\n"
"{\n"
" return NULL;\n"
"}"
msgid"Compile and load the module again. You should get a different error this time."
msgstr"ماژول را دوباره کامپایل و بارگذاری کنید. این بار باید خطای متفاوتی دریافت کنید."
msgid""
">>> import spam\n"
"Traceback (most recent call last):\n"
" ...\n"
"SystemError: module export hook for module 'spam' failed without setting an exception"
msgstr""
">>> import spam\n"
"Traceback (most recent call last):\n"
" ...\n"
"SystemError: module export hook for module 'spam' failed without setting an exception"
msgid"Simply returning ``NULL`` is *not* correct behavior for an export hook, and CPython complains about it. That's good -- it means that CPython found the function! Let's now make it do something useful."
msgstr"صرفاً برگرداندن ``NULL`` رفتار درستی برای یک قلاب اکسپورت *نیست* و سیپایتون از آن شکایت میکند. این خوب است -- به این معنی است که سیپایتون تابع را پیدا کرده است! حالا بیایید کاری کنیم که کار مفیدی انجام دهد."
msgid"The slot table"
msgstr"جدول جایگاه"
msgid"Rather than ``NULL``, the export hook should return the information needed to create a module. Let's start with the basics: the name and docstring."
msgstr"بهجای ``NULL``، قلاب اکسپورت باید اطلاعات لازم برای ایجاد یک ماژول را برگرداند. بیایید با اصول اولیه شروع کنیم: نام و رشته مستند."
msgid"The information should be defined in an array of :c:type:`PySlot` entries, which are essentially key-value pairs. Define this array just before your export hook:"
msgstr"اطلاعات باید در آرایهای از ورودیهای :c:type:`PySlot` تعریف شوند که در واقع جفتهای کلید-مقدار هستند. این آرایه را درست قبل از قلاب اکسپورت خود تعریف کنید:"
msgid""
"PyABIInfo_VAR(abi_info);\n"
"\n"
"static PySlot spam_slots[] = {\n"
" PySlot_STATIC_DATA(Py_mod_abi, &abi_info),\n"
" PySlot_STATIC_DATA(Py_mod_name, \"spam\"),\n"
" PySlot_STATIC_DATA(Py_mod_doc, \"A wonderful module with an example function\"),\n"
" PySlot_END\n"
"};"
msgstr""
"PyABIInfo_VAR(abi_info);\n"
"\n"
"static PySlot spam_slots[] = {\n"
" PySlot_STATIC_DATA(Py_mod_abi, &abi_info),\n"
" PySlot_STATIC_DATA(Py_mod_name, \"spam\"),\n"
" PySlot_STATIC_DATA(Py_mod_doc, \"A wonderful module with an example function\"),\n"
" PySlot_END\n"
"};"
msgid"The :c:macro:`PySlot_STATIC_DATA` macro is used when the slot value (here: ``&abi_info``, ``\"spam\"``, and the docstring) is a pointer to constant, statically allocated data."
msgstr"کلاندستور :c:macro:`PySlot_STATIC_DATA` زمانی استفاده میشود که مقدار جایگاه (اینجا: ``&abi_info``، ``\"spam\"`` و رشته مستند) یک اشارهگر به دادهی ثابت و تخصیصیافتهی ایستا باشد."
msgid"The ``PyABIInfo_VAR(abi_info);`` macro and the :c:data:`Py_mod_abi` slot are a bit of boilerplate that helps prevent extensions compiled for a different version of Python from crashing the interpreter."
msgstr"کلاندستور ``PyABIInfo_VAR(abi_info);`` و جایگاه :c:data:`Py_mod_abi` مقداری کد پیشساخته هستند که کمک میکنند از کرش کردن مفسر توسط افزونههای کامپایلشده برای نسخهی متفاوتی از پایتون جلوگیری شود."
msgid"For both :c:data:`Py_mod_name` and :c:data:`Py_mod_doc`, the values are C strings -- that is, NUL-terminated, UTF-8 encoded byte arrays."
msgstr"برای هر دو :c:data:`Py_mod_name` و :c:data:`Py_mod_doc`، مقادیر رشتههای C هستند -- یعنی آرایههای بایتی پایانیافته با NUL و کدگذاریشده با UTF-8."
msgid"Note ``PySlot_END`` sentinel entry at the end. This marks the end of the array. If you forget it, you'll trigger undefined behavior."
msgstr"ورودی نشانگر ``PySlot_END`` را در انتها توجه کنید. این نشاندهندهی پایان آرایه است. اگر آن را فراموش کنید، رفتار نامشخصی را فعال خواهید کرد."
msgid"The array is defined as ``static`` -- that is, not visible outside this ``.c`` file. This will be a common theme. CPython only needs to access the export hook; all global variables and all other functions should generally be ``static``, so that they don't clash with other extensions."
msgstr"این آرایه به صورت ``static`` تعریف میشود -- یعنی خارج از این پروندهی ``.c`` قابل مشاهده نیست. این یک روند رایج خواهد بود. سیپایتون فقط باید به قلاب اکسپورت دسترسی داشته باشد؛ تمام متغیرهای سراسری و تمام عملکردهای دیگر بهطور کلی باید ``static`` باشند تا با سایر افزونهها تداخل پیدا نکنند."
msgid"Return this array from your export hook instead of ``NULL``:"
msgstr"این آرایه را بهجای ``NULL`` از قلاب (hook) اکسپورت خود برگردانید:"
msgid""
"PyMODEXPORT_FUNC\n"
"PyModExport_spam(void)\n"
"{\n"
" return spam_slots;\n"
"}"
msgstr""
"PyMODEXPORT_FUNC\n"
"PyModExport_spam(void)\n"
"{\n"
" return spam_slots;\n"
"}"
msgid"Now, recompile and try it out:"
msgstr"اکنون، برنامه را دوباره کامپایل کرده و امتحان کنید:"
msgid""
">>> import spam\n"
">>> print(spam)\n"
"<module 'spam' from '/home/encukou/dev/cpython/spam.so'>"
msgstr""
">>> import spam\n"
">>> print(spam)\n"
"<module 'spam' from '/home/encukou/dev/cpython/spam.so'>"
msgid"You have an extension module! Try ``help(spam)`` to see the docstring."
msgstr"شما یک ماژول توسعهای دارید! برای دیدن رشته مستند (docstring)، عبارت ``help(spam)`` را امتحان کنید."
msgid"The next step will be adding a function."
msgstr"گام بعدی افزودن یک تابع خواهد بود."
msgid"Exposing a function"
msgstr"عرضه کردن یک تابع"
msgid"To expose the :c:func:`system` C function directly to Python, we'll need to write a layer of glue code to convert arguments from Python objects to C values, and the C return value back to Python."
msgstr"برای عرضهی مستقیم تابع C با نام :c:func:`system` به پایتون، باید لایهای از کدهای واسط بنویسیم تا آرگومانها را از اشیاء پایتون به مقادیر C و مقدار برگشتی C را دوباره به پایتون تبدیل کنند."
msgid"One of the simplest ways to write glue code is a \":c:data:`METH_O`\" function, which takes two Python objects and returns one. All Python objects -- regardless of the Python type -- are represented in C as pointers to the :c:type:`PyObject` structure."
msgstr"یکی از سادهترین راهها برای نوشتن کدهای واسط، تابعی با نماد \":c:data:`METH_O`\" است که دو شیء پایتون را دریافت کرده و یکی را برمیگرداند. تمام اشیاء پایتون -- صرفنظر از نوع پایتون -- در زبان C به شکل اشارهگرهایی به ساختار :c:type:`PyObject` نمایش داده میشوند."
msgid"Add such a function above the slots array::"
msgstr"چنین تابعی را بالای آرایه جایگاهها (slots) اضافه کنید::"
msgid""
"static PyObject *\n"
"spam_system(PyObject *self, PyObject *arg)\n"
"{\n"
" Py_RETURN_NONE;\n"
"}"
msgstr""
"static PyObject *\n"
"spam_system(PyObject *self, PyObject *arg)\n"
"{\n"
" Py_RETURN_NONE;\n"
"}"
msgid"For now, we ignore the arguments, and use the :c:macro:`Py_RETURN_NONE` macro, which expands to a ``return`` statement that properly returns a Python :py:data:`None` object."
msgstr"فعلاً از آرگومانها صرفنظر میکنیم و از کلاندستور :c:macro:`Py_RETURN_NONE` بهره میبریم؛ این کلاندستور به یک دستور ``return`` گسترش مییابد که به شکل درستی یک شیء :py:data:`None` پایتون را برمیگرداند."
msgid"Recompile your extension to make sure you don't have syntax errors. We haven't yet added ``spam_system`` to the module, so you might get a warning that ``spam_system`` is unused."
msgstr"افزونهی خود را دوباره کامپایل کنید تا مطمئن شوید خطای نحوی ندارید. ما هنوز ``spam_system`` را به ماژول اضافه نکردهایم، بنابراین ممکن است هشداری مبنی بر استفادهنشدن از ``spam_system`` دریافت کنید."
msgid"Method definitions"
msgstr"تعاریف متدها"
msgid"To expose the C function to Python, you will need to provide several pieces of information in a structure called :c:type:`PyMethodDef` [#why-pymethoddef]_:"
msgstr"برای عرضهی تابع C به پایتون، باید چندین قطعه اطلاعات را در ساختاری به نام :c:type:`PyMethodDef` [#why-pymethoddef]_ فراهم کنید:"
msgid"``ml_name``: the name of the Python function;"
msgstr"``ml_name``: نام تابع پایتون؛"
msgid"``ml_doc``: a docstring;"
msgstr"``ml_doc``: یک رشته مستند (docstring)؛"
msgid"``ml_meth``: the C function to be called; and"
msgstr"``ml_meth``: تابع C که باید فراخوانی شود؛ و"
msgid"``ml_flags``: a set of flags describing details like how Python arguments are passed to the C function. We'll use :c:data:`METH_O` here -- the flag that matches our ``spam_system`` function's signature."
msgstr"``ml_flags``: مجموعهای از پرچمها (flags) که جزئیاتی مانند نحوهی ارسال آرگومانهای پایتون به تابع C را توصیف میکنند. ما در اینجا از :c:data:`METH_O` استفاده میکنیم -- یعنی پرچمی که با امضای تابع ``spam_system`` ما مطابقت دارد."
msgid"Because modules typically create several functions, these definitions need to be collected in an array, with a zero-filled sentinel at the end. Add this array just below the ``spam_system`` function:"
msgstr"از آنجا که ماژولها معمولاً چندین تابع ایجاد میکنند، این تعاریف باید در یک آرایه جمعآوری شوند و در انتها یک نشانگر (sentinel) صفر پرشده قرار گیرد. این آرایه را درست در پایین تابع ``spam_system`` اضافه کنید:"
msgid""
"\n"
"static PyMethodDef spam_methods[] = {\n"
" {\n"
" .ml_name=\"system\",\n"
" .ml_meth=spam_system,\n"
" .ml_flags=METH_O,\n"
" .ml_doc=\"Execute a shell command.\",\n"
" },\n"
" {NULL, NULL, 0, NULL} /* Sentinel */\n"
"};\n"
"\n"
msgstr""
"\n"
"static PyMethodDef spam_methods[] = {\n"
" {\n"
" .ml_name=\"system\",\n"
" .ml_meth=spam_system,\n"
" .ml_flags=METH_O,\n"
" .ml_doc=\"Execute a shell command.\",\n"
" },\n"
" {NULL, NULL, 0, NULL} /* Sentinel */\n"
"};\n"
"\n"
msgid"As with module slots, a zero-filled sentinel marks the end of the array."
msgstr"همانند جایگاههای ماژول، یک نشانگر صفرگذاریشده پایان آرایه را مشخص میکند."
msgid"Next, we'll add the method to the module. Add a :c:data:`Py_mod_methods` slot to your :c:type:`PyMethodDef` array:"
msgstr"در ادامه، متد را به ماژول اضافه میکنیم. یک جایگاه :c:data:`Py_mod_methods` به آرایهی :c:type:`PyMethodDef` خود اضافه کنید:"
msgid""
"\n"
"PyABIInfo_VAR(abi_info);\n"
"\n"
"static PySlot spam_slots[] = {\n"
" PySlot_STATIC_DATA(Py_mod_abi, &abi_info),\n"
" PySlot_STATIC_DATA(Py_mod_name, \"spam\"),\n"
" PySlot_STATIC_DATA(Py_mod_doc, \"A wonderful module with an example function\"),\n"
msgid"Recompile your extension again, and test it. Be sure to restart the Python interpreter, so that ``import spam`` picks up the new version of the module."
msgstr"افزونهی خود را مجدداً کامپایل و آن را آزمون کنید. حتماً مفسر پایتون را راهاندازی مجدد کنید تا ``import spam`` نسخهی جدید ماژول را بارگذاری کند."
msgid"You should now be able to call the function:"
msgstr"اکنون باید بتوانید تابع را فراخوانی کنید:"
msgid""
">>> import spam\n"
">>> print(spam.system)\n"
"<built-in function system>\n"
">>> print(spam.system('whoami'))\n"
"None"
msgstr""
">>> import spam\n"
">>> print(spam.system)\n"
"<built-in function system>\n"
">>> print(spam.system('whoami'))\n"
"None"
msgid"Note that our ``spam.system`` does not yet run the ``whoami`` command; it only returns ``None``."
msgstr"توجه داشته باشید که ``spam.system`` ما هنوز دستور ``whoami`` را اجرا نمیکند؛ بلکه فقط مقدار ``None`` را برمیگرداند."
msgid"Check that the function accepts exactly one argument, as specified by the :c:data:`METH_O` flag:"
msgstr"بررسی کنید که تابع، همانطور که با پرچم :c:data:`METH_O` مشخص شده است، دقیقاً یک آرگومان بپذیرد:"
"TypeError: spam.system() takes exactly one argument (3 given)"
msgid"Returning an integer"
msgstr"برگرداندن یک عدد صحیح"
msgid"Now, let's take a look at the return value. Instead of ``None``, we'll want ``spam.system`` to return a number -- that is, a Python :py:type:`int` object. Eventually this will be the exit code of a system command, but let's start with a fixed value, say, ``3``."
msgstr"اکنون، بیایید نگاهی به مقدار بازگشتی بیندازیم. بهجای ``None``، میخواهیم ``spam.system`` یک عدد -- یعنی یک شیء :py:type:`int` پایتون -- برگرداند. در نهایت این مقدار، کد خروج یک دستور پوسته خواهد بود، اما بیایید با یک مقدار ثابت، مثلاً ``3``، شروع کنیم."
msgid"The Python C API provides a function to create a Python :py:type:`int` object from a C ``int`` value: :c:func:`PyLong_FromLong`. [#why-pylongfromlong]_"
msgstr"رابط برنامهنویسی کاربردی C پایتون تابعی برای ایجاد یک شیء :py:type:`int` پایتون از یک مقدار ``int`` زبان C فراهم میکند: :c:func:`PyLong_FromLong`. [#why-pylongfromlong]_"
msgid"To call it, replace the ``Py_RETURN_NONE`` with the following 3 lines:"
msgstr"برای فراخوانی آن، ``Py_RETURN_NONE`` را با ۳ سطر زیر جایگزین کنید:"
msgid""
"static PyObject *\n"
"spam_system(PyObject *self, PyObject *arg)\n"
"{\n"
" int status = 3;\n"
" PyObject *result = PyLong_FromLong(status);\n"
" return result;\n"
"}"
msgstr""
"static PyObject *\n"
"spam_system(PyObject *self, PyObject *arg)\n"
"{\n"
" int status = 3;\n"
" PyObject *result = PyLong_FromLong(status);\n"
" return result;\n"
"}"
msgid"Recompile, restart the Python interpreter again, and check that the function now returns 3:"
msgstr"مجدداً کامپایل کنید، مفسر پایتون را راهاندازی مجدد کنید و بررسی کنید که تابع اکنون عدد ۳ را برمیگرداند:"
msgid""
">>> import spam\n"
">>> spam.system('whoami')\n"
"3"
msgstr""
">>> import spam\n"
">>> spam.system('whoami')\n"
"3"
msgid"Accepting a string"
msgstr"پذیرش یک رشته"
msgid"Finally, let's handle the function argument."
msgstr"در نهایت، بیایید آرگومان تابع را مدیریت کنیم."
msgid"Our C function, :c:func:`!spam_system`, takes two arguments. The first one, ``PyObject *self``, will be set to the ``spam`` module object. This isn't useful in our case, so we'll ignore it."
msgstr"تابع C ما، یعنی :c:func:`!spam_system`، دو آرگومان میپذیرد. اولین آرگومان، یعنی ``PyObject *self``، روی شیء ماژول ``spam`` تنظیم خواهد شد. این مورد در سناریوی ما کاربردی ندارد، بنابراین آن را نادیده میگیریم."
msgid"The other one, ``PyObject *arg``, will be set to the object that the user passed from Python. We expect that it should be a Python string. In order to use the information in it, we will need to convert it to a C value -- in this case, a C string (``const char *``)."
msgstr"مورد دیگر، یعنی ``PyObject *arg``، به شیءای که کاربر از پایتون ارسال کرده است تنظیم خواهد شد. انتظار داریم که این شیء یک رشتهی پایتون باشد. برای استفاده از اطلاعات موجود در آن، باید آن را به یک مقدار C -- در اینجا، یک رشتهی C (``const char *``) -- تبدیل کنیم."
msgid"There's a slight type mismatch here: Python's :py:class:`str` objects store Unicode text, but C strings are arrays of bytes. So, we'll need to *encode* the data, and we'll use the UTF-8 encoding for it. (UTF-8 might not always be correct for system commands, but it's what :py:meth:`str.encode` uses by default, and the C API has special support for it.)"
msgstr"در اینجا ناسازگاری کوچکی در نوع داده وجود دارد: اشیاء :py:class:`str` در پایتون متن یونیکد را ذخیره میکنند، اما رشتههای C آرایههایی از بایتها هستند. بنابراین، باید دادهها را *کدگذاری* (encode) کنیم و برای این کار از کدگذاری UTF-8 استفاده خواهیم کرد. (ممکن است UTF-8 همیشه برای دستورات سیستم درست نباشد، اما همان چیزی است که :py:meth:`str.encode` بهطور پیشفرض استفاده میکند و C API پشتیبانی ویژهای از آن دارد.)"
msgid"The function to encode a Python string into a UTF-8 buffer is named :c:func:`PyUnicode_AsUTF8AndSize` [#why-pyunicodeasutf8]_. Call it like this:"
msgstr"تابع برای کدگذاری یک رشتهی پایتون در یک بافر UTF-8 :c:func:`PyUnicode_AsUTF8AndSize` [#why-pyunicodeasutf8]_ نام دارد. آن را به این صورت فراخوانی کنید:"
msgid"If :c:func:`PyUnicode_AsUTF8AndSize` is successful, *command* will point to the resulting C string -- a zero-terminated array of bytes [#embedded-nul]_. This buffer is managed by the *arg* object, which means we don't need to free it, but we must follow some rules:"
msgstr"اگر :c:func:`PyUnicode_AsUTF8AndSize` موفقیتآمیز باشد، *command* به رشتهی C حاصل -- یک آرایهی بایت ختمشده با صفر [#embedded-nul]_ -- اشاره خواهد کرد. این بافر توسط شیء *arg* مدیریت میشود، به این معنی که نیازی به آزادسازی آن نداریم، اما باید چند قانون را رعایت کنیم:"
msgid"We should only use the buffer inside the ``spam_system`` function. After ``spam_system`` returns, *arg* and the buffer it manages might be garbage-collected."
msgstr"ما باید فقط از بافر درون تابع ``spam_system`` استفاده کنیم. پس از اینکه ``spam_system`` برگردد، ممکن است *arg* و بافری که مدیریت میکند زبالهروبی (garbage-collected) شوند."
msgid"We must not modify it. This is why we use ``const``."
msgstr"ما نباید آن را تغییر دهیم. به همین دلیل است که از ``const`` استفاده میکنیم."
msgid"If :c:func:`PyUnicode_AsUTF8AndSize` was *not* successful, it returns a ``NULL`` pointer. When calling *any* Python C API, we always need to handle such error cases. The way to do this in general is left for later chapters of this documentation. For now, be assured that we are already handling errors from :c:func:`PyLong_FromLong` correctly."
msgstr"اگر :c:func:`PyUnicode_AsUTF8AndSize` موفقیتآمیز *نباشد*، یک اشارهگر ``NULL`` برمیگرداند. هنگام فراخوانی *هر* C API پایتون، همیشه باید چنین مواردی از خطا را مدیریت کنیم. روش انجام این کار بهطور کلی به فصول بعدی این مستندات موکول میشود. فعلاً مطمئن باشید که ما در حال حاضر خطاهای :c:func:`PyLong_FromLong` را به درستی مدیریت میکنیم."
msgid"For the :c:func:`PyUnicode_AsUTF8AndSize` call, the correct way to handle errors is returning ``NULL`` from ``spam_system``. Add an ``if`` block for this:"
msgstr"برای فراخوانی :c:func:`PyUnicode_AsUTF8AndSize`، روش صحیح مدیریت خطاها برگرداندن ``NULL`` از ``spam_system`` است. یک بلوک ``if`` برای این کار اضافه کنید:"
msgid"To test that error handling works, compile again, restart Python so that ``import spam`` picks up the new version of your module, and try passing a non-string value to your function:"
msgstr"برای آزمون اینکه مدیریت خطا کار میکند، دوباره کامپایل کنید، پایتون را مجدداً راهاندازی کنید تا ``import spam`` نسخهی جدید ماژول شما را بارگیری کند، و سعی کنید یک مقدار غیررشتهای به تابع خود ارسال کنید:"
msgid""
">>> import spam\n"
">>> spam.system(3)\n"
"Traceback (most recent call last):\n"
" ...\n"
"TypeError: bad argument type for built-in operation"
msgstr""
">>> import spam\n"
">>> spam.system(3)\n"
"Traceback (most recent call last):\n"
" ...\n"
"TypeError: bad argument type for built-in operation"
msgid"Now, all that is left is calling the C library function :c:func:`system` with the ``char *`` buffer, and using its result instead of the ``3``:"
msgstr"اکنون، تنها چیزی که باقی مانده است فراخوانی تابع کتابخانهی C :c:func:`system` با بافر ``char *`` و استفاده از نتیجهی آن به جای ``3`` است:"
msgid"Compile your module, restart Python, and test. This time, you should see your username -- the output of the ``whoami`` system command:"
msgstr"ماژول خود را کامپایل کنید، پایتون را مجدداً راهاندازی کنید و آزمون کنید. این بار، باید نام کاربری خود را -- که خروجی دستور سیستمی ``whoami`` است -- ببینید:"
msgid""
">>> import spam\n"
">>> result = spam.system('whoami')\n"
"User Name\n"
">>> result\n"
"0"
msgstr""
">>> import spam\n"
">>> result = spam.system('whoami')\n"
"User Name\n"
">>> result\n"
"0"
msgid"You can also test with other commands, like ``ls``, ``dir``, or one that doesn't exist:"
msgstr"همچنین میتوانید با دستورات دیگر، مانند ``ls``، ``dir``، یا دستوری که وجود ندارد، آزمون کنید:"
msgid""
">>> import spam\n"
">>> result = spam.system('nonexistent-command')\n"
"sh: line 1: nonexistent-command: command not found\n"
">>> result\n"
"32512"
msgstr""
">>> import spam\n"
">>> result = spam.system('nonexistent-command')\n"
"sh: line 1: nonexistent-command: command not found\n"
">>> result\n"
"32512"
msgid"The result"
msgstr"نتیجه"
msgid"Congratulations! You have written a complete Python C API extension module, and completed this tutorial!"
msgstr"تبریک میگوییم! شما یک ماژول توسعهای کامل با C API پایتون نوشتهاید و این آموزش را به پایان رساندهاید!"
msgid"Here is the entire source file, for your convenience:"
msgstr"برای راحتی شما، کل پروندهی سورس در ادامه آورده شده است:"
msgid"You should be able to follow this tutorial -- except the *Running your build tool* section itself -- with a build tool other than ``meson-python``."
msgstr"شما باید بتوانید این خودآموز را — به جز خود بخش *Running your build tool* — با ابزار ساختی به غیر از ``meson-python`` دنبال کنید."
msgid"The Python Packaging User Guide has a `list of recommended tools <https://packaging.python.org/en/latest/guides/tool-recommendations/#build-backends-for-extension-modules>`_; be sure to choose one for the C language."
msgstr"«راهنمای کاربر بستهبندی پایتون» دارای یک `فهرست از ابزارهای توصیهشده <https://packaging.python.org/en/latest/guides/tool-recommendations/#build-backends-for-extension-modules>`_ است؛ حتماً یکی را برای زبان C انتخاب کنید."
msgid"Workaround for missing PyInit function"
msgstr"راهحل موقت برای تابع PyInit گمشده"
msgid"If your build tool output complains about missing ``PyInit_spam``, add the following function to your module for now:"
msgstr"اگر خروجی ابزار ساخت شما از گم شدن ``PyInit_spam`` گله میکند، فعلاً تابع زیر را به ماژول خود اضافه کنید:"
msgid""
"// A workaround\n"
"void *PyInit_spam(void) { return NULL; }"
msgstr""
"// A workaround\n"
"void *PyInit_spam(void) { return NULL; }"
msgid"This is a shim for an old-style :ref:`initialization function <extension-export-hook>`, which was required in extension modules for CPython 3.14 and below. Current CPython does not need it, but some build tools may still assume that all extension modules need to define it."
msgstr"این یک لایه (shim) برای :ref:`تابع مقداردهی اولیهی <extension-export-hook>` سبک قدیم است که در ماژولهای توسعهای برای سیپایتون نسخهی ۳.۱۴ و پایینتر الزامی بود. سیپایتون فعلی به آن نیازی ندارد، اما برخی از ابزارهای ساخت ممکن است همچنان فرض کنند که تمام ماژولهای توسعهای باید آن را تعریف کنند."
msgid"If you use this workaround, you will get the exception ``SystemError: initialization of spam failed without raising an exception`` instead of ``ImportError: dynamic module does not define module export function``."
msgstr"اگر از این راهحل موقت استفاده کنید، به جای ``ImportError: dynamic module does not define module export function``، استثنای ``SystemError: initialization of spam failed without raising an exception`` را دریافت خواهید کرد."
msgid"Compiling directly"
msgstr"کامپایل مستقیم"
msgid"Using a third-party build tool is heavily recommended, as it will take care of various details of your platform and Python installation, of naming the resulting extension, and, later, of distributing your work."
msgstr"استفاده از یک ابزار ساخت شخص ثالث بسیار توصیه میشود، زیرا به جزئیات مختلف پلتفرم و نصب پایتون شما، نامگذاری اکستنشن حاصل و بعداً توزیع کار شما رسیدگی میکند."
msgid"If you are building an extension for as *specific* system, or for yourself only, you might instead want to run your compiler directly. The way to do this is system-specific; be prepared for issues you will need to solve yourself."
msgstr"اگر در حال ساخت یک اکستنشن برای یک سیستم *خاص* هستید، یا فقط برای خودتان، ممکن است بخواهید مستقیماً کامپایلر خود را اجرا کنید. نحوهی انجام این کار سیستممحور است؛ برای مشکلاتی که باید خودتان حل کنید آماده باشید."
msgid"Linux"
msgstr"لینوکس"
msgid"On Linux, the Python development package may include a ``python3-config`` command that prints out the required compiler flags. If you use it, check that it corresponds to the CPython interpreter you'll use to load the module. Then, start with the following command:"
msgstr"روی لینوکس، بستهی توسعهی پایتون ممکن است شامل دستوری به نام ``python3-config`` باشد که پرچمهای لازم کامپایلر را چاپ میکند. اگر از آن استفاده میکنید، بررسی کنید که با مفسر سیپایتونی که برای بارگذاری ماژول استفاده خواهید کرد مطابقت داشته باشد. سپس با دستور زیر شروع کنید:"
msgid"The source file name is entirely up to you, though some tools can be picky about the ``.c`` extension. This tutorial uses the traditional ``*module.c`` suffix. Some people would just use :file:`spam.c` to implement a module named ``spam``, projects where Python isn't the primary language might use ``py_spam.c``, and so on."
msgstr"نام پروندهی سورس کاملاً به خود شما بستگی دارد، گرچه برخی ابزارها ممکن است در مورد پسوند ``.c`` سختگیر باشند. این خودآموز از پسوند سنتی ``*module.c`` استفاده میکند. برخی افراد ممکن است به سادگی از :file:`spam.c` برای پیادهسازی ماژولی به نام ``spam`` استفاده کنند، پروژههایی که پایتون زبان اصلی آنها نیست ممکن است از ``py_spam.c`` استفاده کنند و غیره."
msgid"Including :file:`stdlib.h` is technically not necessary, since :file:`Python.h` includes it and :ref:`several other standard headers <capi-system-includes>` for its own use or for backwards compatibility. However, it is good practice to explicitly include what you need."
msgstr"گنجاندن :file:`stdlib.h` از نظر فنی ضروری نیست؛ زیرا :file:`Python.h` آن را به همراه :ref:`چندین سرآیند استاندارد دیگر <capi-system-includes>` برای استفادهی خود یا سازگاری با نسخههای پیشین فراخوانی میکند. با این حال، شیوهی نیکو آن است که آنچه را نیاز دارید بهطور صریح اضافه کنید."
msgid"The :c:type:`!PyMethodDef` structure is also used to create methods of classes, so there's no separate \":c:type:`!PyFunctionDef`\"."
msgstr"ساختار :c:type:`!PyMethodDef` همچنین برای ایجاد متدهای کلاسها استفاده میشود، بنابراین ساختار جداگانهای به نام \":c:type:`!PyFunctionDef`\" وجود ندارد."
msgid"The name :c:func:`PyLong_FromLong` might not seem obvious. ``PyLong`` refers to a the Python :py:class:`int`, which was originally called ``long``; the ``FromLong`` refers to the C ``long`` (or ``long int``) type."
msgstr"نام :c:func:`PyLong_FromLong` ممکن است واضح به نظر نرسد. ``PyLong`` به :py:class:`int` پایتون اشاره دارد که در اصل ``long`` نامیده میشد؛ عبارت ``FromLong`` به نوع ``long`` (یا ``long int``) در زبان C اشاره دارد."
msgid"Here, ``PyUnicode`` refers to the original name of the Python :py:class:`str` class: ``unicode``."
msgstr"در اینجا، ``PyUnicode`` به نام اصلی کلاس :py:class:`str` در پایتون اشاره دارد: ``unicode``."
msgid"The ``AndSize`` part of the name refers to the fact that this function can also retrieve the size of the buffer, using an output argument. We don't need this, so we set the second argument to NULL."
msgstr"بخش ``AndSize`` از نام به این واقعیت اشاره دارد که این تابع همچنین میتواند با استفاده از یک آرگومان خروجی، اندازهی بافر را بازیابی کند. ما به این مورد نیازی نداریم، بنابراین آرگومان دوم را روی NULL تنظیم میکنیم."
msgid"We're ignoring the fact that Python strings can also contain NUL bytes, which terminate a C string. In other words, our function will treat ``spam.system(\"foo\\0bar\")`` as ``spam.system(\"foo\")``. This possibility can lead to security issues, so the real ``os.system`` function size checks for this case and raises an error."
msgstr"ما این حقیقت را نادیده میگیریم که رشتههای پایتون میتوانند حاوی بایتهای NUL نیز باشند که یک رشتهی C را پایان میدهند. به عبارت دیگر، تابع ما عبارت ``spam.system(\"foo\\0bar\")`` را به شکل ``spam.system(\"foo\")`` در نظر خواهد گرفت. این احتمال میتواند به مشکلات امنیتی منجر شود، بنابراین تابع واقعی ``os.system`` اندازهی بافر را برای این مورد بررسی کرده و خطایی را صادر میکند."