• בלוג
  • יבוא כל דבר בפייתון

יבוא כל דבר בפייתון

08/11/2026

פקודת import בפייתון טוענת מודול חיצוני ובדרך כלל אנחנו לומדים אותה יחד עם הלימוד על מודולים. יוצרים קובץ בשם utils.py ואז מתוך main.py כותבים import utils כדי להשתמש בפונקציות שמוגדרות שם. אבל האמת שמנגנון היבוא של פייתון הרבה יותר גמיש.

מודול sys מגדיר משתנה בשם meta_path שמכיל רשימה של "טוענים":

>>> import sys
>>> [print(i) for i in sys.meta_path]
<_distutils_hack.DistutilsMetaFinder object at 0x1023ab8f0>
<class '_frozen_importlib.BuiltinImporter'>
<class '_frozen_importlib.FrozenImporter'>
<class '_frozen_importlib_external.PathFinder'>

מודול importlib יודע לחבר בין שם של מודול לאוביקט שיטען אותו:

>>> import importlib.util
>>> print(importlib.util.find_spec('sys').origin)
built-in
>>> print(importlib.util.find_spec('json').origin)
/Users/ynonp/.pyenv/versions/3.12.0/lib/python3.12/json/__init__.py
>>> print(importlib.util.find_spec('random').origin)
/Users/ynonp/.pyenv/versions/3.12.0/lib/python3.12/random.py

והחלק הכי טוב? אפשר להוסיף "טוענים" משלנו כדי לטעון דברים חדשים. התוכנית הבאה תדפיס Hello from foo בלי שהיא צריכה קובץ foo.py באותה תיקיה:

import sys
import types
import importlib.abc
import importlib.machinery


class CatchAllFinder(importlib.abc.MetaPathFinder):
    def find_spec(self, fullname, path=None, target=None):
        # Only called as a fallback if registered last
        return importlib.machinery.ModuleSpec(
            fullname,
            CatchAllLoader()
        )


class CatchAllLoader(importlib.abc.Loader):
    def create_module(self, spec):
        return None  # Let Python create the module

    def exec_module(self, module):
        module.hello = lambda: f"Hello from {module.__name__}!"


# Append LAST so normal modules take priority
sys.meta_path.append(CatchAllFinder())

import foo
print(foo.hello())

מיטיבי לכת יכולים להוסיף טיפול בהפעלת פונקציה בכל שם ואז אנחנו יכולים לבנות מנגנונים דינמיים לדוגמה לתמוך בקוד כזה שמתחבר ל MCP של ג'ימייל וטוען הודעות אחרונות מתיבת הדואר הנכנס:

import gmail_mcp as gmail

print(gmail.inbox.read(5))

המשחק כאן יהיה לממש Loader שטוען כל שם שמסתיים ב _mcp ומתחבר ל MCP Server שמתאים לו וכל פונקציה על אותו מודול תפעיל כלי באותו שם. בטח הרבה יותר נחמד מהגרסה המשעממת מהמודול mcp:

import asyncio

from mcp import Client


async def main() -> None:
    async with Client("http://localhost:8000/mcp") as client:
        result = await client.call_tool("add", {"a": 1, "b": 2})
        print(result.structured_content)  # {'result': 3}


asyncio.run(main())