पायथन: उप ‑ पैकेज या उप ‑ मॉड्यूल आयात करना


90

पहले से ही फ्लैट पैकेज का उपयोग करने के बाद, मैं नेस्टेड पैकेज के साथ सामना करने वाले मुद्दे की उम्मीद नहीं कर रहा था। यहाँ है…

निर्देशिका लेआउट

dir
 |
 +-- test.py
 |
 +-- package
      |
      +-- __init__.py
      |
      +-- subpackage
           |
           +-- __init__.py
           |
           +-- module.py

Init .py की सामग्री

दोनों package/__init__.pyऔर package/subpackage/__init__.pyखाली हैं।

की सामग्री module.py

# file `package/subpackage/module.py`
attribute1 = "value 1"
attribute2 = "value 2"
attribute3 = "value 3"
# and as many more as you want...

सामग्री test.py(3 संस्करण)

संस्करण 1

# file test.py
from package.subpackage.module import *
print attribute1 # OK

यह चीजों को आयात करने का बुरा और असुरक्षित तरीका है (सभी को थोक में आयात करें), लेकिन यह काम करता है।

संस्करण 2

# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
from module import attribute1

आइटम द्वारा आइटम आयात करने का एक सुरक्षित तरीका, लेकिन यह विफल रहता है, पायथन यह नहीं चाहता है: संदेश के साथ विफल रहता है: "मॉड्यूल के बिना कोई मॉड्यूल नहीं"। तथापि …

# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
print module # Surprise here

… कहता है <module 'package.subpackage.module' from '...'>। तो यह एक मॉड्यूल है, लेकिन यह एक मॉड्यूल / -P 8-O ... उह नहीं है

संस्करण 3

# file test.py v3
from package.subpackage.module import attribute1
print attribute1 # OK

यह काम करता है। तो आप या तो हर समय ओवरकिल उपसर्ग का उपयोग करने के लिए मजबूर होते हैं या असुरक्षित तरीके से संस्करण # 1 का उपयोग करते हैं और सुरक्षित आसान तरीका का उपयोग करने के लिए पायथन द्वारा अस्वीकृत कर दिया जाता है? बेहतर तरीका, जो सुरक्षित है और अनावश्यक लंबे उपसर्ग से बचता है, केवल वही है जिसे पायथन अस्वीकार करता है? क्या यह इसलिए है क्योंकि यह प्यार करता है import *या क्योंकि यह प्रीफिक्स से अधिक प्यार करता है (जो इस अभ्यास को लागू करने में मदद नहीं करता है)।

कठिन शब्दों के लिए क्षमा करें, लेकिन यह दो दिन है जब मैं इस मूर्खतापूर्ण व्यवहार के आसपास काम करने की कोशिश कर रहा हूं। जब तक मैं कहीं पूरी तरह से गलत नहीं था, यह मुझे एक एहसास के साथ छोड़ देगा कि पायथन के पैकेज और उप sub पैकेज के मॉडल में वास्तव में कुछ टूट गया है।

टिप्पणियाँ

  • मैं sys.pathवैश्विक दुष्प्रभावों से बचने के लिए, और न ही *.pthफाइलों पर भरोसा नहीं करना चाहता , जो एक sys.pathही वैश्विक पुतलों के साथ खेलने का एक और तरीका है । स्वच्छ होने के समाधान के लिए, यह केवल स्थानीय होना है। या तो पायथन उप-पैकेज को संभालने में सक्षम है, या तो यह नहीं है, लेकिन इसे स्थानीय सामान को संभालने में सक्षम होने के लिए वैश्विक कॉन्फ़िगरेशन के साथ खेलने की आवश्यकता नहीं होनी चाहिए।
  • मैंने भी आयात का उपयोग करने की कोशिश की package/subpackage/__init__.py, लेकिन यह कुछ भी हल नहीं किया, यह वही करता है, और शिकायत subpackageएक ज्ञात मॉड्यूल नहीं है, जबकि print subpackageयह एक मॉड्यूल (अजीब व्यवहार, फिर से) कहता है।

हो सकता है कि मैं पूरी तरह से गलत हूं (विकल्प मैं पसंद करूंगा), लेकिन इससे मुझे पायथन के बारे में बहुत निराशा हुई।

मैंने कोशिश की तीनों के पास कोई अन्य ज्ञात तरीका? कुछ मैं जिसके बारे में नहीं जानता?

(आह)

-----% <----- संपादित करें ----->% -----

अब तक का निष्कर्ष (लोगों की टिप्पणियों के बाद)

पायथन में वास्तविक उप ‑ पैकेज जैसा कुछ भी नहीं है, क्योंकि सभी पैकेज संदर्भ एक वैश्विक डिक्शनरी में जाते हैं, केवल, जिसका अर्थ है कि कोई स्थानीय शब्दकोष नहीं है, जिसका अर्थ है कि स्थानीय पैकेज संदर्भ को प्रबंधित करने का कोई तरीका नहीं है।

आपको या तो पूर्ण उपसर्ग या लघु उपसर्ग या उपनाम का उपयोग करना होगा। जैसे की:

पूर्ण उपसर्ग संस्करण

from package.subpackage.module import attribute1
# An repeat it again an again
# But after that, you can simply:
use_of (attribute1)

लघु उपसर्ग संस्करण (लेकिन दोहराया उपसर्ग)

from package.subpackage import module
# Short but then you have to do:
use_of (module.attribute1)
# and repeat the prefix at every use place

या फिर, उपरोक्त का एक रूपांतर।

from package.subpackage import module as m
use_of (m.attribute1)
# `m` is a shorter prefix, but you could as well
# define a more meaningful name after the context

फैक्टरेटेड संस्करण

यदि आप एक बैच में एक साथ कई इकाई आयात करने के बारे में बुरा नहीं मानते हैं, तो आप यह कर सकते हैं:

from package.subpackage.module import attribute1, attribute2
# and etc.

मेरे पहले पसंदीदा स्वाद में नहीं (मैं प्रति आयातित इकाई के लिए एक आयात विवरण रखना पसंद करता हूं), लेकिन हो सकता है कि मैं व्यक्तिगत रूप से एहसान करूं।

अपडेट (2012-09-14):

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

from package.subpackage.module import (

    attribute1, 
    attribute2,
    attribute3,
    ...)  # and etc.

जब आप "से आयात मॉड्यूल" को "/ package/subpackage/__init__.py" में लिखते हैं तो चीजें कैसे होती हैं?
मार्कस Unterwaditzer

आपका "फ़ैक्टराइज्ड वर्जन" आप जो करना चाहते हैं उसके लिए बिल्कुल सही लगता है। यदि आप विशेषता 1 और विशेषता 2 (जैसा कि आप "पसंद" करते हैं) के लिए एक अलग आयात लाइन करते हैं, तो आप जानबूझकर खुद को और अधिक काम दे रहे हैं। ऐसा करने का कोई कारण नहीं है।
ब्रेनबर्न

क्षमा करें, लेकिन मुझे वह नहीं मिलता जो आप चाहते हैं। क्या आप अपने प्रश्न को अधिक स्पष्ट तरीके से दोहरा सकते हैं? आप वास्तव में क्या करना चाहेंगे? मेरा मतलब है, आप क्या लिखना पसंद करेंगे जो काम नहीं करता है और आप इसे कैसे काम करने की उम्मीद करेंगे? मैंने जो पढ़ा है उससे मुझे लगता है कि जावा या शायद सी के शामिल होने के लिए आयात के शब्दार्थ क्या हैं। अंतिम बात: आप एक मॉड्यूल "स्टार-इम्पोर्ट" को एक __all__वैरिएबल जोड़कर सुरक्षित बना सकते हैं जिसमें उन नामों की एक सूची शामिल है जिन्हें स्टार-इम्पोर्ट होने पर निर्यात किया जाना चाहिए। संपादित करें: ठीक है, ब्रेनबर्न का जवाब पढ़ना मुझे समझ में आया कि आपका क्या मतलब है।
बाकूउ

जवाबों:


68

आप गलत समझ रहे हैं कि importमॉड्यूल की खोज कैसे होती है । जब आप एक आयात विवरण का उपयोग करते हैं तो यह हमेशा वास्तविक मॉड्यूल पथ (और / या sys.modules) की खोज करता है; यह स्थानीय नाम स्थान में मॉड्यूल ऑब्जेक्ट्स का उपयोग नहीं करता है जो पिछले आयातों के कारण मौजूद हैं। जब तुम करोगे:

import package.subpackage.module
from package.subpackage import module
from module import attribute1

दूसरी पंक्ति नामक पैकेज की तलाश package.subpackageकरता है moduleऔर उस पैकेज से आयात करता है। तीसरी लाइन पर इस लाइन का कोई प्रभाव नहीं है। तीसरी लाइन बस एक मॉड्यूल की तलाश में है जिसे एक कहा जाता है moduleऔर एक नहीं मिलता है। यह उस ऑब्जेक्ट को "री-यूज" नहीं करता है जिसे moduleआपने ऊपर लाइन से प्राप्त किया है।

दूसरे शब्दों में from someModule import ...इसका मतलब यह नहीं है कि "मॉड्यूल से कुछ कहा जाता है जिसे मैंने पहले आयात किया था ..." इसका अर्थ है "कुछ मॉड्यूल नाम के मॉड्यूल से जिसे आप sys.path पर पाते हैं ..."। "वृद्धिशील रूप से" कोई रास्ता नहीं है जिससे पैकेज को आयात करने के लिए मॉड्यूल का मार्ग तैयार किया जा सके। आयात करते समय आपको हमेशा पूरे मॉड्यूल नाम का उल्लेख करना होगा।

यह स्पष्ट नहीं है कि आप क्या हासिल करने की कोशिश कर रहे हैं। यदि आप केवल विशेष Object1 विशेषता को आयात करना चाहते हैं, तो बस इसे करें from package.subpackage.module import attribute1और इसके साथ रहें। package.subpackage.moduleजब आप उस नाम से आयात करना चाहते हैं, तो आपको कभी भी इस बारे में चिंता करने की आवश्यकता नहीं है।

यदि आप बाद में अन्य नामों को एक्सेस करने के लिए मॉड्यूल तक पहुँच प्राप्त करना चाहते हैं, तो आप कर सकते हैं from package.subpackage import moduleऔर जैसा कि आपने देखा है कि आप तब कर सकते हैं module.attribute1और जैसे ही आप चाहें।

यदि आप दोनों चाहते हैं --- अर्थात, यदि आप attribute1सीधे पहुंच चाहते हैं और आप moduleसुलभ चाहते हैं , तो बस उपरोक्त दोनों करें:

from package.subpackage import module
from package.subpackage.module import attribute1
attribute1 # works
module.someOtherAttribute # also works

यदि आप package.subpackageदो बार भी लिखना पसंद नहीं करते हैं , तो आप केवल विशेष रूप से एक स्थानीय संदर्भ बना सकते हैं:

from package.subpackage import module
attribute1 = module.attribute1
attribute1 # works
module.someOtherAttribute #also works

आपकी टिप्पणी उसी दिशा में जाती है जैसे कि इग्नासियो वाज़केज़-अब्राम्स (मैंने उनके संदेश पर टिप्पणी की है)। आप अंत में इसके अलावा, का उपयोग करने के बारे module.attribute1में कुछ है जो मैं के बारे में है, लेकिन मैं हालांकि हर जगह एक उपसर्ग की आवश्यकता से बचने का एक तरीका होगा। इसलिए मुझे या तो हर उपसर्ग का उपयोग करना होगा, या नाम को दोहराते हुए एक स्थानीय उपनाम बनाना होगा। वह शैली नहीं, जिसकी मैं उम्मीद कर रहा था, लेकिन अगर कोई रास्ता नहीं है (आखिरकार, मैं आद्या के लिए उपयोग किया जाता हूं, जिसे इसके नाम बदलने की घोषणाओं के साथ कुछ इसी तरह की आवश्यकता होती है)।
हिबू

@ Hibou57: यह अभी भी मेरे लिए स्पष्ट नहीं है कि आप अपने "संस्करण 2" में क्या हासिल करना चाहते हैं। आप क्या करना चाहते हैं जो संभव नहीं है? आप पैकेज / मॉड्यूल / विशेषता नाम के किसी भी भाग को कभी भी लिखना नहीं चाहते हैं, लेकिन फिर भी मॉड्यूल और इसकी विशेषता दोनों को आयात करते हैं?
ब्रेनबर्न

मैं एक स्थानीय पैकेज संदर्भ रखना चाहता था, ठीक उसी तरह जिस तरह आप एक स्थानीय वस्तु संदर्भ रख सकते हैं। लगता है अंत में वास्तव में स्थानीय मॉड्यूल संदर्भ हैं, लेकिन आप इन से आयात नहीं कर सकते। यह एक मजेदार स्वाद के साथ स्थानीय और वैश्विक का मिश्रण है (कुछ सामान स्थानीय हो सकते हैं, कुछ अन्य वैश्विक होने चाहिए, मुझे यह पसंद नहीं है, लेकिन मैं ठीक हूं जब तक मैं अब बेहतर तरीके से समझता हूं कि यह कैसे काम करता है)। वैसे आपके संदेश के लिए धन्यवाद।
हिबू

1
मुझे यकीन नहीं है कि आप अभी भी समझते हैं कि यह कैसे काम करता है। या कि आपने किसी भी मामले में 2012 में किया था।
हज्जाजमन

1
जब भी मैं 6 महीने की छंटनी के बाद पाइथन में वापस आता हूं, मैं यहां समाप्त होता हूं। यदि केवल मैं इस पृष्ठ पर जाने के लिए हर बार उत्थान कर सकता हूं! मैं इस वाक्य के साथ एक विशाल पोस्टर बनाने जा रहा हूं: "पैकेज को आयात करने वाले मॉड्यूल के पथ का निर्माण करने के लिए" वृद्धिशील रूप से "कोई रास्ता नहीं है।"
पैट्रिक

10

कारण # 2 विफल रहता है क्योंकि sys.modules['module']मौजूद नहीं है (आयात दिनचर्या का अपना दायरा है, और moduleस्थानीय नाम नहीं देख सकता है ), और moduleडिस्क पर कोई मॉड्यूल या पैकेज नहीं है । ध्यान दें कि आप कई आयातित नामों को कॉमा से अलग कर सकते हैं।

from package.subpackage.module import attribute1, attribute2, attribute3

इसके अलावा:

from package.subpackage import module
print module.attribute1

आपका संदर्भ sys.modules['name']जिसके बारे में मुझे अब तक पता नहीं था, मुझे लगता है कि मुझे डर था (और ब्रेनबार पुष्टि करता है): पायथन में असली उप nothing पैकेज जैसा कुछ नहीं है। sys.modules, जैसा कि इसके नाम से पता चलता है, वैश्विक है, और यदि मॉड्यूल के सभी संदर्भ इस पर भरोसा करते हैं, तो एक मॉड्यूल के स्थानीय संदर्भ जैसा कुछ नहीं है (पायथन 3.x के साथ आने के लिए हो सकता है?)।
हिबोउ57

"संदर्भ" का आपका उपयोग अस्पष्ट है; import# 2 में पहले से package.subpackage.moduleबाध्य एक स्थानीय संदर्भ उत्पन्न करता है module
इग्नासियो वाज़क्वेज़-अब्राम्स

हां, लेकिन यह एक "मॉड्यूल" है, जिससे मैं आयात नहीं कर सकता; ;-)
Hibou57

0

यदि आप सभी करने की कोशिश कर रहे हैं, तो अपने वैश्विक नामस्थान में विशेषता 1 प्राप्त करें, संस्करण 3 बस ठीक लगता है। यह उपसर्ग उपसर्ग क्यों है?

इसके बजाय संस्करण 2 में

from module import attribute1

तुम कर सकते हो

attribute1 = module.attribute1

attribute1 = module.attribute1केवल बिना किसी अतिरिक्त मूल्य के नाम को दोहरा रहा है। मुझे पता है कि यह काम करता है, लेकिन मुझे यह शैली पसंद नहीं है (जिसका मतलब यह नहीं है कि मुझे आपका जवाब पसंद नहीं है)।
Hibou57

2
मुझे लगता है कि मैं, जैसे सभी लोग यहाँ टिप्पणी कर रहे हैं, समझ में नहीं आ रहा है कि आप क्या करना चाहते हैं। आपके द्वारा दिए गए सभी उदाहरणों में, ऐसा लगता है कि आप अपने नामस्थान में एक सबपैक से प्रतीक के साथ समाप्त करना चाहते हैं। आपका गैर-काम करने वाला उदाहरण (उदाहरण 2) एक पैकेज से सबमॉडल आयात करके, और फिर उस सबमॉडल से एक प्रतीक आयात करके करना चाहता है। मुझे नहीं पता कि आप इसे एक के बजाय दो चरणों में क्यों करना चाहते हैं। हो सकता है कि अधिक बताएं कि आपका आदर्श समाधान क्या होगा और क्यों।
थॉमस वेंडर स्टिचले
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.