কোনও ফোল্ডারে সমস্ত মডিউল কীভাবে লোড করবেন?


269

মডিউলগুলির একটি সম্পূর্ণ ডিরেক্টরি আমদানির জন্য কোনও ভাল উপায় আমাকে সরবরাহ করতে পারে?
আমার মতো কাঠামো আছে:

/Foo
    bar.py
    spam.py
    eggs.py

আমি শুধু যোগ করে একটি প্যাকেজ থেকে এটি রূপান্তর চেষ্টা __init__.pyএবং করছেন from Foo import *কিন্তু এটা আমি আশা করেছিল কাজ করে নি।


2
Init .py পথ প্রশংসনীয় সঠিক। আপনি কি কোডটি পোস্ট করতে পারেন যা কাজ করে নি?
বালফা

9
আপনি "কাজ করেননি" সংজ্ঞা দিতে পারেন? কি হলো? আপনি কোন ত্রুটি বার্তা পেয়েছেন?
এসলট


স্পষ্টতই আরও ভাল। আপনি প্রতিবার নতুন মডিউল যুক্ত করার পরে আপনি কি সত্যিই এই বিরক্তিকর 'না পাওয়া' বার্তাগুলিকে সম্বোধন করতে চান? আমি মনে করি যে আপনার যদি অনেকগুলি ছোট মডিউল-ফাংশন সমন্বিত একটি প্যাকেজ ডিরেক্টরি থাকে তবে এটি এটি যাওয়ার সর্বোত্তম উপায়। আমার অনুমানগুলি হ'ল: 1. মডিউলটি বরং সহজ 2. আপনি কোড পরিস্কার করার জন্য প্যাকেজটি ব্যবহার করেন
ইডো_ফ

উত্তর:


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
@ নিলডডগলাস এই উত্তরটি নির্দিষ্ট প্রশ্নের জন্য যা ওপি জিজ্ঞাসা করেছিল, তার কাছে একটি জিপ ফাইল নেই এবং পাইক ফাইলগুলি সহজেই অন্তর্ভুক্ত করা যেতে পারে, এবং আপনি .pyd বা .so লিবস ইত্যাদি ভুলে যাচ্ছেন
অনুরাগ ইউনিিয়াল

35
কেবলমাত্র আমি যুক্ত করতে if not os.path.basename(f).startswith('_')if not f.endswith('__init__.py')
পারব বা

10
এটা আরো জোরালো করতে, এছাড়াও নিশ্চিত os.path.isfile(f)হয় True। এটি ভাঙা প্রতিলিপি এবং ডিরেক্টরিগুলি যেমন ফিল্টার করবে somedir.py/(কর্নার-কেস, আমি স্বীকার করি, তবে এখনও ...)
MestreLion

12
যোগ from . import *সেটিং পর __all__যদি আপনি submodules ব্যবহার প্রাপ্তিসাধ্য হতে চান .(যেমন হিসাবে module.submodule1, module.submodule2ইত্যাদি)।
ostrokach

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
Nam G VU

1
@ নামজিভিউ: আমার সম্পর্কিত সম্পর্কিত প্রশ্নের এই কোডটি সর্বজনীন সাব-মডিউলগুলির নাম প্যাকেজটির নেমস্পেসে আমদানি করবে।
মার্টিনিউ

54

2017 সালে আপডেট: আপনি সম্ভবত importlibপরিবর্তে ব্যবহার করতে চান ।

Foo ডিরেক্টরিটি একটি যুক্ত করে একটি প্যাকেজ তৈরি করুন __init__.py। যে __init__.pyঅ্যাড:

import bar
import eggs
import spam

যেহেতু আপনি এটি গতিশীল চান (যা একটি ভাল ধারণা হতে পারে বা নাও হতে পারে), তাই সমস্ত পাই-ফাইল তালিকা ডিরের সাথে তালিকাভুক্ত করুন এবং এ জাতীয় কিছু দিয়ে তা আমদানি করুন:

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
টিবিএইচ, আমি __import__হ্যাকিশ খুঁজে পেয়েছি, আমি মনে করি নামগুলি যুক্ত করা ভাল __all__এবং from . import *স্ক্রিপ্টের নীচে রেখে দেওয়া ভাল হবে
ফ্রিফোরাল টাউজ

1
আমি মনে করি এটি গ্লোব সংস্করণের চেয়ে ভাল।
lpapp

8
__import__এটি সাধারণ ব্যবহারের জন্য নয়, এটি পরিবর্তে interpreterব্যবহার importlib.import_module()করুন।
অ্যান্ড্রু_1510

2
প্রথম উদাহরণটি খুব সহায়ক ছিল, ধন্যবাদ! পাইথন ৩.6.৪ এর অধীনে পাইথন আমদানি 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'>

এটি বেশিরভাগ ক্ষেত্রে সঠিক উত্তরের পথে রয়েছে - এটি জিপ সংরক্ষণাগার পরিচালনা করে, তবে দীক্ষা বা আমদানি করে না । নীচে অটোমোডিনিট দেখুন।
নিলাল ডগলাস

1
আরেকটি বিষয়: উপরের উদাহরণটি মডিউলটি ইতিমধ্যে লোড হয়েছে কিনা তা দেখতে sys.modules পরীক্ষা করে না। উপরের চেকটি ছাড়াই মডিউলটি দ্বিতীয়বার লোড করবে :)
নিলাল ডগলাস

3
আমি যখন আপনার কোড দিয়ে লোড_ল_মডিউল_ফর্ম_ডির ('ফু / বার') চালাই তখন আমি "রানটাইম ওয়ার্নিং: পরম আমদানি পরিচালনা করার সময় পিতামাতা মডিউল 'ফু / বার' খুঁজে পাই না" - এটি দমন করতে, আমাকে পুরো_প্যাকেজ_নাম = 'সেট করতে হবে join dirname.split (os.path.sep) + প্যাকেজ_নাম]) এবং এছাড়াও 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

পাইথন, সমস্ত ফাইল একটি ডিরেক্টরিতে অন্তর্ভুক্ত করুন:

যারা নতুন হাত পেতে কেবল এটি কাজ করতে পারেন না তাদের হাত রাখা দরকার।

  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. স্প্যাম.পাইয়ের ভিতরে একটি ফাংশন সংজ্ঞায়িত করুন:

    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 ফাইলগুলি প্রতিস্থাপন করুন:
__ সমস্ত__ = ["আমি আবার লিখব"]
# উপরের রেখাটি পরিবর্তন করবেন না, বা এই লাইন!
স্বয়ংক্রিয়তা আমদানি করুন
অটোমোডিনিট.আউটোমোডিনিট (__ নাম__, __ ফাইল__, গ্লোবাল ())
ডেল অটোমোডিনিট
# আপনি চাইলে আর যে কোনও কিছু এখানে যেতে পারে, এটি সংশোধিত হবে না।

এটাই! এখন থেকে একটি মডিউল আমদানি করার পরে মডিউলটিতে .py [co] ফাইলগুলির তালিকায় __ সমস্ত___ সেট করা হবে এবং আপনি টাইপ করে যেমন ফাইলগুলি প্রতিটি আমদানি করবেন:

for x in __all__: import x

সুতরাং "এম থেকে আমদানি *" এর প্রভাবটি ঠিক "আমদানি এম" এর সাথে মেলে।

automodinit জিপ সংরক্ষণাগারগুলির অভ্যন্তর থেকে দৌড়াদৌড়ি খুশি এবং তাই জিপ নিরাপদ।

নিয়াল


পাইপ অটোমোডিনাইট ডাউনলোড করতে পারে না কারণ এর জন্য পাইপিতে কিছুই আপলোড করা হয়নি।
কানজুরে

গিথুব-এ বাগ রিপোর্টের জন্য ধন্যবাদ। আমি v0.13 এ এটি স্থির করেছি। নিয়াল
নিলাল ডগলাস

11

আমি জানি আমি একটি বেশ পুরানো পোস্ট আপডেট করছি, এবং আমি চেষ্টা করার চেষ্টা করেছি automodinit, কিন্তু এটির সেটআপ প্রক্রিয়াটি পাইথন 3 এর জন্য নষ্ট হয়ে গেছে। সুতরাং, লুসার উত্তরের ভিত্তিতে আমি একটি সহজ উত্তর নিয়ে এসেছি - যা সম্ভবত এই সমস্যাটিতে .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 *

তারপরে আপনার কাছে সমস্ত মডিউল রয়েছে যা প্যাকেজটি লোড হওয়া অবস্থায় থাকবে এবং আপনি যদি একটি নতুন মডিউল লেখেন তবে এটি স্বয়ংক্রিয়ভাবেও আমদানি করা হবে। অবশ্যই, সেই ধরণের জিনিস যত্ন সহ ব্যবহার করুন, দুর্দান্ত শক্তির সাথে দুর্দান্ত দায়িত্ব আসে responsibilities


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 mahesh

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

একটি বৈধ mypy সমস্যাটি এই বিশালাকার: 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

কেবল সেগুলি আমদানি করে আমদানি করুন এবং প্যাকেজের প্যাকেজে পুনরাবৃত্তি হিসাবে এগুলিতে__all__ ( addক্রিয়াটি is চ্ছিক) যুক্ত করুন __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

পাইফাইল_একটিএস কোথায় সংজ্ঞায়িত হয়?
Jeppe

এটি মিস করার জন্য দুঃখিত, এখন স্থির। এটি আপনি যে অজগর ফাইলটি আমদানি করতে চান তা কেবলমাত্র 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()মডিউলটি ইতিমধ্যে আমদানি করা হলে তা পুনরায় রক্ষা করা এড়ানোর উদ্দেশ্যে করা হয়েছে, কারণ এটি চক্রীয় আমদানির ঝুঁকি নিতে পারে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.