اگر شما در دنیای علوم داده یا محاسبات علمی از پایتون استفاده می کنید، به زودی متوجه خواهید شد که پایتون دو سیستم مدیریت پکیج متفاوت دارد: Pip و Conda. این مسأله سؤالی را پیش می کشد:
- این دو چه تفاوتی دارند؟
- چه برتری هایی در نسبت با هم دارند؟
- بهتر است کدام یک را انتخاب کنید؟
هرچند ممکن نیست به این سؤالات پاسخی جامع و همیشه درست داد، به هر حال در این مقاله تفاوتهای اساسی را یاد می گیرید، البته با در نظر گرفتن اینکه:
- تنها معطوف به پایتون هستیم؛ هرچند Conda از دیگر زبانها نیز پشتیبانی میکند اما من به آن نمی پردازم.
- اولویت با لینوکس است، به علاوه اجرا روی داکر (Docker) هم چنین همراه با اشاراتی به macOS و ویندوز.
- روی مخزن پکیج Conda-Forge تمرکز داریم؛ Conda چندین مخزن پکیج (کانال) دارد.
در انتها شما متوجه میشوید چرا Conda ساخته شده است، چه زمانی ممکن است از آن استفاده کنید و چه هزینه و فایده ای برای انتخاب هر یک از آنها وجود دارد.
نقطه شروع: چه نوع متعلقاتی؟
تفاوت اصلی بین Pip و Conda در این است که چه چیزی را داخل پکیج ها می گذارند.
- پکیج های Pip عبارتند از کتابخانههای پایتون نظیر NumPy یا matplotlib.
- پکیج های Conda شامل کتابخانههای پایتونی (نظیر NumPy یا matplotlib)، کتابخانههای C (مثل libjpeg) و فایلهای اجرایی (مثل کامپایلرهای C یا حتی خود مفسر پایتون) هستند.
Pip: فقط کتابخانههای پایتون
به عنوان مثال، فرض کنیم میخواهید پایتون ۳.۹ را به همراه NumPy و Pandas در کنار ابزار رندرینگ gnuplot نصب کنید که البته این ابزار ارتباطی به پایتون ندارد. محتوای فایل requirements.txt برای pip به این صورت است:
numpy
pandas
نصب پایتون و gnuplot از عهده pip خارج است. شما به عنوان کاربر خودتان باید فکری به حال این دو بکنید. شاید شما مثلاً با ایمیج Docker به این صورت انجامش دهید:
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y gnuplot python3.9
COPY requirements.txt .
RUN pip install -r requirements.txt
پایتون و gnuplot باید از پکیج های سیستمی ، مثلا پکیج های اوبونتو، اضافه بشوند.
Conda: (تقریبا) هر جور متعلقاتی می تونه یک پکیج Conda باشه.
برای Conda، پایتون و gnuplot هم فقط یکسری پکیج Conda هستند، مثل NumPy یا Pandas. در ادامه محتوای فایل environment.yml را می بینیم که یک جورهایی شبیه requirements.txt بوده و همه این پکیج ها را شامل می شود:
name: myenv
channels:
- conda-forge
dependencies:
- python=3.9
- numpy
- pandas
- gnuplot
Conda فقط برای بعضی از امکانات اولیه به سیستم عامل متکی است؛ مثل کتابخانههای استاندارد C. به جز آن ها، همه چیز یک پکیج Conda است و نه یک پکیج سیستمی.
ما میتوانیم این تفاوت را در Dockerfile مربوطه هم ببینیم؛ اصلاً نیازی نیست برای اجرا، هیچ پکیج سیستمی را نصب کنیم.
FROM continuumio/miniconda3
COPY environment.yml .
RUN conda env create
این ایمیج اولیه با Conda ی از پیش نصب شده تحویل داده می شود، در حالی که ما به هیچ نصب پایتونی متکی نیستیم؛ ما یک نصب جدید در یک محیط جدید ایجاد می کنیم.
توجه: در این مقاله استفاده از Dockerfile ها اصلاً best practice نیست، چون پیچیدگی به مساله اضافه میکنند و در نتیجه هدف اصلی مقاله را تحت شعاع قرار می دهد.
چرا Conda همه چیز را پکیج می کند؟
چرا Conda تصمیم گرفته همه چیز، از جمله مفسر پایتون را پکیج کند؟ چه فایده ای دارد؟ میتوان گفت این کار به قابل حمل بودن و تکرار پذیری کمک می کند.
قابل حمل بودن در نسبت با سیستم عامل: به جای نصب پایتون به سه روش مختلف روی linux، macOS و ویندوز، میتوانیم یک environment.yml مشابه را برای هر سه استفاده کنیم.
تکرارپذیری: با اینکار میتوان تقریبا کل استک پروژه را یک جا کرد؛ از مفسر پایتون بگیر تا به بالا!
پیکربندی یک دست: نیازی نیست پکیج های سیستمی و پایتونی را جدا و از دو راه مختلف نصب کنید؛ (اکثرا) همه چیز با یک فایل انجام می شود: فایل environment.yml.
البته برای مشکلی دیگر نیز راهکار دارد: اینکه چطور باید با کتابخانههای پایتونی ای که به کدهای کامپایل شده نیاز دارند کار کنیم. این موضوع آنقدر بزرگ است که میتوانیم در یک بخش جدید، در ادامه به آن بپردازیم.
ورای پایتون خالص: پکیجینگ افزونه های کامپایل شده
در روزهای ابتدایی شروع پکیجینگ پایتون، یک پکیج فقط شامل کد مرجعی بود که باید نصب می شد. این روش برای پکیج های کاملاً پایتونی به خوبی کار کرده و می کند. اما اگر به عنوان بخشی از ساخت پکیج به کامپایل کردن یک تکه کد Rust یا C یا C++ یا فرترن نیاز داشته باشید چه باید کرد؟
راهکار شماره ۱: خودت کامپایلش کن
راه اصلی این است که هر کاربر خودش کدش را حین نصب کامپایل کند. این روند می تواند تا حدی کند، هزینه بر، با پیکربندی زجر آور باشه و هنوز هم مشکل اصلی را حل نمی کند: متعلقات اشتراکی کتابخانه.
به عنوان مثال، کتابخانه تصاویر گرافیکی Pillow به کتابخانههای خارجی اشتراکی نظیر libpng و libjpeg متکی است. برای اینکه Pillow را خودتان کامپایل کنید، باید همه آن ها را نصب کنید، به علاوه هدر توسعه هر کدام (که باید فکری برایش کرد). روی لینوکس یا مک می توانید پکیج های سیستمی یا پکیج های Homebrew نصب کنید؛ ولی برای ویندوز این کار می تواند سخت تر باشد. اما شما مجبورید برای هر سیستم عامل یا حتی هر توزیع لینوکسی یک پیکربندی جدا بنویسید.
راهکار شماره ۲: Pip wheels
راهی که Pip برای حل این مشکل ارائه داده استفاده از پکیج هایی به اسم «wheels» هست که میتوانند کدهای کامپایل شده را شامل شوند. برای حل مشکل متعلقات کتابخانههای اشتراکی مثل libpng، هر یک از آن متعلقات خارجی داخل خود wheel اصطلاحاً bundle می شود.
به عنوان مثال، بیایید به Pillow wheel لینوکس نگاهی بیاندازیم؛ یک wheel فقط یک فایل ZIP است که میتوانیم با یک ابزار استاندارد ZIP بازش کنیم:
$ zipinfo Pillow.whl
...
Pillow.libs/libpng16-213e245f.so.16.37.0
Pillow.libs/libjpeg-183418da.so.9.4.0
...
PIL/FpxImagePlugin.py
PIL/PalmImagePlugin.py
...
PIL/_imagingcms.cpython-39-x86_64-linux-gnu.so
…
این wheel شامل کد پایتون، یک افزونه کامپایل شده پایتونی، و کتابخانههای third-party اشتراکی مثل libpng و libjpeg است. این روش گاهی اوقات پکیج ها را سنگین می کند، چون ممکن است به ازای یک wheel چند کپی از کتابخانههای اشتراکی third-party نصب شده باشند.
راهکار شماره ۳: پکیج های Conda
پکیج های Conda راهکار دیگری برای کتابخانههای اشتراکی third-party دارد. libpng و libjpeg به عنوان پکیج های فرعی Conda پک شده اند:
$ conda install -c conda-forge pillow
...
The following NEW packages will be INSTALLED:
...
jpeg conda-forge/linux-64::jpeg-9d-h36c2ea0_0
...
libpng conda-forge/linux-64::libpng-1.6.37-h21135ba_2
...
pillow conda-forge/linux-64::pillow-7.2.0-py38h9776b28_2
zstd conda-forge/linux-64::zstd-1.5.0-ha95c52a_0
...
حالا این libjpeg و libpng های نصب شده میتوانند به دیگر پکیج های نصب شده ربط پیدا کنند. آنها مختص wheel خاصی نیستند و در دسترس هر پکیج دیگری در محیط Conda خواهند بود.
Conda چون فقط یک سیستم پکیجینگ مخصوص پایتون نیست توان این کار را دارد؛ چرا که میتواند به همین راحتی از کتابخانههای اشتراکی و فایلهای اجرایی پکیج بسازد.
خلاصه: Pip یا Conda
پی نوشت: در بخش دوم این مقاله به مقایسه PyPI با Conda-Forge می پردازم.
منبع: این مطلب ترجمه بخش اول این مقاله است.