पायथन वर्ग को गतिशील रूप से कैसे लोड करें


167

पायथन वर्ग की एक स्ट्रिंग को देखते हुए, उदाहरण के लिए my_package.my_module.MyClass, इसे लोड करने का सबसे अच्छा तरीका क्या है?

दूसरे शब्दों में, मैं Class.forName()जावा में एक समकक्ष की तलाश कर रहा हूं , पायथन में कार्य करता है। इसे Google App Engine पर काम करने की आवश्यकता है।

अधिमानतः यह एक ऐसा कार्य होगा जो वर्ग के FQN को एक स्ट्रिंग के रूप में स्वीकार करता है, और कक्षा के लिए एक संदर्भ देता है:

my_class = load_class('my_package.my_module.MyClass')
my_instance = my_class()

मुझे कक्षा के संदर्भ को एक चर के रूप में भी निर्दिष्ट करने में सक्षम होना चाहिए।
pjesi

1
यह डुप्लिकेट प्रतीत होता है: stackoverflow.com/questions/452969/…
cdleary

आप सही हैं यह एक डुप्लिकेट है, इसे खोजने के लिए धन्यवाद
pjesi

1
मुझे पायथन में इस तरह एक वर्ग को लोड करने की आवश्यकता नहीं है। आप जानते हैं कि मॉड्यूल कहाँ है, इसलिए केवल मॉड्यूल को लोड न करें और फिर अपनी कक्षाओं का उपयोग करें जैसे कि पायथन आपको चाहता है, इसका सबसे सरल
एडम स्पेंस

22
यदि आपको कभी ऐसा करने की आवश्यकता नहीं है, तो आपने अभी तक दिलचस्प कार्यक्रम नहीं लिखे हैं। अभ्यास करते रहो।
जॉन Tyree

जवाबों:


194

अजगर प्रलेखन से, यहाँ आप चाहते हैं समारोह है:

def my_import(name):
    components = name.split('.')
    mod = __import__(components[0])
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod

कारण यह है कि एक साधारण __import__काम नहीं करेगा क्योंकि पैकेज स्ट्रिंग में पहले डॉट के अलावा किसी भी चीज़ का कोई भी आयात आपके द्वारा आयात किए जा रहे मॉड्यूल की विशेषता है। इस प्रकार, कुछ इस तरह से काम नहीं करेगा:

__import__('foo.bar.baz.qux')

आपको उपरोक्त फ़ंक्शन को कॉल करना होगा:

my_import('foo.bar.baz.qux')

या अपने उदाहरण के मामले में:

klass = my_import('my_package.my_module.my_class')
some_object = klass()

संपादित करें : मैं इस पर थोड़ा दूर था। आप मूल रूप से ऐसा करना चाहते हैं:

from my_package.my_module import my_class

उपरोक्त फ़ंक्शन केवल आवश्यक है यदि आपके पास एक खाली सूची है। इस प्रकार, उपयुक्त कॉल इस तरह होगा:

mod = __import__('my_package.my_module', fromlist=['my_class'])
klass = getattr(mod, 'my_class')

मैंने my_import ('my_package.my_module.my_class') की कोशिश की, लेकिन कोई भी ऐसा मॉड्यूल नहीं मिला, जो my_class पाया, जो समझ में आता है क्योंकि यह एक वर्ग है जो मॉड्यूल नहीं है। अगर मैं अपने फोन पर my_import
pjesi

अजीब है कि। पहली डॉट के पीछे सब कुछ गेटअटर का उपयोग करके कहा जाता है। कोई अंतर नहीं होना चाहिए।
जेसन बेकर

धन्यवाद मुझे लगता है कि यह सबसे अच्छा तरीका है। अब मुझे केवल mod_name, klass_name में स्ट्रिंग 'my_pakcage.my_module.my_class' को विभाजित करने का सबसे अच्छा तरीका चाहिए, लेकिन मुझे लगता है कि मैं यह पता लगा सकता हूं :)
pjesi

2
आयात के अजगर प्रलेखन (कोड पर) importlib का उपयोग करने के लिए कहते हैं। इसलिए एडम स्पैन द्वारा जवाब देना चाहिए
नाओको


125

यदि आप अपना स्वयं का रोल नहीं करना चाहते हैं, तो pydocमॉड्यूल में एक फ़ंक्शन उपलब्ध है जो बिल्कुल ऐसा करता है:

from pydoc import locate
my_class = locate('my_package.my_module.MyClass')

यहां सूचीबद्ध अन्य लोगों के लिए इस दृष्टिकोण का लाभ यह है कि प्रदान किए गए बिंदीदार पथ पर किसी भी अजगर वस्तु locateको मिलेगा , न कि सीधे एक मॉड्यूल के भीतर एक वस्तु। उदा ।my_package.my_module.MyClass.attr

यदि आप उत्सुक हैं कि उनका नुस्खा क्या है, तो यहां देखें:

def locate(path, forceload=0):
    """Locate an object by name or dotted path, importing as necessary."""
    parts = [part for part in split(path, '.') if part]
    module, n = None, 0
    while n < len(parts):
        nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
        if nextmodule: module, n = nextmodule, n + 1
        else: break
    if module:
        object = module
    else:
        object = __builtin__
    for part in parts[n:]:
        try:
            object = getattr(object, part)
        except AttributeError:
            return None
    return object

यह pydoc.safeimportफंक्शन पर निर्भर करता है। यहाँ उसके लिए डॉक्स हैं:

"""Import a module; handle errors; return None if the module isn't found.

If the module *is* found but an exception occurs, it's wrapped in an
ErrorDuringImport exception and reraised.  Unlike __import__, if a
package path is specified, the module at the end of the path is returned,
not the package at the beginning.  If the optional 'forceload' argument
is 1, we reload the module from disk (unless it's a dynamic extension)."""

1
मैंने इस उत्तर को उकेरा। BTW, यहाँ वह कोड है जो सुरक्षित भी है क्योंकि यह सिर्फ इसके लिए pydoc आयात करना अजीब लगता है: github.com/python/cpython/blob/…
brirayray

मैंने इस उत्तर को भी बदल दिया, यह सभी प्रासंगिक उत्तरों में से सबसे अच्छा है।
सन वेई सेप

यह qualnameसही ढंग से (मॉड्यूल नेमस्पेस के शीर्ष पर वस्तु नहीं) को ठीक से करने में सक्षम होने के लिए लगता है ।
मिस्टरमैगी

हां, आप कर सकते हैंlocate('my_package.my_module.MyClass.attr.method.etc')
चाडिक

109
import importlib

module = importlib.import_module('my_package.my_module')
my_class = getattr(module, 'MyClass')
my_instance = my_class()

9
एक बार जब आप मॉड्यूल को गतिशील रूप से आयात कर लेते हैं तो आपके पास मॉड्यूल के माध्यम से कक्षा तक पहुंच होती है
एडम स्पेंस

बस मैंने और अधिक संक्षिप्त होने के लिए अपने उत्तर को संपादित किया। पायथन में एक कक्षा को लोड करने का यह सबसे अच्छा तरीका है।
एडम स्पैन

बीबीबी-बेनी एंड द स्पेंस! ;)
dKen

महान! यह मानक पुस्तकालय का हिस्सा 2.7 और ऊपर से भी है।
एपर्टेक्स

मॉड्यूल / क्लास तक पहुंचने का यह सही तरीका है। डॉक्स यह यहाँ बताता
नोएल इवांस

29
def import_class(cl):
    d = cl.rfind(".")
    classname = cl[d+1:len(cl)]
    m = __import__(cl[0:d], globals(), locals(), [classname])
    return getattr(m, classname)

5
यह है स्वच्छ उपाय! आप उपयोग करने पर विचार कर सकते हैं:(modulename, classname) = cl.rsplit('.', 2)
vdboor

यह बहुत अच्छा है) मैंने अलग-अलग बर्तनों के साथ पुटल्स पैकेज बनाया था, वहां आयात करने वाले वर्ग भी। आप चाहें तो उस पैकेज से इसका उपयोग कर सकते हैं।
स्टेन



18

यदि आप Django का उपयोग कर रहे हैं तो आप इसका उपयोग कर सकते हैं। हाँ, मुझे पता है कि ओपी ने django के लिए नहीं पूछा था, लेकिन मैं इस सवाल पर एक Django समाधान की तलाश में दौड़ा, एक नहीं मिला, और इसे अगले लड़के / लड़की के लिए यहां डाल दिया।

# It's available for v1.7+
# https://github.com/django/django/blob/stable/1.7.x/django/utils/module_loading.py
from django.utils.module_loading import import_string

Klass = import_string('path.to.module.Klass')
func = import_string('path.to.module.func')
var = import_string('path.to.module.var')

ध्यान रखें, यदि आप कुछ ऐसा आयात करना चाहते हैं जिसमें ए ., जैसे reया argparseउपयोग न हो:

re = __import__('re')

6

यहाँ मैं पर पाया कुछ साझा करने के लिए है __import__और importlibजबकि इस समस्या को हल करने की कोशिश कर।

मैं पायथॉन 3.7.3 का उपयोग कर रहा हूं।

जब मैं dमॉड्यूल में कक्षा में आने की कोशिश करता हूं a.b.c,

mod = __import__('a.b.c')

modचर शीर्ष नाम स्थान का उल्लेख a

इसलिए कक्षा में जाने के लिए d, मुझे जरूरत है

mod = getattr(mod, 'b') #mod is now module b
mod = getattr(mod, 'c') #mod is now module c
mod = getattr(mod, 'd') #mod is now class d

अगर हम करने की कोशिश करेंगे

mod = __import__('a.b.c')
d = getattr(mod, 'd')

हम वास्तव में देखने की कोशिश कर रहे हैं a.d

उपयोग करते समय importlib, मुझे लगता है कि पुस्तकालय ने getattrहमारे लिए पुनरावर्ती कार्य किया है। इसलिए, जब हम उपयोग करते हैं importlib.import_module, तो हम वास्तव में सबसे गहरे मॉड्यूल पर एक हैंडल प्राप्त करते हैं।

mod = importlib.import_module('a.b.c') #mod is module c
d = getattr(mod, 'd') #this is a.b.c.d

1

ठीक है, मेरे लिए यह काम करने का तरीका है (मैं पायथन 2.7 का उपयोग कर रहा हूं):

a = __import__('file_to_import', globals(), locals(), ['*'], -1)
b = a.MyClass()

तब, b कक्षा 'MyClass' का एक उदाहरण है


0

यदि आपके पास पहले से ही अपनी इच्छित कक्षा का एक उदाहरण है, तो आप 'टाइप' फ़ंक्शन का उपयोग अपनी कक्षा के प्रकार को निकालने के लिए कर सकते हैं और नए उदाहरण के निर्माण के लिए इसका उपयोग कर सकते हैं:

class Something(object):
    def __init__(self, name):
        self.name = name
    def display(self):
        print(self.name)

one = Something("one")
one.display()
cls = type(one)
two = cls("two")
two.display()

-2
module = __import__("my_package/my_module")
the_class = getattr(module, "MyClass")
obj = the_class()

5
ध्यान दें कि आयात फ़ंक्शन में बग के कारण यह काम करता है। फ़ाइल पथ आयात फ़ंक्शन में उपयोग नहीं किए जाने चाहिए और अजगर 2.6 और इसके बाद के संस्करण में काम नहीं करेंगे: docs.python.org/whatsnew/2.6.html#porting-to-python-2-6
जेसन बेकर

-2

Google App Engine में एक webapp2फ़ंक्शन होता है जिसे कहा जाता है import_string। अधिक जानकारी के लिए यहां देखें: https://webapp-improved.appspot.com/api/webapp2.html

इसलिए,

import webapp2
my_class = webapp2.import_string('my_package.my_module.MyClass')

उदाहरण के लिए इसका उपयोग उस webapp2.Routeजगह पर किया जाता है जहां आप या तो हैंडलर या स्ट्रिंग का उपयोग कर सकते हैं।

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