क्या एक पैकेज में पायथन मॉड्यूल के नामों को सूचीबद्ध करने का एक मानक तरीका है?


100

क्या एक पैकेज में सभी मॉड्यूल के नामों को सूचीबद्ध करने का एक सीधा तरीका है, बिना उपयोग किए __all__?

उदाहरण के लिए, यह पैकेज दिया गया:

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

मैं सोच रहा था कि इस तरह से कुछ करने के लिए एक मानक या अंतर्निहित तरीका है:

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

पैकेज की निर्देशिका को खोजने के लिए मॉड्यूल खोज पथ के माध्यम से मैनुअल दृष्टिकोण को पुनरावृत्त करना होगा। एक तो उस निर्देशिका की सभी फाइलों को सूचीबद्ध कर सकता है, विशिष्ट नाम वाली पाई / pyc / pyo फ़ाइलों को फ़िल्टर कर सकता है, एक्सटेंशन स्ट्रिप कर सकता है और उस सूची को वापस कर सकता है। लेकिन ऐसा लगता है कि मॉड्यूल आयात तंत्र के लिए पहले से ही आंतरिक रूप से कुछ किया जा रहा है। क्या वह कार्यक्षमता कहीं उजागर है?

जवाबों:


23

शायद यह वही करेगा जो आप खोज रहे हैं?

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)])

1
मैं 'और' मॉड्यूल जोड़ देगा! = " Init .py" 'को अंतिम' अगर ', क्योंकि init .py वास्तव में पैकेज का हिस्सा नहीं है। और .py एक और वैध विस्तार है। इसके अलावा, imp.find_module का उपयोग करना वास्तव में अच्छा विचार है; मुझे लगता है कि यह सही उत्तर है।
DNS

3
मैं असहमत हूं - आप सीधे init आयात कर सकते हैं, तो विशेष मामला क्यों? यह निश्चित रूप से नियम तोड़ने के लिए पर्याप्त नहीं है। ;-)
cdleary

6
आपको imp.get_suffixes()अपनी हाथ से लिखी सूची के बजाय संभवतः उपयोग करना चाहिए ।
itsadok

3
इसके अलावा, ध्यान दें कि यह xml.sax
उप

1
यह वास्तव में बुरा तरीका है। आप मज़बूती से यह नहीं बता सकते हैं कि फ़ाइल नाम एक्सटेंशन से एक मॉड्यूल क्या है।
विम

188

Python2.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])]

15
यह अशांतिपूर्ण रूप से अनिर्दिष्ट है, लेकिन ऐसा करने का सबसे सही तरीका लगता है। आशा है कि आप बुरा नहीं मानेंगे मैंने नोट जोड़ा।
इसका नाडोक

13
pkgutilवहाँ python2.3 और वास्तव में है । इसके अलावा, जबकि pkgutil.iter_modules()पुनरावर्ती pkgutil.walk_packages()रूप से काम नहीं करेगा, वहाँ एक अच्छी तरह से है, जो पुनरावृत्ति करेगा । हालांकि इस पैकेज के लिए सूचक के लिए धन्यवाद।
संदीप भट्टाचार्य 19

iter_modulesजैसे पूर्ण आयात के लिए काम क्यों नहीं करता है a.b.testpkg? यह मुझे दे रहा है[]
हुसैन

मैंने आपकी EDIT को नजरअंदाज कर दिया :( क्षमा करें। यह मेरे द्वारा दूसरे स्निपेट का अनुसरण करने के बाद काम करता है।
हुसैन

1
मैं पुष्टि नहीं कर सकता कि pkgutil.walk_packages()पुनरावृत्ति होती है, इससे मुझे उतना ही आउटपुट मिलता है pkgutil.iter_modules(), इसलिए मुझे लगता है कि उत्तर अधूरा है।
rwst

29
import module
help(module)

2
हालाँकि मदद पाठ के निचले भाग में पैकेज सामग्री को सूचीबद्ध करने में मदद करता है, लेकिन सवाल यह है कि यह कैसे किया जाए: f (package_name) => ["मॉड्यूल 1_name", "मॉड्यूल 2_name"] की तर्ज पर। मुझे लगता है कि मैं मदद से लौट आए स्ट्रिंग को पार्स कर सकता हूं, लेकिन यह निर्देशिका को सूचीबद्ध करने की तुलना में अधिक गोल चक्कर लगता है।
DNS

1
@DNS: help()सामान प्रिंट करता है, यह एक स्ट्रिंग वापस नहीं करता है।
जून 15x13

मैं मानता हूं कि यह एक राउंडअबाउट तरीका है लेकिन इसने मुझे खरगोश के छेद के नीचे भेजा कि यह कैसे help()काम करता है। वैसे भी, बिल्ट-इन pydocमॉड्यूल थूक मदद कर सकते हैं स्ट्रिंग कि help()पृष्ठांकन: import pydoc; pydoc.render_doc('mypackage')
sraboy

8

नहीं जानता कि मैं कुछ देख रहा हूँ, या अगर जवाब सिर्फ आउट डेटेड हैं लेकिन;

जैसा कि user815423426 द्वारा कहा गया है कि यह केवल जीवित वस्तुओं के लिए काम करता है और सूचीबद्ध मॉड्यूल केवल ऐसे मॉड्यूल हैं जो पहले आयात किए गए थे।

एक पैकेज में लिस्टिंग मॉड्यूल वास्तव में निरीक्षण का उपयोग कर आसान लगता है :

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

मैंने आयातित = आयात __ ('myproj.mymod.mysubmod') m = inspect.getmembers (i, inspect.ismodule) आयात किया है, लेकिन आयात पथ ~ / myproj / __ init .py है और m एक सूची है (mymod, '~ के साथ /myproj/mymod/__init__.py ')
hithwen

1
@hithwen टिप्पणियों में सवाल न पूछें, खासकर अगर वे सीधे संबंधित नहीं हैं। एक अच्छा सामरी होना: उपयोग करना imported = import importlib; importlib.import_module('myproj.mymod.mysubmod')__import__शीर्ष-स्तरीय मॉड्यूल आयात करता है, प्रलेखन देखें
siebz0r

हम्म, यह आशाजनक है लेकिन यह मेरे लिए काम नहीं कर रहा है। जब मैं करता हूं import inspect, mypackageऔर तब inspect.getmembers(my_package, inspect.ismodule)मुझे एक खाली सूची मिलती है, भले ही मेरे पास निश्चित रूप से इसमें विभिन्न मॉड्यूल हों।
अमिलियो वाज़केज़-रीना

1
तथ्य की बात के रूप में, यह केवल तभी काम करता है जब मैं import my_package.fooऔर सिर्फ नहीं import mypackage, जिस स्थिति में यह वापस आता है foo। लेकिन यह उद्देश्य को हरा देता है
अमेलियो वाज़केज़-रीना

3
@ user815423426 आप बिलकुल सही हैं ;-) लगता है जैसे मैं कुछ देख रहा था।
siebz0r

3

यह एक पुनरावर्ती संस्करण है जो अजगर 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

os.scandirसीधे परिणाम प्रविष्टियों पर ध्यान देने के बजाय एक संदर्भ प्रबंधक के रूप में उपयोग करने का क्या फायदा है ?
monkut

1
@monkut देखें docs.python.org/3/library/os.html#os.scandir जो यह सुनिश्चित करने के लिए कि closeजब आप इसके साथ किए जाते हैं, तो यह सुनिश्चित करने के लिए कि यह किसी भी आयोजित संसाधनों को जारी किया जाता है, इसे संदर्भ प्रबंधक के रूप में उपयोग करने का सुझाव दें ।
ताकसवेल

reइसके बजाय यह हर पैकेज को सूचीबद्ध करने के लिए काम नहीं करता है, लेकिन re.उन सभी को जोड़ता है
Tushortz

1

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)


0

यदि आप अजगर कोड के बाहर अपने पैकेज के बारे में एक घुसपैठ देखना चाहते हैं (कमांड प्रॉम्प्ट से) तो आप इसके लिए 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>)

-2
def package_contents(package_name):
  package = __import__(package_name)
  return [module_name for module_name in dir(package) if not module_name.startswith("__")]

यह केवल मॉड्यूल के लिए काम करता है, न कि पैकेज के लिए। पायथन के loggingपैकेज पर यह देखने की कोशिश करें कि मेरा क्या मतलब है। लॉगिंग में दो मॉड्यूल होते हैं: हैंडलर और कॉन्फिग। आपका कोड 66 वस्तुओं की सूची लौटाएगा, जिसमें उन दो नामों को शामिल नहीं किया गया है।
DNS

-3

प्रिंट दिर (मॉड्यूल)


1
यह एक मॉड्यूल की सामग्री को सूचीबद्ध करता है जो पहले से ही आयात किया गया है। मैं एक ऐसे पैकेज की सामग्री को सूचीबद्ध करने का एक तरीका खोज रहा हूं जो अभी तक आयात नहीं किया गया है, जैसे कि 'x आयात *' से होता है जब सभी निर्दिष्ट नहीं होते हैं।
DNS

x आयात से * पहले मॉड्यूल को आयात करता है और फिर वर्तमान मॉड्यूल में सब कुछ कॉपी करता है।
सेब

मुझे एहसास हुआ कि 'एक्स इंपोर्ट * से' वास्तव में एक पैकेज के उप-मॉड्यूल को आयात नहीं करता है, क्योंकि विंडोज पर केस-सेंसिटिव इश्यूज हैं। मैंने केवल इसे शामिल किया था कि मैं क्या करना चाहता था; मैंने इसे भ्रम से बचने के लिए प्रश्न से संपादित किया है।
DNS

वह पहले से ही आयात की गई सभी विशेषताओं को सूचीबद्ध करता है, केवल उप-मॉड्यूल की सूची नहीं। तो यह सवाल का जवाब नहीं है।
bignose
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.