डायनामिक रूप से आयातित मॉड्यूल में एक वर्ग के स्ट्रिंग नाम से डायनेमिक तात्कालिकता?


180

अजगर में, मुझे एक निश्चित स्ट्रिंग में उसका नाम जानने के लिए, निश्चित कक्षा को तुरंत करना होगा, लेकिन यह क्लास एक डायनामिक रूप से आयातित मॉड्यूल में 'रहता है'। एक उदाहरण इस प्रकार है:

लोडर-श्रेणी स्क्रिप्ट:

import sys
class loader:
  def __init__(self, module_name, class_name): # both args are strings
    try:
      __import__(module_name)
      modul = sys.modules[module_name]
      instance = modul.class_name() # obviously this doesn't works, here is my main problem!
    except ImportError:
       # manage import error

कुछ-गतिशील-लोड-मॉड्यूल स्क्रिप्ट:

class myName:
  # etc...

मैं इस व्यवस्था का उपयोग किसी भी गतिशील-लोड-मॉड्यूल को लोड करने के लिए उपयोग करने के लिए करता हूं, जो कि dyn-लोड-मॉड्यूल में कुछ पूर्वनिर्धारित व्यवहारों के बाद लोडर-क्लास द्वारा उपयोग किया जाता है ...

जवाबों:


251

आप getattr का उपयोग कर सकते हैं

getattr(module, class_name)

कक्षा तक पहुँचने के लिए। अधिक पूर्ण कोड:

module = __import__(module_name)
class_ = getattr(module, class_name)
instance = class_()

जैसा कि नीचे उल्लेख किया गया है , हम importlib का उपयोग कर सकते हैं

import importlib
module = importlib.import_module(module_name)
class_ = getattr(module, class_name)
instance = class_()

3
module = __import__(module, fromlist=[name])केवल मेरे लिए काम किया।
umpirsky

16
यदि किसी को ऊपर बताई गई आयात विधि Sven से परेशानी हो रही है, तो मैंने पाया कि मेरा कोड importlib.import_module के बजाय निम्नलिखित विधि का उपयोग करके बेहतर काम कर रहा है । इस तरह इस्तेमाल किया जा सकता है: मॉड्यूल = importlib.import_module (मॉड्यूल_नाम)
jpennell

@ जेन्नेल आपको एक उत्तर के रूप में पोस्ट करना चाहिए, यह अक्सर अधिक उपयोगी है जो सीधे लौटे स्ट्रिंग का उपयोग करने में सक्षम होobj.__module__
एनेंट्रोपिक

importlib.import_moduleयदि आवश्यक हो तो .py फ़ाइल को एक pyc में लोड करें और साथ ही पूरा मॉड्यूल संभालें ।name.pathing.to.get.to.the क्लास। __import__इन दोनों चीजों को नहीं करेंगे, एक django के वातावरण में (इसके बाहर परीक्षण नहीं किया गया)
जेम्स

123

tl; डॉ

रूट मॉड्यूल को आयात करें importlib.import_moduleऔर getattrफ़ंक्शन का उपयोग करके उसके नाम से कक्षा को लोड करें :

# Standard import
import importlib
# Load "module.submodule.MyClass"
MyClass = getattr(importlib.import_module("module.submodule"), "MyClass")
# Instantiate the class (pass arguments to the constructor, if needed)
instance = MyClass()

स्पष्टीकरण

आप शायद __import__नाम से मॉड्यूल को गतिशील रूप से आयात करने के लिए उपयोग नहीं करना चाहते हैं , क्योंकि यह आपको सबमॉड्यूल आयात करने की अनुमति नहीं देता है:

>>> mod = __import__("os.path")
>>> mod.join
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'join'

यहाँ अजगर डॉक्टर के बारे में क्या कहते हैं __import__:

नोट: यह एक उन्नत फंक्शन है, जो कि importlib.import_module () के विपरीत, रोज़ पाइथन प्रोग्रामिंग में आवश्यक नहीं है।

इसके बजाय, मानक importlibमॉड्यूल का उपयोग नाम से मॉड्यूल को गतिशील रूप से आयात करने के लिए करें। साथ getattrआप तो इसके नाम से एक वर्ग का दृष्टांत कर सकते हैं:

import importlib
my_module = importlib.import_module("module.submodule")
MyClass = getattr(my_module, "MyClass")
instance = MyClass()

आप यह भी लिख सकते हैं:

import importlib
module_name, class_name = "module.submodule.MyClass".rsplit(".", 1)
MyClass = getattr(importlib.import_module(module_name), class_name)
instance = MyClass()

यह कोड अजगर is 2.7 (अजगर 3 सहित) में मान्य है।


1
शायद मैं आपका जवाब नहीं समझता, लेकिन मैंने सबमॉडल्स आयात करने के लिए आयात का उपयोग किया है : __import __ ("मॉड्यूल।" + सबमॉड्यूल_नाम_स्ट्रिंग)
जेवियर नोवोआ सी।

निम्नलिखित कोड एक गुण में परिणाम देता है: mod = __import__("os.path"); mod.joinजबकि निम्नलिखित नहीं है:mod = importlib.import_module("os.path"); mod.join
Régis B.

ओह, मैं देख रहा हूँ, आप सही हैं लेकिन मैंने os.path.join विधि प्राप्त करने के लिए निम्न कार्य किया है: getattr (sys.modules ["os.path"], "join")
जेवियर नोवोआ सी।

हा! और मैं देखता हूं कि जब उसका उपयोग होता है, तो ' आयात ' अनावश्यक XD है
जेवियर नोवोआ सी।

2
उत्तर के रूप में चिह्नित विकल्प ने मेरे लिए काम नहीं किया (सबमोडुल्स का उपयोग करके) हालांकि यह उत्तर देता है। मुझे लगता है कि यह जवाब होना चाहिए क्योंकि यह गतिशील रूप से लोडिंग मॉड्यूल के लिए अधिक सामान्य समाधान है।
rachachach

14

getattrएक स्ट्रिंग में नाम से एक विशेषता प्राप्त करने के लिए उपयोग करें । दूसरे शब्दों में, उदाहरण के रूप में मिलता है

instance = getattr(modul, class_name)()

10

कॉपी-पेस्ट स्निपेट:

import importlib
def str_to_class(module_name, class_name):
    """Return a class instance from a string reference"""
    try:
        module_ = importlib.import_module(module_name)
        try:
            class_ = getattr(module_, class_name)()
        except AttributeError:
            logging.error('Class does not exist')
    except ImportError:
        logging.error('Module does not exist')
    return class_ or None

5

यदि आप चाहते हैं कि यह वाक्य from foo.bar import foo2गतिशील रूप से लोड किया जाए, तो आपको यह करना चाहिए

foo = __import__("foo")
bar = getattr(foo,"bar")
foo2 = getattr(bar,"foo2")

instance = foo2()

4

एक बस pydoc.locateफ़ंक्शन का उपयोग कर सकता है ।

from pydoc import locate
my_class = locate("module.submodule.myclass")
instance = my_class()

2

मैं ऊपर के उदाहरणों से अपने उपयोग के मामले में वहां नहीं पहुंच सका, लेकिन अहमद ने मुझे निकटतम (धन्यवाद) दिया। भविष्य में इसे पढ़ने वालों के लिए, यहां वह कोड है जो मेरे लिए काम करता है।

def get_class(fully_qualified_path, module_name, class_name, *instantiation):
    """
    Returns an instantiated class for the given string descriptors
    :param fully_qualified_path: The path to the module eg("Utilities.Printer")
    :param module_name: The module name eg("Printer")
    :param class_name: The class name eg("ScreenPrinter")
    :param instantiation: Any fields required to instantiate the class
    :return: An instance of the class
    """
    p = __import__(fully_qualified_path)
    m = getattr(p, module_name)
    c = getattr(m, class_name)
    instance = c(*instantiation)
    return instance
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.