পাইথনের আপেক্ষিক পাথ


245

আমি কাজের জন্য একটি সহজ সহায়ক স্ক্রিপ্ট তৈরি করছি যা আমাদের কোড বেসে বেশ কয়েকটি টেমপ্লেট ফাইলকে বর্তমান ডিরেক্টরিতে অনুলিপি করবে। টেমপ্লেটগুলি যেখানে সঞ্চিত আছে সেখানে আমার কাছে সম্পূর্ণ পথ নেই। আমার স্ক্রিপ্ট থেকে একটি আপেক্ষিক পাথ আছে তবে আমি যখন স্ক্রিপ্টটি কল করি তখন এটি বর্তমান ওয়ার্কিং ডিরেক্টরিের সাথে সম্পর্কিত হিসাবে পথ হিসাবে বিবেচনা করে। এই আপেক্ষিক url এর পরিবর্তে স্ক্রিপ্টের অবস্থান থেকে নির্দিষ্ট করার কোনও উপায় আছে কি?


উত্তর:


324

স্ক্রিপ্ট থাকা ফাইলটিতে আপনি এরকম কিছু করতে চান:

import os
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

এটি আপনাকে যে ফাইলটি সন্ধান করছে তার নিখুঁত পথ দেবে। মনে রাখবেন যে আপনি যদি সেটআপলগুলি ব্যবহার করছেন তবে আপনার পরিবর্তে সম্ভবত এর প্যাকেজ সংস্থানগুলি API ব্যবহার করা উচিত ।

আপডেট : আমি এখানে একটি মন্তব্যে সাড়া দিচ্ছি যাতে আমি একটি কোডের নমুনা পেস্ট করতে পারি। :-)

আমি কি এই ভেবে সঠিক হয়েছি যে __file__সবসময় পাওয়া যায় না (যেমন আপনি যখন ফাইলটি আমদানির পরিবর্তে সরাসরি চালাবেন)?

আমি ধরে নিচ্ছি __main__যখন আপনি সরাসরি ফাইলটি চালনার উল্লেখ করবেন তখন আপনি স্ক্রিপ্টটি বোঝাচ্ছেন । যদি তা হয় তবে তা আমার সিস্টেমে দেখা যাচ্ছে না (ওএস এক্স 10.5.7-তে অজগর 2.5.1):

#foo.py
import os
print os.getcwd()
print __file__

#in the interactive interpreter
>>> import foo
/Users/jason
foo.py

#and finally, at the shell:
~ % python foo.py
/Users/jason
foo.py

তবে, আমি জানি যে __file__সি এক্সটেনশনে কিছু গণ্ডগোল রয়েছে । উদাহরণস্বরূপ, আমি আমার ম্যাকটিতে এটি করতে পারি:

>>> import collections #note that collections is a C extension in Python 2.5
>>> collections.__file__
'/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-
dynload/collections.so'

যাইহোক, এটি আমার উইন্ডোজ মেশিনে একটি ব্যতিক্রম উত্থাপন করে।


1
আমি কি এই ভেবে সঠিক হয়েছি যে ফাইলটি সবসময় পাওয়া যায় না (যেমন আপনি যখন ফাইলটি আমদানির পরিবর্তে সরাসরি চালাবেন)?
স্টিফেন এডমন্ডস

@ স্টেফেন এডমন্ডস আমি এটিকে আমদানির পরিবর্তে চালিত একটি ফাইল ব্যবহার করছি এবং এটি দুর্দান্ত কাজ করে।
বাডট্যাক

22
দ্রষ্টব্য আপনার বহনযোগ্যতার জন্য সর্বত্র os.path.join ব্যবহার করা উচিত:filename = os.path.join(dir, 'relative', 'path', 'to', 'file', 'you' , 'want')
ফোরড করুন

22
os.path.dirname(__file__)একটি খালি স্ট্রিং দিতে পারে, os.path.dirname(os.path.abspath(__file__))পরিবর্তে ব্যবহার করুন
দিমিত্রি ট্রফিমভ

14
এটি একটি ছোটখাটো জিনিস, তবে দয়া করে দিরটি ভেরিয়েবলের নাম হিসাবে ব্যবহার করবেন না কারণ এটি বিল্টইন।
ডেভিড

63

আপনার প্রয়োজন os.path.realpath(নীচের নমুনা আপনার পথে অভিভাবক ডিরেক্টরি যুক্ত করে)

import sys,os
sys.path.append(os.path.realpath('..'))

2
os.path.dirname(__file__)আমাকে একটি খালি স্ট্রিং দিয়েছে। এটি পুরোপুরি কাজ করে।
দারাগ এনরাট

3
এটি স্ক্রিপ্টের স্ক্রিপ্টটি চালিত ডিরেক্টরিটির পিতামাতাকে দেবে বলে মনে হচ্ছে, স্ক্রিপ্টের অবস্থান নয়।
কোকিলোকট

10
os.path.realpath('..')আপনাকে বর্তমান চলমান দির পিতামতীয় ডিরেক্টরি দেয় । এটি সাধারণত আপনি যা চান তা নয়
মার্টিজন পিটারস

1
@ দারাঘেনারাইট: এটি কেবল পাইথন-স্ক্রিপ্ট-থেকে-এক্সি প্যাকেজিং পরিবেশে ঘটে। এটি বিরল ব্যতিক্রমগুলির মধ্যে একটি যেখানে বর্তমান ওয়ার্কিং ডিয়ারের উপর নির্ভর করা বিকল্প হবে।
মার্টিজন পিটারস

52

হিসাবে গৃহীত উত্তরে উল্লিখিত

import os
dir = os.path.dirname(__file__)
filename = os.path.join(dir, '/relative/path/to/file/you/want')

আমি কেবল এটি যুক্ত করতে চাই

পরবর্তী স্ট্রিং ব্যাকস্ল্যাশ দিয়ে শুরু করতে পারে না, আসলে কোনও স্ট্রিংয়ে ব্যাকস্ল্যাশ অন্তর্ভুক্ত করা উচিত

এটির মতো কিছু হওয়া উচিত

import os
dir = os.path.dirname(__file__)
filename = os.path.join(dir, 'relative','path','to','file','you','want')

গৃহীত উত্তরটি কিছু ক্ষেত্রে বিভ্রান্তিমূলক হতে পারে, বিশদের জন্য দয়া করে এই লিঙ্কটি দেখুন


4
হ্যাঁ ব্যবহার os.path.joinকরা আরও ভাল কারণ এটি ওএস-নির্দিষ্ট বিভাজকের সাথে তাদের সাথে যোগ দেয়।
ফারশিদ টি

'/relative/path...'আপেক্ষিক পথ নয়। এটা কি ইচ্ছাকৃত?
স্টিভায়ার

এই উত্তরটি এখন পুরানো যেমন শীর্ষ উত্তরে একটি সঠিক আপেক্ষিক পথ ব্যবহার করতে সম্পাদনা করা হয়েছে হয় os.path.join()। যা বাকি আছে তা হল পাথ বিভাজককে হার্ডকোডিংয়ের জন্য প্রতিটি পাথ উপাদানগুলির জন্য পৃথক স্ট্রিং ব্যবহার করার পছন্দ।
মার্টিজন পিটারস

@ মার্তিজ্নপিটারস হ্যাঁ, শীর্ষটির উত্তরটি অংশে এটি মিলিয়ে সম্পাদনা করা হয়েছে, তবে পৃথক স্ট্রিংগুলি পছন্দ নয় - এরকম স্টিংগুলিকে পৃথক করা একে স্বতন্ত্র করে তোলে।
jshrimp29

26

এটি এখন 2018, এবং পাইথন ইতিমধ্যে __future__দীর্ঘ সময় আগে বিকশিত হয়েছে । সুতরাং কিভাবে আশ্চর্যজনক ব্যবহার সম্পর্কে pathlibপাইথন 3.4 নিয়ে আসছে টাস্ক সম্পন্ন করার জন্য পরিবর্তে সঙ্গে সংগ্রাম os, os.path, glob, shutil, ইত্যাদি

সুতরাং আমাদের এখানে 3 টি পথ রয়েছে (সম্ভবত নকল):

  • mod_path: যা সাধারণ সহায়ক স্ক্রিপ্টের পথ
  • src_path: এতে অনুলিপি করার জন্য অপেক্ষা করা বেশ কয়েকটি টেম্পলেট ফাইল রয়েছে ।
  • cwd: বর্তমান ডিরেক্টরি , template টেমপ্লেট ফাইলগুলির গন্তব্য।

এবং সমস্যা হল: আমরা না সম্পূর্ণ পাথ src_path, শুধু জানি এটা আপেক্ষিক পাথ করতে mod_path

এখন এটি আশ্চর্যজনক দিয়ে সমাধান করুন pathlib:

# Hope you don't be imprisoned by legacy Python code :)
from pathlib import Path

# `cwd`: current directory is straightforward
cwd = Path.cwd()

# `mod_path`: According to the accepted answer and combine with future power
# if we are in the `helper_script.py`
mod_path = Path(__file__).parent
# OR if we are `import helper_script`
mod_path = Path(helper_script.__file__).parent

# `src_path`: with the future power, it's just so straightforward
relative_path_1 = 'same/parent/with/helper/script/'
relative_path_2 = '../../or/any/level/up/'
src_path_1 = (mod_path / relative_path_1).resolve()
src_path_2 = (mod_path / relative_path_2).resolve()

ভবিষ্যতে, এটি কেবল এটি সহজ। : ডি


তদুপরি, আমরা এই টেম্পলেট ফাইলগুলি নির্বাচন করে চেক এবং কপি / মুভি করতে পারি pathlib:

if src_path != cwd:
    # When we have different types of files in the `src_path`
    for template_path in src_path.glob('*.ini'):
        fname = template_path.name
        target = cwd / fname
        if not target.exists():
            # This is the COPY action
            with target.open(mode='wb') as fd:
                fd.write(template_path.read_bytes())
            # If we want MOVE action, we could use:
            # template_path.replace(target)

14

আমার কোড বিবেচনা করুন:

import os


def readFile(filename):
    filehandle = open(filename)
    print filehandle.read()
    filehandle.close()



fileDir = os.path.dirname(os.path.realpath('__file__'))
print fileDir

#For accessing the file in the same folder
filename = "same.txt"
readFile(filename)

#For accessing the file in a folder contained in the current folder
filename = os.path.join(fileDir, 'Folder1.1/same.txt')
readFile(filename)

#For accessing the file in the parent folder of the current folder
filename = os.path.join(fileDir, '../same.txt')
readFile(filename)

#For accessing the file inside a sibling folder.
filename = os.path.join(fileDir, '../Folder2/same.txt')
filename = os.path.abspath(os.path.realpath(filename))
print filename
readFile(filename)

আমি যখন এটি উইন্ডোতে চালিত করি, তখন আমি একটি ত্রুটি পেয়েছি: ফাইলনটফাউন্ডআরার: [এর্নো 2] এরকম কোনও ফাইল বা ডিরেক্টরি নেই: '<path>' যেখানে <path> এর সঠিক পথ বিভাগ রয়েছে তবে বিভাজকগুলির জন্য uses ব্যবহার করে।
দীর্ঘতম

11

প্রোগ্রামের সূচনার সাথে সাথে sys.path দেখুন , এই তালিকার প্রথম আইটেম, পথ [0], হ'ল ডিরেক্টরিটি পাইথন ইন্টারপ্রেটারকে অনুরোধ করার জন্য ব্যবহৃত স্ক্রিপ্টটি।

এই পাথটিকে মূল ফোল্ডার হিসাবে ব্যবহার করুন যা থেকে আপনি আপনার আপেক্ষিক পাথটি প্রয়োগ করেন

>>> import sys
>>> import os.path
>>> sys.path[0]
'C:\\Python25\\Lib\\idlelib'
>>> os.path.relpath(sys.path[0], "path_to_libs") # if you have python 2.6
>>> os.path.join(sys.path[0], "path_to_libs")
'C:\\Python25\\Lib\\idlelib\\path_to_libs'

3
এটি অগত্যা সত্য নয়। সাধারণত sys.path [0] হ'ল খালি স্ট্রিং বা বিন্দু, যা বর্তমান ডিরেক্টরিতে আপেক্ষিক পথ। আপনি যদি বর্তমান ডিরেক্টরিটি চান তবে os.getcwd ব্যবহার করুন।
জেসন বেকার

আসল পোস্টারটি মন্তব্য করেছিল যে বর্তমানের কাজ করা ডিরেক্টরিটি আপেক্ষিক পথে ভিত্তি করার ভুল জায়গা। আপনি sys.path [0] সর্বদা বৈধ নয় বলে এই কথাটি সঠিক।
টম লেস

না, sys.path[0]সবসময় পিতামাতার ডিরেক্টরিতে সেট করা হয় না। পাইথন কোডটি এম্বেডড ইন্টারপ্রেটারের সাহায্যে -cবা এর -mমাধ্যমে চালু করা যেতে পারে , যেখানে বিন্দুতে sys.path[0]সম্পূর্ণ আলাদা কিছুতে সেট করা থাকে।
মার্টিজন পিটারস

6

পরিবর্তে ব্যবহার

import os
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

গৃহীত উত্তরের মতো এটি ব্যবহার করা আরও দৃust় হবে:

import inspect
import os
dirname = os.path.dirname(os.path.abspath(inspect.stack()[0][1]))
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

কারণ __file__ ব্যবহার করে মডিউলটি লোড হওয়া ফাইলটি ফিরে আসবে, যদি এটি কোনও ফাইল থেকে লোড করা হয়, সুতরাং স্ক্রিপ্টের সাথে ফাইলটি অন্য কোথাও থেকে ডেকে আনা হলে ডিরেক্টরিটি সঠিক হবে না।

এই উত্তরগুলি আরও বিশদ দেয়: https://stackoverflow.com/a/31867043/5542253 এবং https://stackoverflow.com/a/50502/5542253


5
inspect.stack()কল করার জন্য একটি ব্যয়বহুল ফাংশন। এটি সমস্ত স্ট্যাক ফ্রেমগুলির জন্য তথ্য পুনরুদ্ধার করে, যা আপনি পরে তা বাতিল এবং কেবল শীর্ষের জন্য পান। এটি মূলত inspect.getfile()মডিউল অবজেক্টে কল করে, যা কেবল ফিরে আসে module.__file__। আপনি কেবল ব্যবহার করা থেকে অনেক ভাল __file__
মার্টিজন পিটারস

4

হাই আপনার প্রথমে os.path.abspath (পাথ) এবং os.path.relpath (পথ) ফাংশন বুঝতে হবে

সংক্ষেপে os.path.abspath (পাথ) পরম পাথের জন্য একটি আপেক্ষিক পথ তৈরি করে । এবং প্রদত্ত পথটি যদি নিজেই একটি পরম পথ হয় তবে ফাংশনটি একই পথে ফিরে আসে।

একইভাবে os.path.relpath (পথ) আপেক্ষিক পথের জন্য একটি পরম পথ তৈরি করে । এবং প্রদত্ত পথটি যদি নিজেই আপেক্ষিক পথ হয় তবে ফাংশনটি একই পথে ফিরে আসে।

নীচে উদাহরণস্বরূপ আপনি উপরের ধারণাটি সঠিকভাবে বুঝতে পারবেন :

ধরুন আমার কাছে একটি ফাইল ইনপুট_ফিল_লিস্ট.টিএসটি আছে যাতে আমার পাইথন স্ক্রিপ্টটি প্রক্রিয়া করার জন্য ইনপুট ফাইলগুলির তালিকা রয়েছে।

ডি: \ conc \ input1.dic

ডি: \ conc \ input2.dic

ডি: \ Copyioconc \ input_file_list.txt

আপনার কাছে এই ফোল্ডারে কাঠামো উপরে দেখতে পান, তাহলে input_file_list.txt উপস্থিত Copyofconc পাইথন স্ক্রিপ্ট দ্বারা প্রক্রিয়াভুক্ত করা ফোল্ডার এবং ফাইলে উপস্থিত conc ফোল্ডারের

তবে ইনপুট_ফিল_লিস্ট.টেক্সট ফাইলের বিষয়বস্তু নীচে দেখানো হয়েছে:

.. \ conc \ input1.dic

.. \ conc \ input2.dic

এবং আমার অজগর স্ক্রিপ্টটি ডি: ড্রাইভে উপস্থিত রয়েছে ।

এবং ইনপুট_ফাইলে_লিস্ট.টিএসটিএক্স ফাইলটিতে প্রদত্ত আপেক্ষিক পাথ ইনপুট_ফিল_লিস্ট.টেক্সটের পাথের সাথে আপেক্ষিক ফাইলের সাথে সম্পর্কিত।

সুতরাং যখন পাইথন স্ক্রিপ্টটি বর্তমান কার্য সম্পাদনকারী ডিরেক্টরিটি কার্যকর করবে ( os.getcwd ( ব্যবহার করুন ) পাথ পেতে )

আমার আপেক্ষিক পথটি ইনপুট_ফিল_লিস্ট.টেক্সটের সাথে সম্পর্কিত হিসাবে , এটি "ডি: \ কপিওফকনক" , তাই আমাকে বর্তমান কার্য ডিরেক্টরিটি "ডি: \ কপিফোনক" এ পরিবর্তন করতে হবে

সুতরাং আমাকে os.chdir ('D: \ copyofconc') ব্যবহার করতে হবে , সুতরাং বর্তমানের চলমান ডিরেক্টরিটি "ডি: \ কপিওফোনক" হবে

ইনপুট 1.ডিক এবং ইনপুট 2.ডিক ফাইলগুলি পেতে , আমি ".. \ কনক \ ইনপুট 1.dic" লাইনগুলি পড়ব তারপর কমান্ডটি ব্যবহার করবে

ইনপুট 1_পাথ = os.path.abspath ('.. \ conc \ ইনপুট 1.dic') (পরম পাথের তুলনামূলক পাথ পরিবর্তন করতে Here এখানে বর্তমান কার্য ডিরেক্টরি হিসাবে "ডি: \ কপিফোনক" ফাইলটি রয়েছে। "কনক \ ইনপুট 1"। dic "" D: \ copyofconc "এর তুলনায় অ্যাক্সেস করা হবে)

সুতরাং ইনপুট 1_পথটি "ডি: \ কনক \ ইনপুট 1.ডিক" হবে


4

এই কোডটি মূল স্ক্রিপ্টে পরম পাথ ফিরে আসবে।

import os
def whereAmI():
    return os.path.dirname(os.path.realpath(__import__("__main__").__file__))

এটি একটি মডিউল এমনকি কাজ করবে।


পুনরায় আমদানির পরিবর্তে, আপনি ব্যবহার করবেন sys.modules['__main__'].__file__
মার্টিজন পিটারস

3

একটি বিকল্প যা আমার পক্ষে কাজ করে:

this_dir = os.path.dirname(__file__) 
filename = os.path.realpath("{0}/relative/file.path".format(this_dir))

0

আমার জন্য যা কাজ করেছে তা ব্যবহার করছে sys.path.insert। তারপরে আমি যাবার জন্য প্রয়োজনীয় ডিরেক্টরিটি নির্দিষ্ট করেছিলাম। উদাহরণস্বরূপ, আমার কেবল একটি ডিরেক্টরি যেতে হবে।

import sys
sys.path.insert(0, '../')

1
এটি বর্তমান কার্যনির্বাহী ডিরেক্টরিতে নির্ভর করে যা আপনি যা চান তা থেকে একেবারে আলাদা হতে পারে।
মার্টিজন পিটারস

-2

আমি এটি পুরানো সংস্করণগুলির কয়েকটিতে প্রযোজ্য কিনা তা নিশ্চিত নই, তবে আমি বিশ্বাস করি পাইথন ৩.৩-এর স্থানীয় আপেক্ষিক পথ সমর্থন রয়েছে।

উদাহরণস্বরূপ, নীচের কোডটি পাইথন স্ক্রিপ্টের মতো একই ফোল্ডারে একটি পাঠ্য ফাইল তৈরি করা উচিত:

open("text_file_name.txt", "w+t")

(মনে রাখবেন যে এটি কোনও আপেক্ষিক পথ থাকলে শুরুতে কোনও ফরোয়ার্ড বা ব্যাকস্ল্যাশ হওয়া উচিত নয়)


ঠিক আছে, সুতরাং এটি সিডাব্লুডি থেকে কাজ করবে যা ওপি যা চায় তা নয়। স্ক্রিপ্ট অবস্থান থেকে কাজ করতে চান।
স্যামি বেঞ্চেরিফ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.