पायथन 3 में सापेक्ष आयात


711

मैं उसी निर्देशिका में किसी अन्य फ़ाइल से फ़ंक्शन आयात करना चाहता हूं।

कभी-कभी यह मेरे साथ काम करता है from .mymodule import myfunctionलेकिन कभी-कभी मुझे एक मिल जाता है:

SystemError: Parent module '' not loaded, cannot perform relative import

कभी-कभी इसके साथ काम करता है from mymodule import myfunction, लेकिन कभी-कभी मुझे भी मिलता है:

SystemError: Parent module '' not loaded, cannot perform relative import

मैं यहाँ तर्क को नहीं समझता, और मुझे कोई स्पष्टीकरण नहीं मिला। यह पूरी तरह से यादृच्छिक लगता है।

क्या कोई मुझे समझा सकता है कि इस सबके पीछे तर्क क्या है?


76
इसका मतलब है कि आप स्क्रिप्ट के रूप में पैकेज के अंदर एक मॉड्यूल चला रहे हैं। केवल पैकेज के बाहर से स्क्रिप्ट चलाएँ ।
मार्टिज़न पीटरर्स

3
संभवत: आपको उन स्थितियों को परिभाषित करना चाहिए, जिनके बारे में आप 'कभी-कभी' उल्लेख करते हैं। मैं समझता हूं कि आपका मतलब यह नहीं है कि आपकी यादृच्छिक त्रुटियाँ हैं।
जौनकिन

15
@MartijnPieters: ठीक है, दुर्भाग्य से, इस मॉड्यूल को पैकेज के अंदर होना चाहिए, और इसे स्क्रिप्ट के रूप में, कभी-कभी रन करने योग्य भी होना चाहिए। किसी भी विचार मैं कैसे हासिल कर सकता है?
जॉन स्मिथ वैकल्पिक

22
@ जॉन्सस्मिथऑशनल: पैकेज के अंदर स्क्रिप्ट मिक्स करना मुश्किल है और अगर संभव हो तो इसे टाला जाना चाहिए। रैपर स्क्रिप्ट का उपयोग करें जो पैकेज को आयात करता है और इसके बजाय आपके 'स्क्रिप्टी' फ़ंक्शन को चलाता है।
मार्टिज़न पीटरर्स

3
दुर्भाग्यपूर्ण लगता है। मैंने कक्षाओं / विधियों के साथ एक मुख्य मॉड्यूल बनाया जो एक निश्चित प्रकार की फ़ाइल को पार्स / विश्लेषण कर सकता है, और मेरे पास (मुख्य रूप से खुद के लिए) अलग-अलग माध्यमिक मॉड्यूल और स्क्रिप्ट हैं जो इसे आयात करते हैं - ये उन फ़ाइलों को मालिश / परिवर्तित कर सकते हैं। लेकिन मैं उस सिंगल कोर फ़ाइल (पूरे जटिल पैकेज को नहीं) को अंतिम उपयोगकर्ता को सौंपना पसंद करता हूं ताकि वे आसानी से इसे अपनी फ़ाइल के बगल में रख सकें और इसे चला सकें। उस "स्क्रिप्ट मोड" में, यह फ़ाइल और एन्कोडिंग का विश्लेषण और विश्लेषण करता है, विभिन्न क्षेत्रों / मूल्यों / विशेष वर्णों को लंबा करता है, और एक रिपोर्ट देता है। लेकिन यह वास्तव में फ़ाइल को संशोधित नहीं करता है। विरोधी पैटर्न?
जॉन कॉम्ब्स

जवाबों:


526

दुर्भाग्य से, इस मॉड्यूल को पैकेज के अंदर होना चाहिए, और इसे स्क्रिप्ट के रूप में, कभी-कभी रन करने योग्य भी होना चाहिए। किसी भी विचार मैं कैसे हासिल कर सकता है?

इस तरह का लेआउट होना काफी आम है ...

main.py
mypackage/
    __init__.py
    mymodule.py
    myothermodule.py

... mymodule.pyइस तरह से ...

#!/usr/bin/env python3

# Exported function
def as_int(a):
    return int(a)

# Test function for module  
def _test():
    assert as_int('1') == 1

if __name__ == '__main__':
    _test()

... myothermodule.pyइस तरह ...

#!/usr/bin/env python3

from .mymodule import as_int

# Exported function
def add(a, b):
    return as_int(a) + as_int(b)

# Test function for module  
def _test():
    assert add('1', '1') == 2

if __name__ == '__main__':
    _test()

... और main.pyइस तरह ...

#!/usr/bin/env python3

from mypackage.myothermodule import add

def main():
    print(add('1', '1'))

if __name__ == '__main__':
    main()

... जो ठीक काम करता है जब आप चलाते हैं main.pyया mypackage/mymodule.py, लेकिन mypackage/myothermodule.pyरिश्तेदार आयात के कारण विफल रहता है ...

from .mymodule import as_int

जिस तरह से आप इसे चलाने वाले हैं ...

python3 -m mypackage.myothermodule

... लेकिन यह कुछ हद तक क्रियात्मक है, और इस तरह की एक शेबंग लाइन के साथ अच्छी तरह से मिश्रण नहीं होता है #!/usr/bin/env python3

इस मामले के लिए सबसे सरल समाधान, यह मानते हुए कि यह नाम mymoduleविश्व स्तर पर अद्वितीय है, रिश्तेदार आयातों का उपयोग करने से बचना होगा, और बस उपयोग करना होगा ...

from mymodule import as_int

... हालाँकि, यदि यह अद्वितीय नहीं है, या आपकी पैकेज संरचना अधिक जटिल है, तो आपको अपनी पैकेज निर्देशिका वाली निर्देशिका को शामिल PYTHONPATHकरना होगा और इसे इस तरह करना होगा ...

from mypackage.mymodule import as_int

... या यदि आप चाहते हैं कि यह "बॉक्स से बाहर" काम करे, तो आप PYTHONPATHइस के साथ पहले कोड में फ्रोब कर सकते हैं ...

import sys
import os

PACKAGE_PARENT = '..'
SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__))))
sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT)))

from mypackage.mymodule import as_int

यह एक तरह का दर्द है, लेकिन इस बात का कोई सुराग है कि एक ईमेल में एक निश्चित गिडो वैन रोसुम द्वारा लिखित ...

मैं इस पर -1 और __main__ मशीनरी के किसी अन्य प्रस्तावित ट्विडलिंग पर हूँ । एकमात्र उपयोग मामला स्क्रिप्ट को चलाने वाला लगता है जो कि मॉड्यूल की निर्देशिका के अंदर रहने वाला होता है, जिसे मैंने हमेशा एक एंटीपैटर्न के रूप में देखा है। मुझे अपना मन बदलने के लिए आपको मुझे विश्वास दिलाना होगा कि ऐसा नहीं है।

पैकेज के अंदर स्क्रिप्ट चलाना एक विषय-वस्तु है या नहीं व्यक्तिपरक है, लेकिन व्यक्तिगत रूप से मुझे यह वास्तव में एक पैकेज में उपयोगी लगता है, जिसमें कुछ कस्टम wxPython विजेट हैं, इसलिए मैं किसी भी स्रोत फ़ाइलों के लिए स्क्रिप्ट चला सकता हूं wx.Frameजिसमें केवल एक प्रदर्शित करने के लिए है परीक्षण प्रयोजनों के लिए वह विजेट।


7
SCRIPTDIR प्राप्त करने का एक बेहतर तरीका एक रिश्तेदार पथ से एक मॉड्यूल आयात की टिप्पणी में दिया गया है जैसे os.path.realpath(os.path.dirname(inspect.getfile(inspect.currentframe())))कि आपका विश्वास है कि आपका मॉड्यूल हमेशा एक उचित है fileजिसे आप भी उपयोग कर सकते हैं os.path.realpath(os.path.dirname(__file__))
मार्ग

2
अधिक छोटे और पठनीय कोड स्निपेट लगाकर आप अपने PYTHONPATH का विस्तार कर सकते हैं: sys.path.append( os.path.join( os.path.dirname(__file__), os.path.pardir ) )
एलेक्स-बोगडानोव

12
...which I've always seen as an antipattern.मैं यह नहीं देखता कि यह एक विरोधी पैटर्न कैसे है ... ऐसा लगता है कि यह सुपर सुविधाजनक होगा बस रिश्तेदार आयात सहज रूप से काम करते हैं। मैं बस उन चीजों को आयात करने में सक्षम होना चाहता हूं जो मुझे पता है कि उसी निर्देशिका में हैं। मुझे आश्चर्य है कि उसका तर्क क्या था
युंगगुन

8
गुइडो फिर से हमला करता है: निक्सिंग सामान जो उपयोगी हो सकता था। खैर अब ऐसा नहीं होगा।
जादव

3
यह सबसे दुखद बात है जिसे मैंने कभी पायथन के बारे में देखा है।
एतिलियोआ

262

व्याख्या

से पीईपी 328

पैकेज पदानुक्रम में उस मॉड्यूल की स्थिति निर्धारित करने के लिए सापेक्ष आयात एक मॉड्यूल की __name__ विशेषता का उपयोग करते हैं। यदि मॉड्यूल के नाम में कोई पैकेज जानकारी नहीं है (उदाहरण के लिए यह '__main__' पर सेट है) तो सापेक्ष आयात हल किए जाते हैं जैसे कि मॉड्यूल एक शीर्ष स्तर मॉड्यूल था , चाहे मॉड्यूल वास्तव में फ़ाइल सिस्टम पर स्थित हो।

कुछ बिंदु पर PEP 338 PEP 328 के साथ विवादित है :

... सापेक्ष आयात पैकेज पदानुक्रम में वर्तमान मॉड्यूल की स्थिति निर्धारित करने के लिए __name__ पर निर्भर करता है । एक मुख्य मॉड्यूल में, __name__ का मान हमेशा '__main__' होता है , इसलिए स्पष्ट सापेक्ष आयात हमेशा विफल होंगे (क्योंकि वे केवल पैकेज के अंदर एक मॉड्यूल के लिए काम करते हैं)

और समस्या को हल करने के लिए, PEP 366 ने शीर्ष स्तर चर पेश किया __package__:

एक नया मॉड्यूल स्तर विशेषता जोड़कर, यह पीईपी स्वचालित रूप से काम करने की अनुमति देता है यदि मॉड्यूल -m स्विच का उपयोग करके निष्पादित किया जाता है । मॉड्यूल में बॉयलरप्लेट की थोड़ी मात्रा स्वयं ही रिश्तेदार आयात को काम करने की अनुमति देगा जब फ़ाइल को नाम से निष्पादित किया जाता है। [...] जब यह [विशेषता] मौजूद है, रिश्तेदार आयात मॉड्यूल __name__ विशेषता के बजाय इस विशेषता पर आधारित होंगे । [...] जब मुख्य मॉड्यूल इसके फ़ाइलनाम द्वारा निर्दिष्ट किया जाता है, तो __package__ विशेषता को किसी पर सेट नहीं किया जाएगा । [...] जब आयात प्रणाली __package__ सेट के बिना एक मॉड्यूल में एक स्पष्ट सापेक्ष आयात का सामना करती है (या इसके साथ कोई भी सेट नहीं करता है), तो यह सही मूल्य की गणना करेगा और संग्रहीत करेगा ()सामान्य मॉड्यूल के लिए __name __। rpartition ('।') [0] और पैकेज आरंभीकरण मॉड्यूल के लिए __name__ )

(जोर मेरा)

यदि __name__है '__main__', तो __name__.rpartition('.')[0]खाली स्ट्रिंग लौटाता है। यही कारण है कि त्रुटि विवरण में खाली स्ट्रिंग शाब्दिक है:

SystemError: Parent module '' not loaded, cannot perform relative import

सीपीथॉन के PyImport_ImportModuleLevelObjectसमारोह का प्रासंगिक हिस्सा :

if (PyDict_GetItem(interp->modules, package) == NULL) {
    PyErr_Format(PyExc_SystemError,
            "Parent module %R not loaded, cannot perform relative "
            "import", package);
    goto error;
}

CPython इस अपवाद को उठाता है अगर यह package(पैकेज का नाम) interp->modules(जैसा कि सुलभ sys.modules) में नहीं मिल रहा था। के बाद से sys.modulesहै "एक शब्दकोश मॉड्यूल जो पहले से ही लोड हो जाने के लिए मॉड्यूल के नाम के नक्शे है कि" , यह अब स्पष्ट है कि माता-पिता मॉड्यूल रिश्तेदार आयात प्रदर्शन से पहले स्पष्ट रूप से पूर्ण आयातित होना चाहिए

नोट: 18018 के अंक के पैचने एक और ifब्लॉक जोड़ा है, जिसेऊपर दिए गए कोड से पहले निष्पादित किया जाएगा:

if (PyUnicode_CompareWithASCIIString(package, "") == 0) {
    PyErr_SetString(PyExc_ImportError,
            "attempted relative import with no known parent package");
    goto error;
} /* else if (PyDict_GetItem(interp->modules, package) == NULL) {
    ...
*/

यदि package(ऊपर जैसा है) खाली स्ट्रिंग है, तो त्रुटि संदेश होगा

ImportError: attempted relative import with no known parent package

हालाँकि, आप इसे केवल पायथन 3.6 या नए में देखेंगे।

समाधान # 1: -m का उपयोग करके अपनी स्क्रिप्ट चलाएँ

एक निर्देशिका पर विचार करें (जो एक पायथन पैकेज है ):

.
├── package
│   ├── __init__.py
│   ├── module.py
│   └── standalone.py

पैकेज की सभी फाइलें कोड की समान 2 पंक्तियों से शुरू होती हैं:

from pathlib import Path
print('Running' if __name__ == '__main__' else 'Importing', Path(__file__).resolve())

मैं केवल परिचालन के क्रम को स्पष्ट करने के लिए इन दो पंक्तियों को शामिल कर रहा हूँ । हम उन्हें पूरी तरह से अनदेखा कर सकते हैं, क्योंकि वे निष्पादन को प्रभावित नहीं करते हैं।

__init__.py और मॉड्यूल.py में केवल वे दो पंक्तियाँ होंगी (यानी, वे प्रभावी रूप से खाली हैं)।

standalone.py अतिरिक्त मॉड्यूल आयात करने का प्रयास करता है सापेक्ष आयात के माध्यम से:

from . import module  # explicit relative import

हम अच्छी तरह जानते हैं कि /path/to/python/interpreter package/standalone.pyअसफल होंगे। हालांकि, हम साथ मॉड्यूल चला सकते हैं -mआदेश पंक्ति विकल्प कि "खोज sys.pathनामित मॉड्यूल के लिए और के रूप में उसकी सामग्री पर अमल __main__मॉड्यूल" :

vaultah@base:~$ python3 -i -m package.standalone
Importing /home/vaultah/package/__init__.py
Running /home/vaultah/package/standalone.py
Importing /home/vaultah/package/module.py
>>> __file__
'/home/vaultah/package/standalone.py'
>>> __package__
'package'
>>> # The __package__ has been correctly set and module.py has been imported.
... # What's inside sys.modules?
... import sys
>>> sys.modules['__main__']
<module 'package.standalone' from '/home/vaultah/package/standalone.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/package/module.py'>
>>> sys.modules['package']
<module 'package' from '/home/vaultah/package/__init__.py'>

-mक्या आपके लिए सभी आयात करने वाला सामान और स्वचालित रूप से सेट हो जाता है __package__, लेकिन आप स्वयं ऐसा कर सकते हैं

समाधान # 2: सेट __package__ मैन्युअल रूप से

कृपया इसे वास्तविक समाधान के बजाय अवधारणा के प्रमाण के रूप में मानें। यह वास्तविक दुनिया कोड में उपयोग के लिए अच्छी तरह से अनुकूल नहीं है।

PEP 366 में इस समस्या का समाधान है, हालांकि, यह अधूरा है, क्योंकि __package__अकेले सेट करना पर्याप्त नहीं है। आपको मॉड्यूल पदानुक्रम में कम से कम एन पूर्ववर्ती पैकेज आयात करने की आवश्यकता है , जहां एन मूल निर्देशिका (स्क्रिप्ट की निर्देशिका के सापेक्ष) की संख्या है जिसे आयात किए जा रहे मॉड्यूल के लिए खोजा जाएगा।

इस प्रकार,

  1. वर्तमान मॉड्यूल के Nth पूर्ववर्ती की मूल निर्देशिका को इसमें जोड़ेंsys.path

  2. वर्तमान फ़ाइल की निर्देशिका को निकालें sys.path

  3. पूरी तरह से योग्य नाम का उपयोग करके वर्तमान मॉड्यूल के मूल मॉड्यूल को आयात करें

  4. 2__package__ से पूरी तरह से योग्य नाम पर सेट करें

  5. रिश्तेदार आयात करते हैं

मैं समाधान # 1 से फ़ाइलें उधार लूंगा और कुछ और उप-पैकेज जोड़ूंगा:

package
├── __init__.py
├── module.py
└── subpackage
    ├── __init__.py
    └── subsubpackage
        ├── __init__.py
        └── standalone.py

इस बार स्टैंडअलोनहोम निम्नलिखित सापेक्ष आयात का उपयोग करके पैकेज से मॉड्यूल थिंकपैड आयात करेगा

from ... import module  # N = 3

हमें बॉयलरलाइन कोड के साथ उस लाइन को पूर्ववर्ती करने की आवश्यकता होगी, जिससे यह काम कर सके।

import sys
from pathlib import Path

if __name__ == '__main__' and __package__ is None:
    file = Path(__file__).resolve()
    parent, top = file.parent, file.parents[3]

    sys.path.append(str(top))
    try:
        sys.path.remove(str(parent))
    except ValueError: # Already removed
        pass

    import package.subpackage.subsubpackage
    __package__ = 'package.subpackage.subsubpackage'

from ... import module # N = 3

यह हमें फ़ाइल नाम से स्टैंडअलोनहोम निष्पादित करने की अनुमति देता है :

vaultah@base:~$ python3 package/subpackage/subsubpackage/standalone.py
Running /home/vaultah/package/subpackage/subsubpackage/standalone.py
Importing /home/vaultah/package/__init__.py
Importing /home/vaultah/package/subpackage/__init__.py
Importing /home/vaultah/package/subpackage/subsubpackage/__init__.py
Importing /home/vaultah/package/module.py

एक समारोह में लिपटे एक अधिक सामान्य समाधान यहां पाया जा सकता है । उदाहरण उपयोग:

if __name__ == '__main__' and __package__ is None:
    import_parents(level=3) # N = 3

from ... import module
from ...module.submodule import thing

समाधान # 3: पूर्ण आयात और सेटपूल का उपयोग करें

कदम हैं -

  1. समान पूर्ण आयात के साथ स्पष्ट सापेक्ष आयात बदलें

  2. packageइसे आयात करने योग्य बनाने के लिए स्थापित करें

उदाहरण के लिए, निर्देशिका संरचना निम्नानुसार हो सकती है

.
├── project
│   ├── package
│   │   ├── __init__.py
│   │   ├── module.py
│   │   └── standalone.py
│   └── setup.py

जहां सेटअप है

from setuptools import setup, find_packages
setup(
    name = 'your_package_name',
    packages = find_packages(),
)

बाकी फाइलें समाधान # 1 से उधार ली गई थीं ।

स्थापना आपको अपनी कार्यशील निर्देशिका की परवाह किए बिना पैकेज को आयात करने की अनुमति देगा (यह मानते हुए कि कोई नामकरण समस्या नहीं होगी)।

हम इस लाभ (चरण 1) का उपयोग करने के लिए स्टैंडअलोनहोम को संशोधित कर सकते हैं :

from package import module  # absolute import

अपनी कार्यशील निर्देशिका को बदलें projectऔर चलाएं /path/to/python/interpreter setup.py install --user( अपनी साइट-संकुल निर्देशिका--user में पैकेज स्थापित करता है ) (चरण 2):

vaultah@base:~$ cd project
vaultah@base:~/project$ python3 setup.py install --user

आइए सत्यापित करें कि स्क्रिप्ट के रूप में स्टैंडअलोनहोम चलाना अब संभव है :

vaultah@base:~/project$ python3 -i package/standalone.py
Running /home/vaultah/project/package/standalone.py
Importing /home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/__init__.py
Importing /home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py
>>> module
<module 'package.module' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py'>
>>> import sys
>>> sys.modules['package']
<module 'package' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/__init__.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py'>

नोट : यदि आप इस मार्ग से नीचे जाने का निर्णय लेते हैं, तोअलगाव में पैकेजों को स्थापित करने के लिए आभासी वातावरण का उपयोग करना बेहतर होगा।

समाधान # 4: पूर्ण आयात और कुछ बॉयलरप्लेट कोड का उपयोग करें

सच कहूँ तो, इंस्टॉलेशन आवश्यक नहीं है - पूर्ण आयात कार्य करने के लिए आप अपनी स्क्रिप्ट में कुछ बॉयलरप्लेट कोड जोड़ सकते हैं।

मैं समाधान # 1 से फ़ाइलों को उधार लेने जा रहा हूं और स्टैंडअलोन एरोमा को बदलूंगा :

  1. पूर्ण आयात का उपयोग करके पैकेज से कुछ भी आयात करने का प्रयास करने से पहले पैकेज की मूल निर्देशिका को जोड़ें :sys.path

    import sys
    from pathlib import Path # if you haven't already done so
    file = Path(__file__).resolve()
    parent, root = file.parent, file.parents[1]
    sys.path.append(str(root))
    
    # Additionally remove the current file's directory from sys.path
    try:
        sys.path.remove(str(parent))
    except ValueError: # Already removed
        pass
  2. पूर्ण आयात द्वारा सापेक्ष आयात को बदलें:

    from package import module  # absolute import

स्टैंडअलोनहोम समस्याओं के बिना चलता है:

vaultah@base:~$ python3 -i package/standalone.py
Running /home/vaultah/package/standalone.py
Importing /home/vaultah/package/__init__.py
Importing /home/vaultah/package/module.py
>>> module
<module 'package.module' from '/home/vaultah/package/module.py'>
>>> import sys
>>> sys.modules['package']
<module 'package' from '/home/vaultah/package/__init__.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/package/module.py'>

मुझे लगता है कि मुझे आपको चेतावनी देनी चाहिए: ऐसा करने की कोशिश न करें, खासकर अगर आपकी परियोजना में एक जटिल संरचना है।


एक साइड नोट के रूप में, PEP 8 पूर्ण आयात के उपयोग की सिफारिश करता है, लेकिन बताता है कि कुछ परिदृश्यों में स्पष्ट सापेक्ष आयात स्वीकार्य हैं:

पूर्ण आयात की सिफारिश की जाती है, क्योंकि वे आमतौर पर अधिक पठनीय होते हैं और बेहतर व्यवहार करने की प्रवृत्ति होती है (या कम से कम बेहतर त्रुटि संदेश देते हैं)। [...] हालांकि, स्पष्ट सापेक्ष आयात पूर्ण आयात के लिए एक स्वीकार्य विकल्प है, खासकर जब जटिल पैकेज लेआउट के साथ काम करते हुए जहां पूर्ण आयात का उपयोग अनावश्यक रूप से किया जाएगा।


3
क्या समस्या को हल करने के लिए __package__नाम मैन्युअल रूप से सेट करना संभव __main__है?
पाउलो स्कर्दिन

धन्यवाद, अच्छा जवाब! मैं मॉड्यूल का उपयोग करके मॉड्यूल को लोड करने impऔर __package__तदनुसार सेट करने में सक्षम था, लेकिन परिणाम स्पष्ट रूप से एक विरोधी पैटर्न है।
पाउलो स्कर्डीने

मुझे त्रुटि मिलती है AttributeError: 'PosixPath' object has no attribute 'path'
उपयोगकर्ता

त्वरित उत्तर के लिए धन्यवाद। मैं nltk पैकेज का उपयोग कर रहा हूं, मुझे एक त्रुटि मिल रही है: 'फ़ाइल' /usr/local/lib/python3.5/dist-packages/nltk/__init__.py ", लाइन 115, <मॉड्यूल> में nltk.decorators पर आयात डेकोरेटर, मेमो फ़ाइल "/usr/local/lib/python3.5/dist-packages/nltk/decorators.py", पंक्ति 23, में <मॉड्यूल> sys.path = "p में sys.path पर" nltk "नहीं पी में" फ़ाइल "/usr/local/lib/python3.5/dist-packages/nltk/decorators.py", पंक्ति 23, में <listcomp> sys.path = [p से sys.path में यदि " nltk "p में नहीं] TypeError: 'PosixPath' प्रकार का तर्क चलने योग्य नहीं है
उपयोगकर्ता

1
आप फ़ाइल पथ द्वारा फ़ाइल आयात भी कर सकते हैं (सापेक्ष भी): docs.python.org/3/library/…
Ctrl-C

84

इसे अपने पैकेज की __init__.py फ़ाइल के अंदर रखें :

# For relative imports to work in Python 3.6
import os, sys; sys.path.append(os.path.dirname(os.path.realpath(__file__)))

अपने पैकेज को इस तरह से मान लें:

├── project
   ├── package
      ├── __init__.py
      ├── module1.py
      └── module2.py
   └── setup.py

अब आप पैकेज में नियमित आयात का उपयोग करें, जैसे:

# in module2.py
from module1 import class1

यह अजगर 2 और 3 दोनों में काम करता है।


अगर हम इसे
वेल

1
मुझे यह भी लगता है कि यह अधिक वोटों का हकदार है। इसे प्रत्येक में डालना __init__.pyमूल रूप से सभी सापेक्ष आयात त्रुटियों को हल करेगा।
फ्रैंकलीआओ

3
मैं दूसरों के लिए नहीं बोल सकता, लेकिन मैं संशोधित करने से बचता sys.pathहूं क्योंकि मैं चिंतित हूं कि यह अन्य कोड को प्रभावित कर सकता है। (आंशिक रूप से इस क्योंकि मैं यह कैसे काम करता की पेचीदगियों को पता नहीं है है।)
pianoJames

@pianoJames मुझे पता है कि आपका क्या मतलब है, यह (प्रतीत होता है, बहुत पेंच के बाद) जादू फिक्स थोड़ा आसान लगता है। लेकिन यह काम करता है। रुचि रखते हैं कि उन लोगों से नहीं पता होगा कि यह नकारात्मक दुष्प्रभाव है।
जॉन

मैं अब इसका उपयोग कर रहा हूं: और अब तक बहुत अच्छा।
जवदाबा

37

मैं इस मुद्दे में भाग गया। एक हैक वर्कअराउंड आयात कर रहा है जैसे कि / तो ब्लॉक इस प्रकार है:

#!/usr/bin/env python3
#myothermodule

if __name__ == '__main__':
    from mymodule import as_int
else:
    from .mymodule import as_int


# Exported function
def add(a, b):
    return as_int(a) + as_int(b)

# Test function for module  
def _test():
    assert add('1', '1') == 2

if __name__ == '__main__':
    _test()

29
यह बहुत अच्छा समाधान नहीं है। भी, नंगे except:बुरे है। except ImportError:इसके बजाय का उपयोग करें !
थिएस्टरमास्टर

6
यह SystemErrorयहाँ है। (Py 3.4)
Avi

8
यह एक भयानक विचार नहीं है, लेकिन यह पता लगाने के लिए बेहतर होगा कि कोशिश / छोड़कर के बजाय किस आयात का उपयोग करना है। कुछ इस तरह if __name__ == '__main__': from mymod import as_int; else: from .mymod import as_int
पर्किन्स

@ अच्छी तरह से ... ज्यादातर मामलों में यह नहीं होगा । मुझे लगता है कि रिश्तेदार आयात हालांकि अपवाद हो सकते हैं।
wizzwizz4

8

उम्मीद है, यह किसी के लिए मूल्य का होगा - मैं यहाँ से ऊपर पोस्ट किए गए समान के समान सापेक्ष आयात का पता लगाने की कोशिश कर रहे आधा दर्जन स्टैक्वेरफ़्लो पोस्ट से गुजरा। मैंने सुझाव के रूप में सब कुछ सेट किया लेकिन मैं अभी भी मार रहा थाModuleNotFoundError: No module named 'my_module_name'

चूँकि मैं सिर्फ स्थानीय रूप से विकसित हो रहा था और खेल रहा था, इसलिए मैंने एक setup.pyफ़ाइल नहीं बनाई थी । मैं भी जाहिरा तौर पर मेरे सेट नहीं था PYTHONPATH

मुझे एहसास हुआ कि जब मैं अपने कोड को चलाता था जैसा कि मैं था जब परीक्षण मॉड्यूल के समान निर्देशिका में थे, तो मुझे अपना मॉड्यूल नहीं मिला:

$ python3 test/my_module/module_test.py                                                                                                               2.4.0
Traceback (most recent call last):
  File "test/my_module/module_test.py", line 6, in <module>
    from my_module.module import *
ModuleNotFoundError: No module named 'my_module'

हालाँकि, जब मैंने स्पष्ट रूप से निर्दिष्ट किया कि पथ चीजें काम करने लगीं:

$ PYTHONPATH=. python3 test/my_module/module_test.py                                                                                                  2.4.0
...........
----------------------------------------------------------------------
Ran 11 tests in 0.001s

OK

इसलिए, इस घटना में कि किसी ने कुछ सुझाव देने की कोशिश की है, उनका मानना ​​है कि उनका कोड सही ढंग से संरचित है और अभी भी खुद को उसी तरह की स्थिति में पाता है जैसे कि आप निम्नलिखित में से किसी एक को भी आज़माते हैं यदि आप वर्तमान निर्देशिका को अपने PYTHONPATH में निर्यात नहीं करते हैं:

  1. अपना कोड चलाएँ और स्पष्ट रूप से पथ को शामिल करें: $ PYTHONPATH=. python3 test/my_module/module_test.py
  2. कॉल करने से बचने के लिए PYTHONPATH=., setup.pyनिम्न जैसी सामग्री के साथ एक फ़ाइल बनाएं और python setup.py developmentपैकेज को पथ में जोड़ने के लिए चलाएँ :
# setup.py
from setuptools import setup, find_packages

setup(
    name='sample',
    packages=find_packages()
)

6

मुझे इसे काम करने के लिए मुख्य परियोजना निर्देशिका से python3 चलाने की आवश्यकता थी।

उदाहरण के लिए, यदि परियोजना में निम्नलिखित संरचना है:

project_demo/
├── main.py
├── some_package/
   ├── __init__.py
   └── project_configs.py
└── test/
    └── test_project_configs.py

समाधान

मैं फ़ोल्डर project_demo / के अंदर python3 चलाऊंगा और फिर a

from some_package import project_configs

4

इस समस्या को दूर करने के लिए, मैंने रिपैकेज पैकेज के साथ एक समाधान तैयार किया , जिसने कुछ समय के लिए मेरे लिए काम किया। यह ऊपरी निर्देशिका को कार्य पथ में जोड़ता है:

import repackage
repackage.up()
from mypackage.mymodule import myfunction

एक बुद्धिमान रणनीति (कॉल स्टैक का निरीक्षण) का उपयोग करके, रिपैकेज सापेक्ष आयात कर सकता है जो मामलों की एक विस्तृत श्रृंखला में काम करता है।


अब तक का सबसे आसान उपाय! धन्यवाद!
CodingInCircles

1
धन्यवाद! सबसे अच्छा जवाब देने की कोशिश करने के बजाय, मैंने एक उपयोगी जवाब देने की कोशिश की :-)
fralau

3

यदि दोनों पैकेज आपके आयात पथ (sys.path) में हैं, और आपके द्वारा इच्छित मॉड्यूल / वर्ग उदाहरण / example.py में है, तो सापेक्ष आयात के बिना वर्ग का उपयोग करने का प्रयास करें:

from example.example import fkt

1

मुझे लगता है कि सबसे अच्छा समाधान अपने मॉड्यूल के लिए एक पैकेज बनाने के लिए है: यहाँ यह कैसे करना है के बारे में अधिक जानकारी है।

एक बार जब आपके पास एक पैकेज होता है तो आपको रिश्तेदार आयात के बारे में चिंता करने की आवश्यकता नहीं होती है, आप बस पूर्ण आयात कर सकते हैं।


0

मुझे एक समान समस्या थी: मुझे एक लिनक्स सेवा और सीजीआई प्लगइन की आवश्यकता थी जो सहयोग करने के लिए सामान्य स्थिरांक का उपयोग करते हैं। ऐसा करने का 'प्राकृतिक' तरीका उन्हें पैकेज के init .py में रखना है , लेकिन मैं -m पैरामीटर के साथ cgi प्लगइन शुरू नहीं कर सकता।

मेरा अंतिम समाधान उपरोक्त समाधान # 2 के समान था:

import sys
import pathlib as p
import importlib

pp = p.Path(sys.argv[0])
pack = pp.resolve().parent

pkg = importlib.import_module('__init__', package=str(pack))

नुकसान यह है कि आपको स्थिरांक (या सामान्य कार्यों) को pkg के साथ उपसर्ग करना होगा:

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