هل هناك طريقة قياسية لسرد أسماء وحدات بايثون في الحزمة؟

StackOverflow https://stackoverflow.com/questions/487971

  •  20-08-2019
  •  | 
  •  

سؤال

هل هناك طريقة مباشرة لسرد أسماء كافة الوحدات في الحزمة، دون استخدام __all__?

على سبيل المثال، بالنظر إلى هذه الحزمة:

/testpkg
/testpkg/__init__.py
/testpkg/modulea.py
/testpkg/moduleb.py

أتساءل عما إذا كانت هناك طريقة قياسية أو مدمجة للقيام بشيء مثل هذا:

>>> package_contents("testpkg")
['modulea', 'moduleb']

سيكون الأسلوب اليدوي هو التكرار عبر مسارات بحث الوحدة للعثور على دليل الحزمة.يمكن للمرء بعد ذلك إدراج جميع الملفات الموجودة في هذا الدليل، وتصفية ملفات py/pyc/pyo ذات الأسماء الفريدة، وإزالة الامتدادات، وإرجاع تلك القائمة.ولكن يبدو أن هذا يمثل قدرًا لا بأس به من العمل لشيء تقوم به آلية استيراد الوحدة داخليًا بالفعل.هل هذه الوظيفة مكشوفة في أي مكان؟

هل كانت مفيدة؟

المحلول

وربما هذا سوف تفعل ما كنت تبحث عنه؟

import imp
import os
MODULE_EXTENSIONS = ('.py', '.pyc', '.pyo')

def package_contents(package_name):
    file, pathname, description = imp.find_module(package_name)
    if file:
        raise ImportError('Not a package: %r', package_name)
    # Use a set because some may be both source and compiled.
    return set([os.path.splitext(module)[0]
        for module in os.listdir(pathname)
        if module.endswith(MODULE_EXTENSIONS)])

نصائح أخرى

استخدام بيثون 2.3 وما فوق, ، يمكنك أيضًا استخدام pkgutil وحدة:

>>> import pkgutil
>>> [name for _, name, _ in pkgutil.iter_modules(['testpkg'])]
['modulea', 'moduleb']

يحرر: لاحظ أن المعلمة ليست قائمة وحدات، ولكنها قائمة مسارات، لذلك قد ترغب في القيام بشيء مثل هذا:

>>> import os.path, pkgutil
>>> import testpkg
>>> pkgpath = os.path.dirname(testpkg.__file__)
>>> print [name for _, name, _ in pkgutil.iter_modules([pkgpath])]
import module
help(module)

<الإضراب> لا أعرف إذا أنا تطل على شيء، أو إذا كانت الإجابات للتو مؤرخة ولكن؛

وكما ذكر user815423426 يعمل هذا فقط للكائنات الحية والوحدات المدرجة ليست سوى الوحدات التي تم استيرادها من قبل.

وحدات قائمة في حزمة يبدو من السهل حقا باستخدام تفقد :

>>> import inspect, testpkg
>>> inspect.getmembers(testpkg, inspect.ismodule)
['modulea', 'moduleb']

وهذا هو نسخة العودية التي تعمل مع بيثون 3.6 وأعلاه:

import importlib.util
from pathlib import Path
import os
MODULE_EXTENSIONS = '.py'

def package_contents(package_name):
    spec = importlib.util.find_spec(package_name)
    if spec is None:
        return set()

    pathname = Path(spec.origin).parent
    ret = set()
    with os.scandir(pathname) as entries:
        for entry in entries:
            if entry.name.startswith('__'):
                continue
            current = '.'.join((package_name, entry.name.partition('.')[0]))
            if entry.is_file():
                if entry.name.endswith(MODULE_EXTENSIONS):
                    ret.add(current)
            elif entry.is_dir():
                ret.add(current)
                ret |= package_contents(current)


    return ret

وهذا يجب إدراج وحدات:

help("modules")

إذا كنت ترغب في عرض لمراسلة حول حزمة الخاص بك خارج رمز الثعبان (من موجه الأوامر) يمكنك استخدام pydoc لذلك.

# get a full list of packages that you have installed on you machine
$ python -m pydoc modules

# get information about a specific package
$ python -m pydoc <your package>

وسيكون لديك نفس النتيجة كما pydoc لكن داخل مترجم باستخدام المساعدة

>>> import <my package>
>>> help(<my package>)

وبناء على سبيل المثال cdleary، وهنا نسخة سرد مسار عودي لجميع الوحدات الفرعية:

import imp, os

def iter_submodules(package):
    file, pathname, description = imp.find_module(package)
    for dirpath, _, filenames in os.walk(pathname):
        for  filename in filenames:
            if os.path.splitext(filename)[1] == ".py":
                yield os.path.join(dirpath, filename)

والطباعة دير (وحدة)

def package_contents(package_name):
  package = __import__(package_name)
  return [module_name for module_name in dir(package) if not module_name.startswith("__")]
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top