سؤال

أريد اكتشاف ما إذا كانت الوحدة قد تغيرت.الآن، أصبح استخدام inotify أمرًا بسيطًا، كل ما عليك فعله هو معرفة الدليل الذي تريد الحصول على الإشعارات منه.

كيف يمكنني استرداد مسار الوحدة في بيثون؟

هل كانت مفيدة؟

المحلول

import a_module
print(a_module.__file__)

هل فعلا تعطيك المسار إلى ملف .pyc التي تم تحميلها، على الأقل على نظام التشغيل Mac OS X. لذا أعتقد يمكنك القيام به:

import os
path = os.path.dirname(a_module.__file__)

ويمكنك أيضا محاولة:

path = os.path.abspath(a_module.__file__)

لتحصل على دليل الوحدة النمطية.

نصائح أخرى

وهناك وحدة inspect في بيثون.

الوثائق الرسمية

<اقتباس فقرة>   

وتفقد وحدة يوفر العديد من الوظائف المفيدة للمساعدة في الحصول   معلومات حول الكائنات الحية مثل وحدات، والطبقات، والأساليب،   وظائف، tracebacks، والأشياء الإطار، والأشياء التعليمات البرمجية. فمثلا،   يمكن أن تساعدك على فحص محتويات الطبقة، استرجاع المصدر   مدونة طريقة، استخراج، وتحديد شكل قائمة وسيطة لوظيفة،   أو الحصول على كافة المعلومات التي تحتاجها لعرض traceback تفصيلا.

مثال:

>>> import os
>>> import inspect
>>> inspect.getfile(os)
'/usr/lib64/python2.7/os.pyc'
>>> inspect.getfile(inspect)
'/usr/lib64/python2.7/inspect.pyc'
>>> os.path.dirname(inspect.getfile(inspect))
'/usr/lib64/python2.7'

وكما قال وإجابات أخرى، فإن أفضل طريقة للقيام بذلك هي مع __file__ (أثبتت مرة أدناه). ومع ذلك، هناك تحذير هام، وهو أن __file__ غير موجود إذا كنت تقوم بتشغيل وحدة من تلقاء نفسه (أي كما __main__).

وعلى سبيل المثال، نقول لديك ملفين (وكلاهما على PYTHONPATH الخاص بك):

#/path1/foo.py
import bar
print(bar.__file__)

و

#/path2/bar.py
import os
print(os.getcwd())
print(__file__)

وسوف تشغيل foo.py إعطاء الإخراج:

/path1        # "import bar" causes the line "print(os.getcwd())" to run
/path2/bar.py # then "print(__file__)" runs
/path2/bar.py # then the import statement finishes and "print(bar.__file__)" runs

ولكن إذا حاولت تشغيل bar.py من تلقاء نفسها، وسوف تحصل على:

/path2                              # "print(os.getcwd())" still works fine
Traceback (most recent call last):  # but __file__ doesn't exist if bar.py is running as main
  File "/path2/bar.py", line 3, in <module>
    print(__file__)
NameError: name '__file__' is not defined 

ويساعد هذا الأمل. تكلف هذا التحذير لي الكثير من الوقت والارتباك أثناء اختبار حلول أخرى قدمت.

سأحاول معالجة بعض الاختلافات حول هذا السؤال أيضًا:

  1. العثور على مسار البرنامج النصي المسمى
  2. العثور على مسار البرنامج النصي الذي يتم تنفيذه حاليًا
  3. العثور على دليل البرنامج النصي المسمى

(تم طرح بعض هذه الأسئلة على SO، ولكن تم إغلاقها باعتبارها مكررة وإعادة توجيهها هنا.)

محاذير الاستخدام __file__

بالنسبة للوحدة النمطية التي قمت باستيرادها:

import something
something.__file__ 

سوف يعود مطلق مسار الوحدة.ومع ذلك، بالنظر إلى النص البرمجي التالي foo.py:

#foo.py
print '__file__', __file__

إن استدعائه باستخدام "python foo.py" سيرجع ببساطة "foo.py".إذا قمت بإضافة shebang:

#!/usr/bin/python 
#foo.py
print '__file__', __file__

واستدعائه باستخدام ./foo.py، سيعود "./foo.py".استدعائه من دليل مختلف (على سبيل المثال، ضع foo.py في شريط الدليل)، ثم اتصل بأي منهما

python bar/foo.py

أو إضافة shebang وتنفيذ الملف مباشرة:

bar/foo.py

سيعود "bar/foo.py" (ملف نسبي طريق).

العثور على الدليل

الآن نذهب من هناك للحصول على الدليل، os.path.dirname(__file__) يمكن أن تكون صعبة أيضًا.على الأقل على نظامي، يقوم بإرجاع سلسلة فارغة إذا قمت باستدعائها من نفس الدليل مثل الملف.السابق.

# foo.py
import os
print '__file__ is:', __file__
print 'os.path.dirname(__file__) is:', os.path.dirname(__file__)

سوف يخرج:

__file__ is: foo.py
os.path.dirname(__file__) is: 

بمعنى آخر، تقوم بإرجاع سلسلة فارغة، لذلك لا يبدو هذا موثوقًا إذا كنت تريد استخدامه للتيار ملف (على عكس ملف من وحدة مستوردة).للتغلب على هذا، يمكنك تغليفه باستدعاء لـ abspath:

# foo.py
import os
print 'os.path.abspath(__file__) is:', os.path.abspath(__file__)
print 'os.path.dirname(os.path.abspath(__file__)) is:', os.path.dirname(os.path.abspath(__file__))

الذي يخرج شيئا مثل:

os.path.abspath(__file__) is: /home/user/bar/foo.py
os.path.dirname(os.path.abspath(__file__)) is: /home/user/bar

لاحظ أن abspath() لا يحل الروابط الرمزية.إذا كنت تريد القيام بذلك، استخدم realpath() بدلاً من ذلك.على سبيل المثال، إنشاء رابط رمزي file_import_testing_link يشير إلى file_import_testing.py، بالمحتوى التالي:

import os
print 'abspath(__file__)',os.path.abspath(__file__)
print 'realpath(__file__)',os.path.realpath(__file__)

سيؤدي التنفيذ إلى طباعة المسارات المطلقة مثل:

abspath(__file__) /home/user/file_test_link
realpath(__file__) /home/user/file_test.py

file_import_testing_link -> file_import_testing.py

باستخدام فحص

يذكر @SummerBreeze استخدام فحص وحدة.

يبدو أن هذا يعمل بشكل جيد وموجز جدًا بالنسبة للوحدات النمطية المستوردة:

import os
import inspect
print 'inspect.getfile(os) is:', inspect.getfile(os)

يعود بطاعة المسار المطلق.ومع ذلك، بالنسبة للعثور على مسار البرنامج النصي الذي يتم تنفيذه حاليًا، لم أر طريقة لاستخدامه.

لا أفهم لماذا لا يتحدث أحد عن هذا، ولكن بالنسبة لي فإن الحل الأبسط هو الاستخدام imp.find_module("اسم الوحدة") (توثيق هنا):

import imp
imp.find_module("os")

يعطي صفًا مع المسار في الموضع الثاني:

(<open file '/usr/lib/python2.7/os.py', mode 'U' at 0x7f44528d7540>,
'/usr/lib/python2.7/os.py',
('.py', 'U', 1))

تتمثل ميزة هذه الطريقة على طريقة "الفحص" في أنك لا تحتاج إلى استيراد الوحدة لجعلها تعمل، ويمكنك استخدام سلسلة في الإدخال.مفيد عند التحقق من الوحدات النمطية التي يتم استدعاؤها في برنامج نصي آخر على سبيل المثال.

يحرر:

في بيثون3، importlib يجب أن تفعل الوحدة ما يلي:

وثيقة من importlib.util.find_spec:

قم بإرجاع المواصفات للوحدة المحددة.

أولاً، يتم فحص sys.modules لمعرفة ما إذا كانت الوحدة قد تم استيرادها بالفعل.إذا كان الأمر كذلك، إذن sys.modules[name].المواصفات يتم إرجاع.إذا حدث ذلك على أي شيء ، فسيتم رفع ValueRror.إذا لم تكن الوحدة في sys.modules ، فسيتم البحث في sys.meta_path عن مواصفات مناسبة مع قيمة "المسار" المقدمة إلى الباحثين.لم يتم إرجاع أي شيء إذا لم يتم العثور على مواصفات.

إذا كان الاسم للوحدة الفرعية (يحتوي على نقطة) ، يتم استيراد الوحدة الأصل تلقائيًا.

تعمل وسيطات الاسم والحزمة بنفس الطريقة التي تعمل بها importlib.import_module().بمعنى آخر، تعمل أسماء الوحدات النسبية (مع النقاط البادئة).

وكان هذا تافهة.

وكل وحدة لديها متغير __file__ التي تظهر مسار النسبي من حيث أنت الآن.

لذلك، والحصول على دليل لوحدة لإعلام أنها بسيطة على النحو التالي:

os.path.dirname(__file__)
import os
path = os.path.abspath(__file__)
dir_path = os.path.dirname(path)

سطر الأوامر المساعدة

ويمكنك قرص لأداة سطر الأوامر،

python-which <package name>


إنشاء /usr/local/bin/python-which

#!/usr/bin/env python

import importlib
import os
import sys

args = sys.argv[1:]
if len(args) > 0:
    module = importlib.import_module(args[0])
    print os.path.dirname(module.__file__)

وجعله قابل للتنفيذ

sudo chmod +x /usr/local/bin/python-which

وهكذا قضيت قدرا كبيرا من الوقت في محاولة للقيام بذلك مع py2exe وكانت مشكلة في الحصول على مجلد قاعدة النصي إذا كان يتم تشغيله كبرنامج نصي الثعبان أو قابل للتنفيذ py2exe. أيضا أن يكون ذلك العمل سواء كان يجري تشغيلها من المجلد الحالي، مجلد آخر أو (وهذا كان أصعب) من مسار النظام.

وأخيرا أنا استخدم هذا النهج، وذلك باستخدام sys.frozen كمؤشر على التوالي في py2exe:

import os,sys
if hasattr(sys,'frozen'): # only when running in py2exe this exists
    base = sys.prefix
else: # otherwise this is a regular python script
    base = os.path.dirname(os.path.realpath(__file__))
import module
print module.__path__
<اقتباس فقرة>   

وحزم دعم واحد أكثر سمة خاصة، __path__. هذا هو   تهيئة أن تكون قائمة تحتوي على اسم إجراء الدليل   يتم تنفيذ __init__.py حزمة قبل رمز في هذا الملف.   هذا المتغير يمكن تعديلها. ذلك يؤثر على عمليات البحث المستقبلية ل   وحدات والحزم الفرعية الواردة في الحزمة.

     

وحين لا تكون هناك حاجة هذه الميزة في كثير من الأحيان، يمكن أن تستخدم لتمديد   مجموعة من وحدات وجدت في مجموعة واحدة.

المصدر

ويمكنك فقط استيراد الوحدة النمطية الخاص بك ثم ضرب اسمها وستحصل على مساره الكامل

>>> import os
>>> os
<module 'os' from 'C:\\Users\\Hassan Ashraf\\AppData\\Local\\Programs\\Python\\Python36-32\\lib\\os.py'>
>>>

وإذا كان الشرط الوحيد لاستخدام __file__ هو عندما الحالية، والدليل النسبي فارغ (أي، عند تشغيل كبرنامج نصي من نفس الدليل حيث السيناريو هو)، ثم حل تافهة هو:

import os.path
mydir = os.path.dirname(__file__) or '.'
full  = os.path.abspath(mydir)
print __file__, mydir, full

والنتيجة:

$ python teste.py 
teste.py . /home/user/work/teste

والحيلة هي في or '.' بعد المكالمة dirname(). ويحدد دير كما .، وهو ما يعني <م> الدليل الحالي وهو دليل صالح لأي وظيفة ذات الصلة المسار.

وهكذا، وذلك باستخدام abspath() ليست هناك حاجة حقا. ولكن إذا كنت تستخدم على أي حال، ليست هناك حاجة خدعة: abspath() يقبل مسارات فارغة وصحيح يفسر على أنه الدليل الحالي

أرغب في المساهمة بسيناريو واحد شائع (في Python 3) واستكشاف بعض الطرق للتعامل معه.

الوظيفة المضمنة يفتح() يقبل إما المسار النسبي أو المطلق كوسيطة أولى.يتم التعامل مع المسار النسبي على أنه نسبة إلى دليل العمل الحالي على الرغم من ذلك فمن المستحسن تمرير المسار المطلق إلى الملف.

ببساطة، إذا قمت بتشغيل ملف نصي بالكود التالي، فهو كذلك لا يضمن أن example.txt سيتم إنشاء الملف في نفس الدليل الذي يوجد به ملف البرنامج النصي:

with open('example.txt', 'w'):
    pass

لإصلاح هذا الرمز، نحتاج إلى الحصول على المسار إلى البرنامج النصي وجعله مطلقًا.لضمان أن يكون المسار مطلقًا، نستخدم ببساطة ملف نظام التشغيل. المسار الحقيقي () وظيفة.للحصول على المسار إلى البرنامج النصي، هناك العديد من الوظائف الشائعة التي تُرجع نتائج مسار مختلفة:

  • os.getcwd()
  • os.path.realpath('example.txt')
  • sys.argv[0]
  • __file__

كلتا الوظيفتين نظام التشغيل.getcwd() و نظام التشغيل. المسار الحقيقي () نتائج مسار الإرجاع بناءً على دليل العمل الحالي.عموما ليس ما نريد.العنصر الأول من sys.argv القائمة هي مسار البرنامج النصي الجذر (البرنامج النصي الذي تقوم بتشغيله) بغض النظر عما إذا كنت تقوم باستدعاء القائمة في البرنامج النصي الجذر نفسه أو في أي من وحداته.قد يكون مفيدًا في بعض المواقف.ال __ملف__ يحتوي المتغير على مسار الوحدة التي تم استدعاؤه منها.


التعليمة البرمجية التالية بشكل صحيح بإنشاء ملف example.txt في نفس الدليل حيث يوجد البرنامج النصي:

filedir = os.path.dirname(os.path.realpath(__file__))
filepath = os.path.join(filedir, 'example.txt')

with open(filepath, 'w'):
    pass

ومن داخل وحدات من حزمة الثعبان كان لي أن أشير إلى الملف الذي أقام في نفس الدليل الحزمة. السابق.

some_dir/
  maincli.py
  top_package/
    __init__.py
    level_one_a/
      __init__.py
      my_lib_a.py
      level_two/
        __init__.py
        hello_world.py
    level_one_b/
      __init__.py
      my_lib_b.py

وحتى في أعلى اضطررت للاتصال maincli.py من وحدة my_lib_a.py مع العلم أن top_package وmaincli.py في نفس الدليل. وهنا كيف أحصل على طريق maincli.py:

import sys
import os
import imp


class ConfigurationException(Exception):
    pass


# inside of my_lib_a.py
def get_maincli_path():
    maincli_path = os.path.abspath(imp.find_module('maincli')[1])
    # top_package = __package__.split('.')[0]
    # mod = sys.modules.get(top_package)
    # modfile = mod.__file__
    # pkg_in_dir = os.path.dirname(os.path.dirname(os.path.abspath(modfile)))
    # maincli_path = os.path.join(pkg_in_dir, 'maincli.py')

    if not os.path.exists(maincli_path):
        err_msg = 'This script expects that "maincli.py" be installed to the '\
        'same directory: "{0}"'.format(maincli_path)
        raise ConfigurationException(err_msg)

    return maincli_path

واستنادا إلى نشر من قبل PlasmaBinturong I تعديل التعليمات البرمجية.

إذا كنت ترغب في القيام بذلك بشكل حيوي في "البرنامج" محاولة هذا الرمز:
ومن وجهة نظري، قد لا تعرف بالضبط اسم الوحدة النمطية إلى "ترميز ثابت" عليه. ويمكن اختيار من قائمة أو قد لا تكون قيد التشغيل حاليا لاستخدام __file __.

(وأنا أعلم، أنه لن ينجح في بيثون 3)

global modpath
modname = 'os' #This can be any module name on the fly
#Create a file called "modname.py"
f=open("modname.py","w")
f.write("import "+modname+"\n")
f.write("modpath = "+modname+"\n")
f.close()
#Call the file with execfile()
execfile('modname.py')
print modpath
<module 'os' from 'C:\Python27\lib\os.pyc'>

وحاولت التخلص من هذه القضية "العالمية" ولكن وجدت الحالات التي لم ينجح وأعتقد أن "execfile ()" يمكن أن يحتذى في بيثون 3 لأن هذا هو في البرنامج، فإنه يمكن بسهولة وضع في طريقة أو وحدة نمطية لإعادة استخدامها.

إذا كنت ترغب في معرفة المسار المطلق من البرنامج النصي الخاص بك يمكنك استخدامه طريق هدف:

from pathlib import Path

print(Path().absolute())
print(Path().resolve('.'))
print(Path().cwd())

طريقة سي دبليو دي ().

قم بإرجاع كائن مسار جديد يمثل الدليل الحالي (كما تم إرجاعه بواسطة os.getcwd())

طريقة الحل ().

اجعل المسار مطلقًا، وحل أي روابط رمزية.يتم إرجاع كائن مسار جديد:

إذا كنت ترغب في استرداد مسار الجذر حزمة من أي من وحداتها، ويعمل التالية (اختبار على بيثون 3.6):

from . import __path__ as ROOT_PATH
print(ROOT_PATH)

ويمكن أيضا أن يكون مرجعا المسار __init__.py الرئيسي باستخدام __file__ بدلا من ذلك.

وآمل أن يساعد هذا!

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top