<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های Pooya Dowlat Abadi</title>
        <link>https://virgool.io/feed/@pooyadowlat</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-06-17 12:50:12</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/1276686/avatar/avatar.png?height=120&amp;width=120</url>
            <title>Pooya Dowlat Abadi</title>
            <link>https://virgool.io/@pooyadowlat</link>
        </image>

                    <item>
                <title>برنامه‌های سازمان‌ یافته‌تر در پایتون - relative import - قسمت پنجم</title>
                <link>https://virgool.io/@pooyadowlat/%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D9%87%D8%A7%DB%8C-%D8%B3%D8%A7%D8%B2%D9%85%D8%A7%D9%86-%DB%8C%D8%A7%D9%81%D8%AA%D9%87-%D8%AA%D8%B1-%D8%AF%D8%B1-%D9%BE%D8%A7%DB%8C%D8%AA%D9%88%D9%86-relative-import-%D9%82%D8%B3%D9%85%D8%AA-%D9%BE%D9%86%D8%AC%D9%85-cpmmvty1ztnb</link>
                <description>در قسمت قبل ساخت یک زیرپکیج یا sub package رو با هم انجام دادیم و یاد گرفتیم حالا در این قسمت می‌خوایم relative import رو یاد بگیریم، اما سوال اصلی اینه که فرق absolute import با relative import چیه؟دو مدل import داریم به طور کلی که شامل relative import و absolute import میشهدر مدل اول که absolute import هستش ما به دو صورت پکیج‌ها و فانکشن‌ها رو می‌تونیم ایمپورت کنیمimport demo_reader.compressed.bzippedمدل اول هستش که با همون اسم باید استفاده‌اش کنیم یعنی هر جا که بخوایم استفاده کنیم باید به این شکل اونو استفاده کنیمdemo_reader.compressed.bzipped()مدل دوم که کار کردن باهاش راحت‌تره ولی وقتی تعداد زیادی فانکشن هم اسم داشته باشیم کار باهاش سخت می‌شه مدل زیر هستشfrom demo_reader.compressed import bzippedکه می‌تونیم به روش زیر ازش استفاده کنیمbzipped()حالا اگر بخوایم حالت سوم که میشه relative import رو بررسی کنیم حالت زیر رو در نظر بگیریدfrom ..module import nameاون دو نقطه یعنی دو فولدر یا دو پکیج عقب‌تر برگرده یعنی نقطه سمت راست میشه والد ماژول فعلی و نقطه بعد میشه والد والد فعلی(معادل پدربزرگ/مادربزرگ)دو قانون اصلی داریم توی relative import که شامل برعکس حالت اول مدل absolute نمی‌تونیم از اون حالت استفاده کنیم یعنی فقط از حالت زیر می‌توانیم استفاده کنیمfrom module import nameاز relative import نمی‌توانیم برای import کردن پکیج‌های دیگر که در پکیج‌مون نیستن استفاده کنیم و فقط از پکیج‌هایی که در پکیج‌اصلی هستند استفاده کنیم.حالا با چیزهایی که یاد گرفتیم بیایم و یکمی روی برنامه‌ای که تا این مرحله روش کار کردیم تغییراتی ایجاد کنیم و نحوه استفاده ازش رو ببینیمدر داخل فولدر demo_reader یک فولدر جدید ایجاد کنید به اسم util و مانند آموزش‌های قبلی __init__ رو بسازید و هم‌چنین یک فایل جدید به اسم writer.py بسازید و محتویات زیر رو داخل اون قرار بدیدimport sys


def main(opener):
    &amp;quot&amp;quot&amp;quot
    Opens the file and writes the data to it.
    &amp;quot&amp;quot&amp;quot
    f = opener(sys.argv[1], mode=&amp;quotwt&amp;quot)
    f.write(&amp;quot &amp;quot.join(sys.argv[2:]))
    f.close()حالا می‌تونیم ماژول‌های قبلی رو که کدهای تکراری داشت رو حذف کنیم و از فایل util.writer که ایجاد کردیم داخل اون‌ها استفاده کنیمبه فایل bzipped.py بروید و محتویات اون رو ادیت کنیدimport bz2
from demo_reader.util import writer
opener = bz2.open

if __name__ == &#039;__main__&#039;:
    writer.main(opener)حالا به فایل gzipped.py بروید و محتویات اون رو هم ادیت کنیدimport gzip
from demo_reader.util import writer
opener = gzip.open

if __name__ == &#039;__main__&#039;:
    writer.main(opener)حالا این روشی بود که از absolute import استفاده می‌کنه اما ما می‌تونیم از relative import استفاده کنیم که خیلی راحت‌تر این کارو انجام بدیمimport bz2
from ..util import writer
opener = bz2.open

if __name__ == &#039;__main__&#039;:
    writer.main(opener)و فایل gzipped.py هم محتویات زیر رو میگیرهimport gzip from ..util import writer opener = gzip.open  if __name__ == &#039;__main__&#039;:       writer.main(opener)خلاصه(حوصله نداشتید بخونید)from . import name                                                      from demo_reader.compressed import namefrom .. import name                                                     from demo_reader import namefrom ..util import writer                                                from demo_reader.util import nameسمت چپ حالت relative import هستش و سمت راست حالت absolute import خواهد بودامیدوارم از این قسمت لذت برده باشید</description>
                <category>Pooya Dowlat Abadi</category>
                <author>Pooya Dowlat Abadi</author>
                <pubDate>Sun, 09 Jan 2022 14:38:48 +0330</pubDate>
            </item>
                    <item>
                <title>برنامه‌های سازمان‌ یافته‌تر در پایتون - قسمت چهارم - ساخت یک زیرپکیج</title>
                <link>https://virgool.io/@pooyadowlat/%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D9%87%D8%A7%DB%8C-%D8%B3%D8%A7%D8%B2%D9%85%D8%A7%D9%86-%DB%8C%D8%A7%D9%81%D8%AA%D9%87-%D8%AA%D8%B1-%D8%AF%D8%B1-%D9%BE%D8%A7%DB%8C%D8%AA%D9%88%D9%86-%D9%82%D8%B3%D9%85%D8%AA-%DA%86%D9%87%D8%A7%D8%B1%D9%85-%D8%B3%D8%A7%D8%AE%D8%AA-%DB%8C%DA%A9-%D8%B2%DB%8C%D8%B1%D9%BE%DA%A9%DB%8C%D8%AC-qwog1i84jnm5</link>
                <description>ما در قسمت‌های قبل تا جایی پیش اومدیم که یک پکیج ساختیم و اون پکیج رو استفاده کردیم اما هنوز بسیار با مرحله‌ای که شبیه بیشتر پکیج‌های پایتونی باشه فاصله داریم در نتیجه در این مرحله زیرپکیج‌ها (Subpackages) رو بررسی می‌کنیم و ازشون استفاده می‌کنیم.در این مرحله اسم فولدری که ساخته بودیم رو از package_root به demo_reader تغییر بدیددر محل demo_reader یک فولدر جدید با اسم compressed بسازید که میشه اولین ساب‌پکیج‌ مامثل مرحله ساختن یک پکیج ما داخل این فولدر یک فایل __init__ می‌سازیم و توش هر چیزی که می‌خوایم رو می‌نویسیم، توی مرحله‌های قبلی توضیح دادیم که این فرمت اجباری نیست ولی کمک می‌کنه کسی که داره کدمارو هر جایی می‌خونه بفهمه چرا این کد این شکلی کار می‌کنه و یک پکیج هستش.بعد از ساختن compressed یک فایل gzipped.py می‌سازیم که داخل اون محتویات زیر رو قرار میدیمimport gzip
import sys

opener = gzip.open

if __name__ == &#039;__main__&#039;:
    f = gzip.open(sys.argv[1], &#039;wt&#039;)
    f.write(&#039; &#039;.join(sys.argv[2:]))
    f.close()هم‌چنین یک فایل دیگه هم می‌سازیم با اسم bzipped.py که محتویات زیر رو داخلش قرار میدیمimport bz2
import sys

opener = bz2.open

if __name__ == &#039;__main__&#039;:
    f = bz2.open(sys.argv[1], &#039;wt&#039;)
    f.write(&#039; &#039;.join(sys.argv[2:]))
    f.close()حالا یک فایل جدید ایجاد کنید به اسم multi_reader.py با محتویات زیرimport os

from demo_reader.compressed import bzipped,gzipped

extension_map = {
    &#039;.bz2&#039;: bzipped.opener,
    &#039;.gz&#039;: gzipped.opener
}

class MultiReader:
    def __init__(self, filename):
        extension = os.path.splitext(filename)[1]
        opener = extension_map.get(extension, open)
        self.f = opener(filename, &#039;rt&#039;)


    def close(self):
        self.f.close()

    def read(self):
        return self.f.read()بسیار شبیه قسمت دوم و سوم هستش با تفاوت این‌که امکان خوندن فایل‌های bz2 و gz رو هم اضافه کردیماگر طبق آموزش‌های قبلی محلی که ساختید رو به syspath اضافه کرده باشید می‌تونید از دستور زیر جهت ایجاد یک نمونه فایل برای تست کدتون استفاده کنیدpython3 -m demo_reader.compressed.bzippped test.bz2 data compressed with bzipتیکه‌های مختلفی داره این کد شامل این که از پکیج demo_reader ساب‌پکیج compressed فانکشن bzipped استفاده می‌کنیم و تیکه کد پایین که میگه اگه arg دوم پاس داده شده بود(محل نوشتن فایل) رو استفاده کنf.write(&#039; &#039;.join(sys.argv[2:]))خب حالا برای این که ببینم آیا چیزهایی که نوشتیم درست کار می‌کنه یا نهدستورات زیر رو می‌نویسیمpython3import syssys.path.append(&amp;quotaddtosyspath&amp;quot)from demo_reader.multi_reader import MultiReaderr = MultiReader(&amp;quottest.bz2&amp;quot)r.read()r.close()با در صورتی که کارهارو درست انجام داده باشید باید data compressed with bzip رو مشاهده کنیدامیدوارم که از این قسمت خوشتون اومده باشهدر صورتی که سوالی دارید توی کامنت‌ها بپرسید</description>
                <category>Pooya Dowlat Abadi</category>
                <author>Pooya Dowlat Abadi</author>
                <pubDate>Sat, 08 Jan 2022 16:55:21 +0330</pubDate>
            </item>
                    <item>
                <title>برنامه‌های سازمان‌ یافته‌تر در پایتون - قسمت سوم - ساخت یک پکیج</title>
                <link>https://virgool.io/@pooyadowlat/%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D9%87%D8%A7%DB%8C-%D8%B3%D8%A7%D8%B2%D9%85%D8%A7%D9%86-%DB%8C%D8%A7%D9%81%D8%AA%D9%87-%D8%AA%D8%B1-%D8%AF%D8%B1-%D9%BE%D8%A7%DB%8C%D8%AA%D9%88%D9%86-%D9%82%D8%B3%D9%85%D8%AA-%D8%B3%D9%88%D9%85-%D8%B3%D8%A7%D8%AE%D8%AA-%DB%8C%DA%A9-%D9%BE%DA%A9%DB%8C%D8%AC-jsmgemoatdgq</link>
                <description>اگر دو قسمت قبل رو دنبال کرده باشید با ساختار کلی پکیج‌ها و ماژول‌ها در پایتون آشنا شدید و با روش‌های اضافه‌کردن یک پکیج به سیستم ویندوزی، مک یا لینوکسی خودتون هم آشنا شدید و نحوه کار با sys.path هم گفته شد.توی این قسمت می‌خوایم که یک پکیج برای خودمون بسازیم و توی قسمت‌های بعد هم با اون پکیج کار کنیم و یک برنامه مرتب‌تر و منظم‌تر توی پایتون داشته باشیمبرای ساخت یک پکیج توی ide یا idle و یا هر گونه دیگه‌ای که با پایتون کد می‌زنید یک پروژه جدید ایجاد کنیدتوجه داشته باشید که بعد از ساختن این پروژه جدید همون‌طوری که در قسمت قبل گفتیم به sys.path اونو اضافه کنیدمرحله اول اینه که یک دایرکتوری بسازید و اسم دلخواه خودتون رو بهش بدید و داخل اون یک اسکریپت پایتونی(فایل پایتونی) با اسم __init__ با فرمت py بسازیدمعمولا داخل فایل __init__ خالی هستشو ساختار دایرکتوری که من استفاده کردم هم به صورت زیر هستProjectname
    - addtosyspath
        - package_root
             - __init__.pyچند تا نکته در مورد فایل __init__:این فایل معمولا خالی هستشاز ورژن پایتون ۳.۳ به بعد نیازی به ایجاد این فایل نیستبا این که نیازی به ایجادش نیست اما وجود داشتنش به کسی که کد رو می‌خونه می‌گه که این دایرکتوری قرار بوده که یک پکیج باشه و این خیلی اوقات مفیدهتا این مرحله ما یک پکیج‌خالی ساختیم اما با کدهایی که معمولا میبینیم کمی متفاوت تر هستش به عنوان مثال کد زیر رو در نظر بگیرید و اگر بخوایم ما هم یک ساختار این شکلی داشته باشیم باید چه کارهایی انجام بدیم؟import urllib.request
with urllib.request.urlopen(&#039;http://python.org/&#039;) as response:
   html = response.read()خب پس باید کمی ادامه بدیمیک فایل جدید داخل پروژه‌تون ایجاد کنید به اسم content_reader.py و در کنار __init__ و داخلش کدهای زیر رو می‌نویسیمclass MultiReader:
    def __init__(self, filename):
        self.filename = filename
        self.f = open(filename, &#039;rt&#039;)

    def close(self):
        self.f.close()

    def read(self):
        return self.f.read()در مورد کدهای زیر موضوعی که وجود داره اینه که یک کلاس تعریف شده با یک تابع که باعث میشه بتونیم کلاس رو با پاس دادن مقادیر ایجاد کنیم و دو تابع که یکی مسئول بستن فایل و یکی مسئول خوندن محتویات اون هستشبرگردیم به کنسول‌مونهمین‌طوری که میبینید ابتدا دایرکتوری اولیه ایجاد شده رو به sys.path اضافه می‌کنیم و بعدش کلاس ایجاد شده رو به صورت زیر import می‌کنیم و از فانکشن read برای خواندن محتویات یک فایل تستی استفاده می‌کنیمimport package_root.content_reader
data = package_root.content_reader.MutliReader(&amp;quotaddtosyspath/package_root/test&amp;quot)
data.read()که محتویات فایلی که ساختیم رو بهمون میده.امیدوارم این قسمت براتون مفید بوده باشه</description>
                <category>Pooya Dowlat Abadi</category>
                <author>Pooya Dowlat Abadi</author>
                <pubDate>Mon, 25 Oct 2021 08:20:13 +0330</pubDate>
            </item>
                    <item>
                <title>برنامه‌های سازمان یافته‌تر در پایتون - قسمت دوم - پیدا کردن پکیج‌ها</title>
                <link>https://virgool.io/@pooyadowlat/%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D9%87%D8%A7%DB%8C-%D8%B3%D8%A7%D8%B2%D9%85%D8%A7%D9%86-%DB%8C%D8%A7%D9%81%D8%AA%D9%87-%D8%AA%D8%B1-%D8%AF%D8%B1-%D9%BE%D8%A7%DB%8C%D8%AA%D9%88%D9%86-%D9%82%D8%B3%D9%85%D8%AA-%D8%AF%D9%88%D9%85-%D9%BE%DB%8C%D8%AF%D8%A7-%DA%A9%D8%B1%D8%AF%D9%86-%D9%BE%DA%A9%DB%8C%D8%AC-%D9%87%D8%A7-ezjr128dezxe</link>
                <description>قبل از این که بریم سراغ قسمت‌های دیگه کار با پکیج‌های پایتون باید یک کار خیلی مهم و یک قسمت مهم رو یاد بگیریم:یک سوالی که قبل از ادامه کار به ذهن ما می‌رسه اینه که پایتون چطوری پکیج‌های مختلف و ماژول‌های رو پیدا می‌کنه؟وقتی که شما می‌خواید یک پکیج یا ماژول رو import کنید پایتون روی سیستم شما دنبال سورسش می‌گرده و اون کد رو لود می‌کنه، اما سوالی که پیش میاد اینه که چطوری پایتون این کارو می‌کنه؟ و می‌دونه که کجارو دنبال بگرده؟جواب سوال اینه که پایتون path attribute ماژول استاندارد سیستم یا همون standard sys module رو چک می‌کنه که بهش sys.path هم می‌گندر عمل sys.path یک لیست از دایرکتوری‌ها هستش که وقتی ما می‌خوایم یک پکیج یا ماژول رو import کنیم اول داخل دایرکتوری اول رو نگاه می‌کنه و اگر نبود یک مرحله میره داخل‌تر و sub directory رو چک می‌کنه تا جایی که دیگه sub directory ای برای چک کردن نباشه و اون زمان ImportError رو به ما میده که یعنی نتونسته چیزی که ما می‌خوایم رو پیدا کنههم‌چنین یک نکته جالب دیگه هم در مورد این سرچ کردن هست و اونم اینه که اولین match شدن رو به عنوان نتیجه به ما برمی‌گردونهبه عنوان مثال من پایتون ۳.۱۰ و لیست دایرکتوری‌هاش رو در تصویر زیر نمایش دادمPython3.10 sys.pathولی اگه پایتون ۳ که توی لینوکس به پایتونی که توسط پکیج‌ها استفاده میشه این دستور رو بزنیم آیا متفاوت خواهد بود؟Python3.9 sys.pathخب توجه کنیم که sys.path یک لیسته مثل بقیه لیست‌ها پس می‌تونیم از روش slicing و index بندی داخلش استفاده کنیم&gt;&gt;importsys&gt;&gt;&gt;sys.path[&#039;&#039;,&#039;/usr/lib/python310.zip&#039;,&#039;/usr/lib/python3.10&#039;,&#039;/usr/lib/python3.10/lib-dynload&#039;,&#039;/usr/local/lib/python3.10/dist-packages&#039;,&#039;/usr/lib/python3/dist-packages&#039;]&quot;&gt; &gt;&gt;&gt;importsys&gt;&gt;&gt;sys.path[&#039;&#039;,&#039;/usr/lib/python310.zip&#039;,&#039;/usr/lib/python3.10&#039;,&#039;/usr/lib/python3.10/lib-dynload&#039;,&#039;/usr/local/lib/python3.10/dist-packages&#039;,&#039;/usr/lib/python3/dist-packages&#039;] یعنی که می‌تونیم مقدار sys.path[0] که برابر &#x27;&#x27; هستش رو نمایش بدیم یا کارهای این شکلی باهاش انجام بدیمالبته سوالی که شاید پیش بیاد برای شما اینه که چرا sys.path[0] برابر با &#x27; &#x27; یا همون خالی هستش؟جوابش اینه که چون پایتون رو با آرگومان خاصی اجرا نکردیم و دستور python3 یا python3.10 رو خالی بدون هیچ پسوندی اجرا کردیم داره اعلام می‌کنه که پسوندی ندارههم‌چنین نکته جالب دیگه‌ای که در مورد sys.path وجود داره اینه که sys.path[-5:] مقادیر استاندارد و پکیج‌های استاندارد رو نمایش می‌دهتا این مرحله همه چیز تئوری بوده اما فرض کنید که می‌خوایم یک کار عملی انجام بدیمفرض کنید که می‌خوایم یک پکیج یا یک دایرکتوری رو به sys.path اضافه کنیمیک پروژه ایجاد می‌کنیم و داخلش یک directory ایجاد می‌کنیم و یک فایل پایتونی با اسم دلخواه خودمون می‌سازیم داخلشمن برای مثال یک پروژه با اسم Python-Organize ایجاد کردم که یک فولدر یا دایرکتوری با نام addsyspath می‌سازم که داخلش یک اسکریپت پایتونی با نام sysadd.py ایجاد کردم به صورت عکس زیرحالا می‌خوایم اونو به sys.path اضافه کنیم چرا این ارور رو میده؟ چون که داخل sys.path نیست هنوزبه محلی که پروژه رو ایجاد کردیم cd می‌کنیم و اون رو به sys.path اضافه می‌کنیمقبلا گفتیم که sys.path یک لیست هستش در واقع پس برای اضافه کردن یک آیتم به اون هم مثل هر لیست دیگه‌ای عمل می‌کنیمsys.path.append(&amp;quotaddsyspath&amp;quot)خب حالا این دایرکتوری اضافه شد و می‌تونیم ماژول مورد نظرمون یعنی sysadd رو اضافه کنیمو با دستور زیر اونو import می‌کنیمfrom addsyspath import sysaddاگه کارهارو درست انجام داده باشیم باید با پیام Added To Syspath که قبلا تعریف کردیم رو به رو میشیمخب شاید این روش چندان خوب نباشه و بخوایم پروژه‌ای که ایجاد کردیم رو بدون نوشتن و اجرا کردن این دستورات داشته باشیماینجا جایی هست که PYTHONPATH به کار ما میاد، هنگامی که پایتون رو اجرا می‌کنیم به صورت استاندارد چیزهایی که در PYTHONPATH هستند به sys.path اضافه میشهبرای اضافه کردن یک path یا directory به ورژن ویندوزی پایتون لازمه که دستور زیر رو اجرا کنیمset PYTHONPATH=path1;path2;path3برای اضافه کردن توی لینوکس یا مک هم به صورت زیر انجام میشهexport PYTHONPATH=path1:path2:path3اگر بخوایم این تغییرات رو سیو کنیم و هربار این دستورات رو اجرا نکنیم در ویندوز باید از environmental path استفاده کنیمتوی لینوکس و مک هم می‌تونیم اونو به .bashrc یا .zshrc اضافه کنیم یا محل‌های دیگری مثل محل زیر اضافش کنیم:nano /etc/bash.bashrcامیدوارم این قسمت آموزش براتون مفید بوده باشهقسمت قبلی رو در این لینک ببینید:https://virgool.io/@pooyadowlat/%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D9%87%D8%A7%DB%8C-%D8%B3%D8%A7%D8%B2%D9%85%D8%A7%D9%86-%DB%8C%D8%A7%D9%81%D8%AA%D9%87-%D8%AA%D8%B1-%D8%AF%D8%B1-%D9%BE%D8%A7%DB%8C%D8%AA%D9%88%D9%86-%D9%82%D8%B3%D9%85%D8%AA-%D8%A7%D9%88%D9%84-%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-vedyhpyvlxhn</description>
                <category>Pooya Dowlat Abadi</category>
                <author>Pooya Dowlat Abadi</author>
                <pubDate>Sun, 24 Oct 2021 15:07:03 +0330</pubDate>
            </item>
                    <item>
                <title>برنامه‌های سازمان یافته‌تر در پایتون - قسمت اول - آشنایی</title>
                <link>https://virgool.io/@pooyadowlat/%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D9%87%D8%A7%DB%8C-%D8%B3%D8%A7%D8%B2%D9%85%D8%A7%D9%86-%DB%8C%D8%A7%D9%81%D8%AA%D9%87-%D8%AA%D8%B1-%D8%AF%D8%B1-%D9%BE%D8%A7%DB%8C%D8%AA%D9%88%D9%86-%D9%82%D8%B3%D9%85%D8%AA-%D8%A7%D9%88%D9%84-%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-vedyhpyvlxhn</link>
                <description>من قصد دارم توی چند بخش مرتب‌سازی و ساختارمند کردن یک کد پایتونی رو آموزش بدم چرا که بهترین روش یادگرفتن عمیق یک مطلب اینه که آدم آموزشش بدهماژول‌ها در پایتون شاید چیزی باشن که شما هم مثل من بهشون برخورده باشید اما هیچ‌وقت عمیق نشده باشید یا حتی نیاز نبوده که باهاشون کار کنید اما برای ایجاد برنامه‌های ساختارمندتر و مرتب‌تر بهشون نیاز داریدمثال بالارو ببینید که کتابخانه urllib خودش یک ماژول در پایتون هستش و urllib.request هم یک ماژول هستیکمی برگردیم عقب‌تر پس یک ماژول خودش میتونه زیر ماژول داشته باشه اما ماژول کجا قرار گرفته؟ماژول‌ها داخل چیزی به اسم پکیج‌ها قرار دارند، یکمی پیچیده شد بزارید خیلی ساده‌تر بگم پکیج‌ها روش مرتب‌سازی و ساختارمند کردن ماژول‌ها هستند پس یعنی پکیج‌ها می‌تونن شامل ماژول‌ها باشند و خودشون هم زیرپکیج‌هایی داشته باشند که داخلشون ماژول‌هایی دارهاین ساختار بهمون کمک می‌کنه قسمت‌هایی و فانکشن‌ها و کدهایی که کارهای شبیه به هم می‌کنند رو کنار هم قرار بدیم و اونارو مرتب کنیماما نکته‌ جالبی که وجود داره اینه که به طور عادی فقط پکیج اصلی شامل __path__ هست و زیرپکیج‌ها شامل این قسمت به طور عادی نیستند</description>
                <category>Pooya Dowlat Abadi</category>
                <author>Pooya Dowlat Abadi</author>
                <pubDate>Fri, 22 Oct 2021 23:48:58 +0330</pubDate>
            </item>
            </channel>
</rss>