স্ট্রিং হিসাবে একটি মডিউল এর নাম দেওয়া কীভাবে আমদানি করবেন?


543

আমি একটি পাইথন অ্যাপ্লিকেশন লিখছি যা একটি আর্গুমেন্ট হিসাবে একটি আদেশ হিসাবে গ্রহণ করে, উদাহরণস্বরূপ:

$ python myapp.py command1

আমি চাইছি অ্যাপ্লিকেশনটি এক্সটেনসিবল হোক, অর্থাত্ মূল অ্যাপ্লিকেশন উত্সটি পরিবর্তন না করেই নতুন কমান্ড প্রয়োগকারী নতুন মডিউল যুক্ত করতে সক্ষম হোন। গাছটি দেখতে এমন কিছু দেখাচ্ছে:

myapp/
    __init__.py
    commands/
        __init__.py
        command1.py
        command2.py
    foo.py
    bar.py

সুতরাং আমি অ্যাপ্লিকেশনটি রানটাইমের সময় উপলভ্য কমান্ড মডিউলগুলি সন্ধান করতে এবং উপযুক্তটিকে সম্পাদন করতে চাই।

পাইথন একটি __Import__ ফাংশন সংজ্ঞায়িত করে, যা মডিউল নামের জন্য একটি স্ট্রিং নেয়:

__ গুরুত্বপূর্ণ __ (নাম, গ্লোবালস = কোনও নয়, স্থানীয় = কোনওটি নেই, তালিকা = () স্তর = 0)

প্যাকেজ প্রসঙ্গে কীভাবে নামটি ব্যাখ্যা করা যায় তা নির্ধারণ করতে ফাংশনটি প্রদত্ত গ্লোবাল এবং স্থানীয়দের ব্যবহার করে মডিউলটির নাম আমদানি করে। নাম তালিকা মডিউল থেকে আমদানি করা উচিত এমন বস্তু বা সাবমডিউলগুলির নাম দেয় list

উত্স: https://docs.python.org/3/library/function.html# আমদানি

সুতরাং বর্তমানে আমার মতো কিছু রয়েছে:

command = sys.argv[1]
try:
    command_module = __import__("myapp.commands.%s" % command, fromlist=["myapp.commands"])
except ImportError:
    # Display error message

command_module.run()

এটি ঠিকঠাক কাজ করে, আমি কেবল ভাবছি যে এই কোডটি দিয়ে আমরা কী করছি তা সম্পাদন করার জন্য আরও কোনও মূর্খ উপায় আছে কিনা।

নোট করুন যে আমি বিশেষত ডিম বা এক্সটেনশন পয়েন্ট ব্যবহার করতে চাই না। এটি কোনও ওপেন সোর্স প্রকল্প নয় এবং আমি "প্লাগইন" থাকার আশা করি না। মূল বক্তব্যটি হ'ল মূল অ্যাপ্লিকেশন কোডটি সরল করা এবং প্রতিবার নতুন কমান্ড মডিউল যুক্ত হওয়ার পরে এটি সংশোধন করার প্রয়োজনীয়তা সরিয়ে ফেলা উচিত।


Fromlist = ["myapp.commands"] কি করে?
পিটার মোলার

@ PieterMüller: একটি পাইথন শেল এই টাইপ করুন: dir(__import__)। "নাম আমদানি থেকে ..." অনুকরণ করার জন্য তালিকা থেকে নামগুলির তালিকা হওয়া উচিত।
mawimawi


2019 হিসাবে, আপনার সন্ধান করা উচিত importlib: স্ট্যাকওভারফ্লো.com
ব্র্যান্ডেট

অযৌক্তিক__ ব্যবহার করবেন না পাইথন ডকটি একটি Importlib.import_module
এফসিএম

উত্তর:


320

পাইথনটি ২.7 / ৩.১ এর চেয়ে পুরানো, আপনি এটি কীভাবে করেন তা অনেকটাই।

নতুন সংস্করণগুলির importlib.import_moduleজন্য, পাইথন 2 এবং পাইথন 3 এর জন্য দেখুন

আপনিও চাইলে ব্যবহার করতে পারেন exec

বা ব্যবহার করে __import__আপনি এটি করে মডিউলগুলির একটি তালিকা আমদানি করতে পারেন:

>>> moduleNames = ['sys', 'os', 're', 'unittest'] 
>>> moduleNames
['sys', 'os', 're', 'unittest']
>>> modules = map(__import__, moduleNames)

পাইথন থেকে ডাইভ থেকে সোজা ছিড়ে ।


7
কার্যকর করতে আলাদা কি?
ব্যবহারকারী 1767754

1
আপনি কিভাবে __init__এই মডিউল ব্যবহার করতে পারেন ?
ডোরিয়ান ডোরে

7
ওপির জন্য এই সমাধানটির একটি সমস্যা হ'ল দু'টি খারাপ "কমান্ড" মডিউলগুলির জন্য ব্যতিক্রম আটকে দেওয়া তার ব্যতীত সম্পূর্ণ কমান্ড-অ্যাপকে ব্যর্থ করে দেয়। ব্যক্তিগতভাবে আমি প্রতিটি আমদানির জন্য পৃথকভাবে একটি চেষ্টা করে মোড়ানোর জন্য লুপ চাইতাম : মোডস = __ আমদানি __ () x নেক্সসেপ্ট ইম্পোর্টের ত্রুটি হিসাবে ভুল: খারাপগুলি স্থির হওয়ার সাথে সাথে অন্যান্য কমান্ডগুলি কাজ চালিয়ে যাওয়ার অনুমতি দেওয়ার জন্য রিপোর্ট (ত্রুটি) করুন।
দেবপ্লেয়ার

7
ডেনিস ম্যালিনোভস্কি নীচের দিকে নির্দেশ করেছেন বলে এই সমাধানের সাথে আর একটি সমস্যা হ'ল পাইথন ডক্সগুলি নিজেরাই ব্যবহার না করার পরামর্শ দেয় __import__। ২. doc ডক্স: "কারণ এই ফাংশনটি পাইথন দোভাষী দ্বারা ব্যবহারের জন্য এবং সাধারণ ব্যবহারের জন্য নয়, ইম্পোর্টলিবি.মম্পোর্ট_মডিউল () ব্যবহার করা আরও ভাল ..." পাইথন 3 ব্যবহার করার সময় impমডিউলটি এই সমস্যাটি সমাধান করে, যেমন নীচে মনকুত উল্লেখ করেছেন।
লিয়াভকে

2
@ জোহানউইউ আপনার foreachযখন প্রয়োজন for element inএবং কেন map():) আপনাকে প্রয়োজন
কৌবার্ট

300

পাইথন ২.7 এবং ৩.১ এর প্রস্তাবিত উপায় এবং পরবর্তীটি হল importlibমডিউলটি ব্যবহার করা :

Importlib.import_module (নাম, প্যাকেজ = কিছুই নেই)

একটি মডিউল আমদানি করুন। নামের যুক্তিটি নির্ধারণ করে যে কোন মডিউলটি পরম বা আপেক্ষিক পদে আমদানি করতে হবে (উদাঃ pkg.mod বা ..mod) either নামটি যদি আপেক্ষিক পদে নির্দিষ্ট করা থাকে, তবে প্যাকেজটির নামটি সমাধান করার জন্য অ্যাঙ্কর হিসাবে কাজ করার জন্য প্যাকেজ আর্গুমেন্টটি অবশ্যই সেট করতে হবে (যেমন Import_module ('.. মোড', 'pkg.subpkg')) pkg.mod আমদানি করবে)।

যেমন

my_module = importlib.import_module('os.path')

2
কোন উত্স বা কর্তৃপক্ষ দ্বারা প্রস্তাবিত?
মিচুয়েলনিক

66
ডকুমেন্টেশন উল্লিখিত মডিউলটির পক্ষে ফাংশন ব্যবহারের বিরুদ্ধে পরামর্শ দেয় __import__
ডেনিস ম্যালিনভস্কি

8
এটি আমদানির জন্য ভাল কাজ করে os.path; কীভাবে from os.path import *?
নাম জি ভিইউ

5
আমি উত্তরটি এখানে stackoverflow.com/a/44492879/248616 অর্থাত্ পেয়ে যাচ্ছি । কল করাglobals().update(my_module.__dict)
নাম জি ভিইউ

2
@ নামজিভিউ, এটি আপনার বিপ্লবকে দূষিত করার কারণে এটি একটি বিপজ্জনক পদ্ধতি এবং একই নামের সাথে কোনও শনাক্তকারীকে ওভাররাইড করতে পারে। আপনার পোস্ট করা লিঙ্কটির এই কোডটির একটি উন্নততর উন্নত সংস্করণ রয়েছে।
ডেনিস ম্যালিনভস্কি

131

নোট: বিচ্ছু পক্ষে পাইথন 3.4 থেকে অবচিত importlib

যেমন উল্লেখ করা হয়েছে ইমম্প মডিউল আপনাকে লোডিং ফাংশন সরবরাহ করে:

imp.load_source(name, path)
imp.load_compiled(name, path)

আমি এ জাতীয় কিছু ব্যবহার করতে আগে ব্যবহার করেছি।

আমার ক্ষেত্রে আমি সংজ্ঞায়িত পদ্ধতিগুলির সাথে একটি নির্দিষ্ট শ্রেণি সংজ্ঞায়িত করেছি যা প্রয়োজনীয় ছিল। আমি মডিউলটি লোড করার পরে ক্লাসটি মডিউলটিতে ছিল কিনা তা পরীক্ষা করে দেখি এবং তারপরে that শ্রেণীর একটি উদাহরণ তৈরি করতাম, এরকম কিছু:

import imp
import os

def load_from_file(filepath):
    class_inst = None
    expected_class = 'MyClass'

    mod_name,file_ext = os.path.splitext(os.path.split(filepath)[-1])

    if file_ext.lower() == '.py':
        py_mod = imp.load_source(mod_name, filepath)

    elif file_ext.lower() == '.pyc':
        py_mod = imp.load_compiled(mod_name, filepath)

    if hasattr(py_mod, expected_class):
        class_inst = getattr(py_mod, expected_class)()

    return class_inst

2
ভাল এবং সহজ সমাধান। আমি অনুরূপ একটি লিখেছি: stamat.wordpress.com/dynamic-module-import-in-python তবে আপনার কিছু ত্রুটি রয়েছে: ব্যতিক্রম সম্পর্কে কী? IOError এবং ImportError? প্রথমে সংকলিত সংস্করণ এবং তারপরে উত্স সংস্করণটি কেন পরীক্ষা করা হবে না। কোনও শ্রেণি আশা করা আপনার ক্ষেত্রে পুনরায় ব্যবহারযোগ্যতা হ্রাস করে।
stamat

3
লক্ষ্য মডিউলে যেখানে আপনি MyClass বানান সেই লাইনে আপনি শ্রেণীর নামের সাথে একটি অপ্রয়োজনীয় উল্লেখ যুক্ত করছেন। এটি ইতিমধ্যে সংরক্ষণ করা হয়েছে expected_classযাতে আপনি class_inst = getattr(py_mod,expected_name)()পরিবর্তে এটি করতে পারেন ।
অ্যান্ড্রু

1
মনে রাখবেন যে যদি একটি যথাযথভাবে মিলে যাওয়া বাইট-সংকলিত ফাইল (প্রত্যয়। পিপিসিপি বা .pyo সহ) উপস্থিত থাকে তবে প্রদত্ত উত্স ফাইলটি পার্স করার পরিবর্তে এটি ব্যবহৃত হবেhttps://docs.python.org/2/library/imp.html#imp.load_source
সিডোসবার

1
মাথা আপ: এই সমাধান কাজ করে; তবে ইমম্প মডিউলটি আমদানি লিবের পক্ষে অবচয় করা হতে চলেছে, ইমের পৃষ্ঠাটি দেখুন: "" "সংস্করণ ৩.৪ থেকে অবহেলিত: ইমপ্লাইজটির পক্ষে ইমপ্যাক্স প্যাকেজ অবমানন মুলতুবি রয়েছে" ""
রিকার্ডো


15

আজকাল আপনার আমদানি করা উচিত ।

একটি উত্স ফাইল আমদানি করুন

ডক্স আসলে যে জন্য একটি উপায় প্রদান করে, এবং এটি ভালো যায়:

import sys
import importlib.util

file_path = 'pluginX.py'
module_name = 'pluginX'

spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)

# check if it's all there..
def bla(mod):
    print(dir(mod))
bla(module)

একটি প্যাকেজ আমদানি করুন

একটি প্যাকেজ আমদানি হচ্ছে ( যেমন , pluginX/__init__.py) আপনার বর্তমান Dir অধীনে আসলে সহজবোধ্য:

import importlib

pkg = importlib.import_module('pluginX')

# check if it's all there..
def bla(mod):
    print(dir(mod))
bla(pkg)

2
যোগ sys.modules[module_name] = moduleআপনার কোড শেষে আপনি পাবে চান import module_nameপরে
ড্যানিয়েল ব্রাউন

11

আপনি যদি এটি চান আপনার স্থানীয়দের মধ্যে:

>>> mod = 'sys'
>>> locals()['my_module'] = __import__(mod)
>>> my_module.version
'2.6.6 (r266:84297, Aug 24 2010, 18:46:32) [MSC v.1500 32 bit (Intel)]'

একই সাথে কাজ করবে globals()


ডকুমেন্টেশন জন্য বিল্ট ইন locals()ফাংশন স্পষ্টভাবে সতর্ক করেন যে, "এই অভিধান বিষয়বস্তু পরিবর্তন করা উচিত"।
মার্টিনিউ

9

আপনি ব্যবহার করতে পারেন exec:

exec("import myapp.commands.%s" % command)

আমি এক্সিকিউটের মাধ্যমে মডিউলে কীভাবে একটি হ্যান্ডেল পাব, যাতে আমি .run () পদ্ধতিটি কল করতে পারি?
কামিল কিসিয়েল

5
তারপরে মডিউলটি অ্যাক্সেস করতে আপনি getattr (myapp.commands, আদেশ) করতে পারেন।
গ্রেগ হিউগিল

1
... বা as command_moduleআমদানির বিবরণীর শেষে যুক্ত করুন এবং তারপরেcommand_module.run()
অক্সফেন

পাইথন 3+ এর কয়েকটি সংস্করণে এক্সিকিউটর অতিরিক্ত সংযোজন হিসাবে একটি ফাংশনে রূপান্তরিত হয়েছিল যে উত্সটিতে তৈরি ফলাফলটি রেফারেন্সযুক্ত স্থানীয়দের () এক্সিকিউটিভ () এর যুক্তিতে সংরক্ষণ করে। স্থানীয় কোড ব্লকের স্থানীয়দের থেকে নির্বাহিত রেফারেন্সকে আলাদা করতে আপনি নিজের ডিকটি সরবরাহ করতে পারেন, খালিটির মতো এবং সেই ডিকটি ব্যবহার করে রেফারেন্সগুলি উল্লেখ করতে পারেন বা সেই ডিকটি অন্য ফাংশনে এক্সিকিউটি (উত্স, গোবলস (), কমান্ড 1_ডিক্ট) দিয়ে যেতে পারেন .... মুদ্রণ (কমান্ড 1_ডিক্ট ['কিছুটা পরিবর্তনযোগ্য'])
দেবপ্লেয়ার

3

@ মোমকুট এর সমাধান হিসাবে অনুরূপ তবে এখানে বর্ণিত পুনরায় ব্যবহারযোগ্য এবং ত্রুটি সহনশীল http://stamat.wordpress.com/dynamic-module-import-in-python/ :

import os
import imp

def importFromURI(uri, absl):
    mod = None
    if not absl:
        uri = os.path.normpath(os.path.join(os.path.dirname(__file__), uri))
    path, fname = os.path.split(uri)
    mname, ext = os.path.splitext(fname)

    if os.path.exists(os.path.join(path,mname)+'.pyc'):
        try:
            return imp.load_compiled(mname, uri)
        except:
            pass
    if os.path.exists(os.path.join(path,mname)+'.py'):
        try:
            return imp.load_source(mname, uri)
        except:
            pass

    return mod

1

নীচের অংশটি আমার জন্য কাজ করেছে:

>>>import imp; 
>>>fp, pathname, description = imp.find_module("/home/test_module"); 
>>>test_module = imp.load_module("test_module", fp, pathname, description);
>>>print test_module.print_hello();

আপনি যদি শেল-স্ক্রিপ্টে আমদানি করতে চান:

python -c '<above entire code in one line>'

-2

উদাহরণস্বরূপ, আমার মডিউলের নামগুলি jan_module/ feb_module/ এর মতো mar_module

month = 'feb'
exec 'from %s_module import *'%(month)

-7

নিম্নলিখিত আমার জন্য কাজ করেছে:

import sys, glob
sys.path.append('/home/marc/python/importtest/modus')
fl = glob.glob('modus/*.py')
modulist = []
adapters=[]
for i in range(len(fl)):
    fl[i] = fl[i].split('/')[1]
    fl[i] = fl[i][0:(len(fl[i])-3)]
    modulist.append(getattr(__import__(fl[i]),fl[i]))
    adapters.append(modulist[i]())

এটি ফোল্ডার 'মোডাস' থেকে মডিউলগুলি লোড করে। মডিউলগুলির একটি একক বর্গ রয়েছে মডিউলের নামের মতো name উদাহরণস্বরূপ ফাইল মোডাস / modu1.py রয়েছে:

class modu1():
    def __init__(self):
        self.x=1
        print self.x

ফলাফলটি গতিশীল লোড শ্রেণীর "অ্যাডাপ্টার" এর একটি তালিকা।


13
মন্তব্যে কোনও কারণ না দিয়ে উত্তরগুলি কবর দেবেন না। এটি কাউকে সাহায্য করে না।
রিবস

আমি কেন এটি খারাপ জিনিস তা জানতে চাই।
দেবপ্লেয়ার

আমার মতো একই, যেহেতু আমি পাইথনে নতুন এবং জানতে চাই, কেন এটি খারাপ।
Kosmos

5
এটি অজগরটিকে খারাপ বলে নয়, এটি সাধারণত খারাপ কোডও। কী fl? লুপ সংজ্ঞা জন্য অত্যধিক জটিল। পাথটি হার্ড কোডড (এবং উদাহরণস্বরূপ, অপ্রাসঙ্গিক)। এটি নিরুৎসাহিত অজগর ( __import__) ব্যবহার করছে, এগুলি কীসের fl[i]জন্য? এটি মূলত অপঠনযোগ্য, এবং এমন কোনও কিছুর জন্য অহেতুক জটিল যেগুলি এতটা কঠিন নয় - শীর্ষস্থানীয় ভোট দেওয়া উত্তরটি এর ওয়ান-লাইনারের সাথে দেখুন।
ফিল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.