मैं हाल ही में कुछ ऐसा ही करने की कोशिश कर रहा हूं और मुझे ये जवाब मेरे उपयोग के मामलों (एक वितरित पुस्तकालय जिसे मूल रूट का पता लगाने की आवश्यकता है) के लिए अपर्याप्त पाया गया है। मुख्य रूप से मैं विभिन्न वातावरणों और प्लेटफार्मों से जूझ रहा हूं, और अभी भी कुछ पूरी तरह से सार्वभौमिक नहीं मिला है।
परियोजना के लिए स्थानीय कोड
मैंने इस उदाहरण का उल्लेख किया है और कुछ स्थानों, Django, आदि में उपयोग किया है।
import os
print(os.path.dirname(os.path.abspath(__file__)))
यह सरल है, यह केवल तभी काम करता है जब स्निपेट जिस फ़ाइल में है वह वास्तव में परियोजना का हिस्सा है। हम परियोजना निर्देशिका को पुनः प्राप्त नहीं करते हैं, बल्कि स्निपेट की निर्देशिका को छोड़ देते हैं
इसी तरह, sys.modules जब नीचे टूटता दृष्टिकोण बुलाया आवेदन की entrypoint बाहर से, विशेष रूप से मैं एक बच्चा धागे 'के संबंध वापस बिना इस निर्धारित नहीं कर सकता' पाया है मुख्य 'मॉड्यूल। मैंने स्पष्ट रूप से एक आयात को एक बच्चे के धागे से आयात प्रदर्शित करने के लिए एक फ़ंक्शन के अंदर रखा है, इसे शीर्ष स्तर पर ले जाकर app.py इसे ठीक कर देगा।
app/
|-- config
| `-- __init__.py
| `-- settings.py
`-- app.py
app.py
#!/usr/bin/env python
import threading
def background_setup():
# Explicitly importing this from the context of the child thread
from config import settings
print(settings.ROOT_DIR)
# Spawn a thread to background preparation tasks
t = threading.Thread(target=background_setup)
t.start()
# Do other things during initialization
t.join()
# Ready to take traffic
settings.py
import os
import sys
ROOT_DIR = None
def setup():
global ROOT_DIR
ROOT_DIR = os.path.dirname(sys.modules['__main__'].__file__)
# Do something slow
इस कार्यक्रम को चलाने से विशेषता त्रुटि उत्पन्न होती है:
>>> import main
>>> Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Python2714\lib\threading.py", line 801, in __bootstrap_inner
self.run()
File "C:\Python2714\lib\threading.py", line 754, in run
self.__target(*self.__args, **self.__kwargs)
File "main.py", line 6, in background_setup
from config import settings
File "config\settings.py", line 34, in <module>
ROOT_DIR = get_root()
File "config\settings.py", line 31, in get_root
return os.path.dirname(sys.modules['__main__'].__file__)
AttributeError: 'module' object has no attribute '__file__'
... इसलिए थ्रेडिंग आधारित समाधान
स्थान स्वतंत्र
पहले की तरह ही एप्लिकेशन संरचना का उपयोग करना लेकिन सेटिंग्स को संशोधित करना
import os
import sys
import inspect
import platform
import threading
ROOT_DIR = None
def setup():
main_id = None
for t in threading.enumerate():
if t.name == 'MainThread':
main_id = t.ident
break
if not main_id:
raise RuntimeError("Main thread exited before execution")
current_main_frame = sys._current_frames()[main_id]
base_frame = inspect.getouterframes(current_main_frame)[-1]
if platform.system() == 'Windows':
filename = base_frame.filename
else:
filename = base_frame[0].f_code.co_filename
global ROOT_DIR
ROOT_DIR = os.path.dirname(os.path.abspath(filename))
इसे तोड़ना: पहले हम मुख्य धागे की थ्रेड आईडी को सही ढंग से ढूंढना चाहते हैं। Python3.4 + में थ्रेडिंग लाइब्रेरी में threading.main_thread()हालांकि, हर कोई 3.4+ का उपयोग नहीं करता है, इसलिए हम सभी थ्रेड्स के माध्यम से खोज करते हैं जो मुख्य थ्रेड को ढूंढते हैं , यह आईडी है। यदि मुख्य धागा पहले ही निकल चुका है, तो इसे सूचीबद्ध नहीं किया जाएगा threading.enumerate()। हम RuntimeError()इस मामले में तब तक बढ़ाते हैं जब तक कि मुझे बेहतर समाधान नहीं मिल जाता।
main_id = None
for t in threading.enumerate():
if t.name == 'MainThread':
main_id = t.ident
break
if not main_id:
raise RuntimeError("Main thread exited before execution")
अगला हम मुख्य धागे का पहला स्टैक फ्रेम पाते हैं। CPython विशिष्ट फ़ंक्शन का उपयोग करके sys._current_frames() हमें हर थ्रेड के वर्तमान स्टैक फ्रेम का एक शब्दकोश मिलता है। तब inspect.getouterframes()हम मुख्य धागे और बहुत पहले फ्रेम के लिए पूरे स्टैक को पुनः प्राप्त कर सकते हैं। current_main_frame = sys._current_frames () [main_id] base_frame = inspect.getouterframes (current_main_frame) [- 1] अंत में, विंडोज और लिनक्स कार्यान्वयन के बीच के अंतर inspect.getouterframes()को संभालने की आवश्यकता है। साफ किए गए फ़ाइल नाम का उपयोग करना os.path.abspath()और os.path.dirname()चीजों को साफ करना।
if platform.system() == 'Windows':
filename = base_frame.filename
else:
filename = base_frame[0].f_code.co_filename
global ROOT_DIR
ROOT_DIR = os.path.dirname(os.path.abspath(filename))
अब तक मैंने इसे Python2.7 और 3.6 पर विंडोज के साथ-साथ WSL पर Python3.4 पर टेस्ट किया है
<ROOT>/__init__.pyमौजूद हैं?