किसी फ़ोल्डर में सभी मॉड्यूल कैसे लोड करें?


269

क्या कोई मुझे मॉड्यूल की एक पूरी निर्देशिका आयात करने का एक अच्छा तरीका प्रदान कर सकता है?
मेरे पास इस तरह की एक संरचना है:

/Foo
    bar.py
    spam.py
    eggs.py

मैंने इसे जोड़ने __init__.pyऔर करने के द्वारा इसे एक पैकेज में बदलने की कोशिश की, from Foo import *लेकिन यह उस तरह से काम नहीं कर पाया जैसा मैंने आशा की थी।


2
Init .py रास्ता बहुत सही है। क्या आप उस कोड को पोस्ट कर सकते हैं जो काम नहीं किया?
बाल्हा

9
क्या आप परिभाषित कर सकते हैं "काम नहीं किया"? क्या हुआ? आपको क्या त्रुटि संदेश मिला?
एस.लॉट

क्या यह पायथोनिक है या अनुशंसित है? "स्पष्ट रूप से निहितार्थ से बेहतर है।"
यंगमिलस्टेथोरी

स्पष्ट रूप से बेहतर है। लेकिन क्या आप वास्तव में इन कष्टप्रद 'संदेश नहीं' संदेशों को संबोधित करना चाहते हैं जो आप एक नया मॉड्यूल जोड़ते हैं। मुझे लगता है कि अगर आपके पास कई छोटे मॉड्यूल-फंक्शंस वाले पैकेज डायरेक्टरी हैं, तो इसके बारे में जाने का सबसे अच्छा तरीका है। मेरी धारणाएँ हैं: 1. मॉड्यूल बल्कि सरल हैं। आप कोड के लिए पैकेज का उपयोग करते हैं
tidiness

जवाबों:


400

.pyवर्तमान फ़ोल्डर में सभी अजगर ( ) फ़ाइलों को सूचीबद्ध करें और उन्हें __all__चर के रूप में डालें__init__.py

from os.path import dirname, basename, isfile, join
import glob
modules = glob.glob(join(dirname(__file__), "*.py"))
__all__ = [ basename(f)[:-3] for f in modules if isfile(f) and not f.endswith('__init__.py')]

57
मूल रूप से इसलिए मैं अजगर फ़ाइलों को बिना किसी कॉन्फ़िगरेशन के एक निर्देशिका में छोड़ सकता हूं और उन्हें कहीं और चलने वाली स्क्रिप्ट द्वारा निष्पादित किया जा सकता है।
इवान फॉसमार्क

5
@NiallDouglas यह उत्तर एक विशिष्ट प्रश्न के लिए है, जो ओपी ने पूछा था, उसके पास एक ज़िप फ़ाइल नहीं है और pyc फाइलें आसानी से शामिल की जा सकती हैं, और आप .pyd या .so libs आदि को भी भूल रहे हैं
अनुराग उनियाल

35
केवल एक चीज मैं if not os.path.basename(f).startswith('_')if not f.endswith('__init__.py')
जोड़ूंगा या

10
इसे और अधिक मजबूत बनाने के लिए, यह भी सुनिश्चित करें कि os.path.isfile(f)है True। यह टूटे हुए सिमिलिंक और निर्देशिका somedir.py/(कोने-केस, मैं मानता हूं, लेकिन अभी भी ...) को
फ़िल्टर कर देगा

12
जोड़े from . import *सेटिंग के बाद __all__अगर आप submodules का उपयोग कर उपलब्ध करना चाहते हैं .(उदाहरण के रूप में module.submodule1, module.submodule2, आदि)।
ओस्ट्रोकैच

133

युक्त __all__करने के लिए चर जोड़ें __init__.py:

__all__ = ["bar", "spam", "eggs"]

Http://docs.python.org/tutorial/modules.html भी देखें


163
हाँ, हाँ, लेकिन क्या यह गतिशील होने का कोई तरीका है?
इवान फॉसमार्क

27
का संयोजन os.listdir(), कुछ फ़िल्टरिंग, .pyविस्तार के अलग करना और __all__

मेरे लिए नमूना कोड के रूप में यहां काम नहीं कर रहा है github.com/namgivu/python-import-all/blob/master/error_app.py । शायद मुझे वहाँ कुछ याद आता है?
नाम जी वीयू

1
मैंने अपने आप को पता लगाया - उन मॉड्यूल में परिभाषित चर / ऑब्जेक्ट का उपयोग करने के लिए, हमें पूर्ण संदर्भ पथ जैसे moduleName.varNameरेफरी का उपयोग करना होगा । stackoverflow.com/a/710603/248616
नाम जी VU

1
@NamGVU: संबंधित प्रश्न के उत्तर में यह कोड सभी सार्वजनिक उप-मॉड्यूलों को पैकेज के नाम स्थान में आयात करेगा।
मार्टीन्यू

54

2017 में अपडेट: आप शायद importlibइसके बजाय उपयोग करना चाहते हैं ।

फू निर्देशिका को एक जोड़कर एक पैकेज बनाएं __init__.py। उस __init__.pyऐड में:

import bar
import eggs
import spam

चूंकि आप इसे गतिशील चाहते हैं (जो कि एक अच्छा विचार नहीं हो सकता है), सूची pir के साथ सभी py-files को सूचीबद्ध करें और उन्हें कुछ इस तरह से आयात करें:

import os
for module in os.listdir(os.path.dirname(__file__)):
    if module == '__init__.py' or module[-3:] != '.py':
        continue
    __import__(module[:-3], locals(), globals())
del module

फिर, अपने कोड से ऐसा करें:

import Foo

अब आप के साथ मॉड्यूल का उपयोग कर सकते हैं

Foo.bar
Foo.eggs
Foo.spam

आदि from Foo import *कई कारणों से एक अच्छा विचार नहीं है, जिसमें नाम की गड़बड़ी और कोड का विश्लेषण करना कठिन है।


1
बुरा नहीं है, लेकिन यह मत भूलो कि आप .pyc और .pyo फ़ाइलें भी आयात कर सकते हैं।
इवान फॉसमार्क

7
tbh, मुझे __import__hackish लगता है, मुझे लगता है कि नामों को जोड़ना बेहतर होगा __all__और फिर from . import *स्क्रिप्ट के निचले भाग में डाल दिया जाएगा
freeforall tousez

1
मुझे लगता है कि यह ग्लोब वर्जन की तुलना में अच्छा है।
lpapp 14

8
__import__सामान्य उपयोगों के लिए नहीं है, यह इसके बजाय interpreterउपयोग importlib.import_module()करता है।
एंड्रयू_ १५१०

2
पहला उदाहरण बहुत मददगार था, धन्यवाद! पहले पायथॉन 3.6.4 के तहत मुझे पायथन आयात from . import eggsकरने __init__.pyसे पहले आदि करना था । केवल के साथ import eggsमैं ModuleNotFoundError: No module named 'eggs'जब की कोशिश कर रहा import Fooमें main.pyऊपर निर्देशिका में।
निक

41

मिहेल के उत्तर पर विस्तार करते हुए, मेरा मानना ​​है कि गैर-हैकिश तरीका (जैसे, सीधे फ़ाइल पथों को नहीं संभालना) निम्नलिखित है:

  1. के __init__.pyतहत एक खाली फ़ाइल बनाएँFoo/
  2. निष्पादित
import pkgutil
import sys


def load_all_modules_from_dir(dirname):
    for importer, package_name, _ in pkgutil.iter_modules([dirname]):
        full_package_name = '%s.%s' % (dirname, package_name)
        if full_package_name not in sys.modules:
            module = importer.find_module(package_name
                        ).load_module(full_package_name)
            print module


load_all_modules_from_dir('Foo')

आपको मिलेगा:

<module 'Foo.bar' from '/home/.../Foo/bar.pyc'>
<module 'Foo.spam' from '/home/.../Foo/spam.pyc'>

यह एक सही जवाब के लिए वहाँ जिस तरह से ज्यादातर है - यह ज़िप अभिलेखागार संभालती है, लेकिन ऐसा नहीं करता लिखने init और न ही आयात। नीचे ऑटोमोडिनेट देखें।
नियाल डगलस

1
एक और बात: उपरोक्त उदाहरण sys.modules को देखने के लिए नहीं देखता है कि क्या मॉड्यूल पहले से लोड है। उस चेक के बिना उपरोक्त मॉड्यूल दूसरी बार लोड होगा :)
नील डगलस

3
जब मैं आपके कोड के साथ load_all_modules_from_dir ('Foo / bar') चलाता हूं तो मुझे "RuntimeWarning: पेरेंट मॉड्यूल 'Foo / bar' पूर्ण आयात को हैंडल करते समय नहीं मिला" - इसे दबाने के लिए, मुझे full_package_name = 'सेट करना होगा।' dirname.split (os.path.sep) + package_name]) और Foo.bar को भी आयात करें
एलेक्स

उन RuntimeWarningसंदेशों को भी full_package_name का उपयोग नहीं करके बचा जा सकता है importer.find_module(package_name).load_module(package_name):।
आर्टफंकल

RuntimeWarningत्रुटियों भी माता-पिता (उर्फ dirname) आयात करने से बचा जा सकता है (एक यकीनन बदसूरत तरीके से)। एक तरीका यह है कि ऐसा करने के लिए है - if dirname not in sys.modules: pkgutil.find_loader(dirname).load_module(dirname)। बेशक, यह केवल तभी काम करता है जब dirnameएक एकल-घटक सापेक्ष पथ हो; कोई स्लैश नहीं। व्यक्तिगत रूप से, मैं इसके बजाय आधार पैकेज_नाम का उपयोग करने के @ आर्टफंकल के दृष्टिकोण को पसंद करता हूं।
dannysauer

31

अजगर, एक निर्देशिका के तहत सभी फ़ाइलों को शामिल करें:

Newbies के लिए जो सिर्फ यह काम करने के लिए नहीं मिल सकता है जिन्हें अपने हाथों की आवश्यकता है।

  1. एक फोल्डर / होम / एल / फू बनाएं और एक फाइल main.pyको / होम / एल / फू के तहत बनाएं और इस कोड को वहां डालें:

    from hellokitty import *
    spam.spamfunc()
    ham.hamfunc()
  2. एक निर्देशिका बनाओ /home/el/foo/hellokitty

  3. के __init__.pyतहत एक फ़ाइल बनाएं /home/el/foo/hellokittyऔर इस कोड को उसमें डालें:

    __all__ = ["spam", "ham"]
  4. दो अजगर फाइलें बनाएं: spam.pyऔर उसके ham.pyनीचे/home/el/foo/hellokitty

  5. Spam.py के अंदर एक फंक्शन को परिभाषित करें:

    def spamfunc():
      print("Spammity spam")
  6. Ham.py के अंदर एक फ़ंक्शन को परिभाषित करें:

    def hamfunc():
      print("Upgrade from baloney")
  7. चलाओ:

    el@apollo:/home/el/foo$ python main.py 
    spammity spam
    Upgrade from baloney

1
न केवल न्यूबीज़ के लिए, बल्कि उन पाइथन देवों का भी अनुभव किया जो स्पष्ट उत्तर पसंद करते हैं। धन्यवाद।
माइकल शेपर

लेकिन उपयोग import *करना बुरा पायथन कोडिंग अभ्यास माना जाता है। आप इसके बिना यह कैसे करते हैं?
राचेल ब्लेक

16

मैं खुद इस समस्या से थक गया था, इसलिए मैंने इसे ठीक करने के लिए ऑटोमोडीनिट नामक एक पैकेज लिखा। आप इसे http://pypi.python.org/pypi/automodinit/ से प्राप्त कर सकते हैं ।

उपयोग इस प्रकार है:

  1. automodinitपैकेज को अपनी setup.pyनिर्भरता में शामिल करें ।
  2. इस तरह सभी __init__.py फ़ाइलों को बदलें:
__all__ = ["मैं फिर से लिखूंगा"]
# ऊपर की रेखा, या इस रेखा को संशोधित न करें!
आयात ऑटोमोडिनिट
ऑटोमोडिनिट.ओटोमोडिनिट (__ name__, __file__, ग्लोबल्स ())
डेल ऑटोमोडिनिट
# जो कुछ भी आप चाहते हैं वह यहां के बाद जा सकता है, यह संशोधित नहीं होगा।

बस! अब से एक मॉड्यूल आयात करने के लिए __all__ को मॉड्यूल में .py [co] फ़ाइलों की सूची में सेट करेगा और उन फ़ाइलों में से प्रत्येक को भी आयात करेगा जैसे आपने टाइप किया था:

for x in __all__: import x

इसलिए "एम आयात * से" का प्रभाव बिल्कुल "आयात एम" से मेल खाता है।

automodinit ज़िप अभिलेखागार के अंदर से खुश है और इसलिए ज़िप सुरक्षित है।

नियाल


पाइप ऑटोमोडिनेट डाउनलोड नहीं कर सकता है क्योंकि इसके लिए पीपीआई पर कुछ भी अपलोड नहीं किया गया है।
kanzure

जीथब पर बग रिपोर्ट के लिए धन्यवाद। मैंने इसे v0.13 में तय किया है। नियाल
नियाल डगलस

11

मुझे पता है कि मैं एक बहुत पुरानी पोस्ट को अपडेट कर रहा हूं, और मैंने उपयोग करने की कोशिश की automodinit, लेकिन पता चला कि यह python3 के लिए सेटअप प्रक्रिया टूट गई है। इसलिए, लुका के जवाब के आधार पर, मैं एक सरल उत्तर के साथ आया - जो इस मुद्दे पर .zip के साथ काम नहीं कर सकता है, इसलिए मुझे लगा कि मुझे इसे यहाँ साझा करना चाहिए:

भीतर __init__.pyसे मॉड्यूल yourpackage:

#!/usr/bin/env python
import os, pkgutil
__all__ = list(module for _, module, _ in pkgutil.iter_modules([os.path.dirname(__file__)]))

और नीचे एक और पैकेज के भीतर yourpackage:

from yourpackage import *

फिर आपके पास सभी मॉड्यूल होंगे जो लोड किए गए पैकेज के भीतर रखे गए हैं, और यदि आप एक नया मॉड्यूल लिखते हैं, तो यह स्वचालित रूप से भी आयात किया जाएगा। बेशक, इस तरह की चीजों का उपयोग सावधानी से करें, बड़ी शक्तियों के साथ बड़ी जिम्मेदारियां आती हैं।


6
import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
for imp, module, ispackage in pkgutil.walk_packages(path=__path__, prefix=__name__+'.'):
  __import__(module)

5

मैंने भी इस समस्या का सामना किया है और यह मेरा समाधान था:

import os

def loadImports(path):
    files = os.listdir(path)
    imps = []

    for i in range(len(files)):
        name = files[i].split('.')
        if len(name) > 1:
            if name[1] == 'py' and name[0] != '__init__':
               name = name[0]
               imps.append(name)

    file = open(path+'__init__.py','w')

    toWrite = '__all__ = '+str(imps)

    file.write(toWrite)
    file.close()

यह फ़ंक्शन एक फ़ाइल (प्रदान किए गए फ़ोल्डर में) नामित करता है __init__.py, जिसमें एक __all__चर होता है जो फ़ोल्डर में प्रत्येक मॉड्यूल रखता है।

उदाहरण के लिए, मेरे पास एक फ़ोल्डर है जिसका नाम है Test :

Foo.py
Bar.py

इसलिए स्क्रिप्ट में मैं चाहता हूं कि मॉड्यूल आयात किए जाएं जो मैं लिखूंगा:

loadImports('Test/')
from Test import *

इससे अब सब कुछ आयात हो जाएगा Testऔर __init__.pyफ़ाइल में Testअब शामिल होगा:

__all__ = ['Foo','Bar']

एकदम सही, मैं क्या देख रहा हूँ
uma महेश

4

कुछ सुधारों के साथ अनुराग का उदाहरण:

import os, glob

modules = glob.glob(os.path.join(os.path.dirname(__file__), "*.py"))
__all__ = [os.path.basename(f)[:-3] for f in modules if not f.endswith("__init__.py")]


3

देखें कि आपका __init__.pyपरिभाषित __all__मॉड्यूल - संकुल दस्तावेज़ कहते हैं

__init__.pyफ़ाइलों अजगर का इलाज के रूप में संकुल युक्त निर्देशिका बनाने के लिए आवश्यक हैं, यह एक सामान्य नाम से निर्देशिकाओं को रोकने के लिए किया जाता है, जैसे कि स्ट्रिंग, अनजाने में वैध मॉड्यूल छिपाते हैं जो बाद में मॉड्यूल खोज पथ पर होते हैं। सबसे सरल मामले में, __init__.pyबस एक खाली फ़ाइल हो सकती है, लेकिन यह पैकेज के लिए इनिशियलाइज़ेशन कोड को निष्पादित कर सकता है या __all__चर सेट कर सकता है, जिसे बाद में वर्णित किया गया है।

...

पैकेज लेखक के लिए एकमात्र समाधान पैकेज का एक स्पष्ट सूचकांक प्रदान करना है। आयात विवरण निम्न सम्मेलन का उपयोग करता है: यदि पैकेज का __init__.pyकोड नाम की सूची को परिभाषित करता है __all__, तो इसे उन मॉड्यूल नामों की सूची में लिया जाता है, जिन्हें पैकेज आयात * से सामना करने पर आयात किया जाना चाहिए। जब पैकेज का नया संस्करण जारी किया जाता है तो इस सूची को अद्यतित रखना पैकेज लेखक पर निर्भर है। पैकेज लेखक भी इसका समर्थन नहीं करने का फैसला कर सकते हैं, अगर उन्हें अपने पैकेज से * आयात करने के लिए उपयोग नहीं दिखता है। उदाहरण के लिए, फ़ाइल sounds/effects/__init__.pyमें निम्न कोड हो सकता है:

__all__ = ["echo", "surround", "reverse"]

इसका मतलब यह होगा कि from sound.effects import *साउंड पैकेज के तीन नामित सबमॉडल्स आयात करेंगे।


3

यह मुझे अब तक मिला सबसे अच्छा तरीका है:

from os.path import dirname, join, isdir, abspath, basename
from glob import glob
pwd = dirname(__file__)
for x in glob(join(pwd, '*.py')):
    if not x.startswith('__'):
        __import__(basename(x)[:-3], globals(), locals())

2

importlibकेवल एक चीज का उपयोग करना जो आपको मिला है वह है

from importlib import import_module
from pathlib import Path

__all__ = [
    import_module(f".{f.stem}", __package__)
    for f in Path(__file__).parent.glob("*.py")
    if "__" not in f.stem
]
del import_module, Path

यह एक वैध खस्ता मुद्दे की ओर जाता है error: Type of __all__ must be "Sequence[str]", not "List[Module]":। __all__यदि इस import_moduleआधारित दृष्टिकोण का उपयोग किया जाता है, तो परिभाषित करने की आवश्यकता नहीं है।
एक्यूमेनस

1

मानक पुस्तकालय से pkgutil मॉड्यूल को देखें। यह आपको वही करेगा जो आप तब तक करना चाहते हैं जब तक आपके पास __init__.pyनिर्देशिका में एक फ़ाइल है। __init__.pyफ़ाइल खाली हो सकती।


1

मैंने उसके लिए एक मॉड्यूल बनाया है, जो कि __init__.py(या किसी अन्य सहायक फ़ाइल पर) निर्भर नहीं करता है और मुझे केवल निम्न दो लाइनें टाइप करता है:

import importdir
importdir.do("Foo", globals())

बेझिझक पुन: उपयोग करें या योगदान करें: http://gitlab.com/aurelien-lourot/importdir


0

बस उन्हें importlib द्वारा आयात करें और पैकेज में पुनरावृत्ति के लिए __all__( addक्रिया वैकल्पिक है) में जोड़ें __init__.py

/Foo
    bar.py
    spam.py
    eggs.py
    __init__.py

# __init__.py
import os
import importlib
pyfile_extes = ['py', ]
__all__ = [importlib.import_module('.%s' % filename, __package__) for filename in [os.path.splitext(i)[0] for i in os.listdir(os.path.dirname(__file__)) if os.path.splitext(i)[1] in pyfile_extes] if not filename.startswith('__')]
del os, importlib, pyfile_extes

Pyfile_extes को कहाँ परिभाषित किया गया है?
जेपी

इसे याद करने के लिए खेद है, अब ठीक हो गया है। यह पायथन फाइल का एक्स्टेंशन है जिसे आप आयात करना चाहते हैं, आमतौर पर सिर्फpy
चेनी

0

जब from . import *यह पर्याप्त नहीं है, तो यह टेड द्वारा उत्तर पर एक सुधार है । विशेष रूप से, __all__इस दृष्टिकोण के साथ का उपयोग आवश्यक नहीं है।

"""Import all modules that exist in the current directory."""
# Ref https://stackoverflow.com/a/60861023/
from importlib import import_module
from pathlib import Path

for f in Path(__file__).parent.glob("*.py"):
    module_name = f.stem
    if (not module_name.startswith("_")) and (module_name not in globals()):
        import_module(f".{module_name}", __package__)
    del f, module_name
del import_module, Path

ध्यान दें कि module_name not in globals()यदि यह पहले से ही आयात किया गया है, तो मॉड्यूल को पुन: आयात करने से बचने का इरादा है, क्योंकि यह चक्रीय आयात को जोखिम में डाल सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.