Kod deposuyla çalışırken kaynakların göreli yollarına başvurma


188

Hem Windows hem de Linux'a dağıtılan bir kod havuzuyla çalışıyoruz - bazen farklı dizinlerde. Proje içindeki modüllerden biri, projedeki Python dışı kaynaklardan birine (CSV dosyaları vb.) Nasıl atıfta bulunmalıdır?

Şöyle bir şey yaparsak:

thefile=open('test.csv')

veya:

thefile=open('../somedirectory/test.csv')

Yalnızca komut dosyası belirli bir dizinden veya dizinlerin bir alt kümesinden çalıştırıldığında çalışır.

Ne yapmak istiyorum gibi bir şey:

path=getBasePathOfProject()+'/somedirectory/test.csv'
thefile=open(path)

Mümkün mü?

Yanıtlar:


255

Geçerli dosya yoluna göre bir dosya adı kullanmaya çalışın. './My_file' için örnek:

fn = os.path.join(os.path.dirname(__file__), 'my_file')

Python 3.4+ sürümünde ayrıca pathlib kullanabilirsiniz :

fn = pathlib.Path(__file__).parent / 'my_file'

3
Bu çözüm yalnızca kaynak python dosyasının aynı dizininde veya bir alt dizinde ise çalışacağını düşünüyorum. Aşağıdaki ağaç yapınız olduğunda bunu nasıl çözersiniz: / Project_Root_dir / python_files_dir / Burada daha fazla alt dizin py_file.py / resources / some
altdirs

1
Maalesef, dosya ağacı son mesajda bozuldu ... ikinci deneme: Dosyanız /Project_Root_dir/python_files_dir/some_subdirs/py_file.py adresinde var ve kaynak dosyanız /Project_Root_dir/resources/some_subdirs/resource_file.csv adresinde
olamundo

28
Join (foo, '..') kullanarak üst dizine erişebilmelisiniz. Bu nedenle / root / python_files / module / myfile dosyasından os.path.join (os.path.dirname ( __file__), '..', '..', 'resources') kullanın
c089

7
os.pardir'..'her ikisi de POSIX ve Windows'ta eşdeğer olsa da biraz daha iyidir .
davidchambers

4
@cedbeu: Bu şimdiye kadar karşılaştığım her sistemde eşdeğerdir ve bence her sistem pythonu bugün çalışmaktadır (burada yanılıyorsam lütfen beni düzeltin). Ancak, python'un gelecekte farklı bir yol ayırıcı kullanarak bir sisteme taşınmasını ve kodunuzun buna hazır olmasını istiyorsanız, os.pardir daha taşınabilir olacaktır. Ben her programcı, hiç python okumamış biri bile ".." anlamını bildiğini, "os.pardir" ise kişisel olarak belgelere bakmak zorunda kalacak dolaylı bir seviyedir d ".." ye yapışır.
c089

40

Kurulum araçlarını kullanıyorsanız veya dağıtırsanız (setup.py kurulumu), bu paketlenmiş kaynaklara erişmenin "doğru" yolu package_resources kullanıyor gibi görünmektedir.

Sizin durumunuzda örnek

import pkg_resources
my_data = pkg_resources.resource_string(__name__, "foo.dat")

Tabii ki kaynağı okur ve ikili verileri okur benim verilerimin değeri olur

Sadece dosya adına ihtiyacınız varsa,

resource_filename(package_or_requirement, resource_name)

Misal:

resource_filename("MyPackage","foo.dat")

Avantajı, yumurta gibi bir arşiv dağıtımı olsa bile çalışacağı garantisidir.

Bkz. Http://packages.python.org/distribute/pkg_resources.html#resourcemanager-api


3
Bunun eski bir cevap olduğunu biliyorum, tercih ettiğim yol pkg_resources kullanmak (/ belki de?), Ama fermuarlı yumurtaların kaybolması ile, sadece __file__eski güzel günler gibi kullanmanın herhangi bir zararı var mı?
Pykler

1
Bu sağlam bir yaklaşımdır. Yumurta konvansiyonu gitse bile, setuptools değil ve birçoğu hala yumurtanın çalışma zamanında inşa edildiği git repolarına karşı
deps kuruyor

18

Python'da, yollar geçerli çalışma dizinine göredir çoğu durumda programınızı çalıştırdığınız dizin olan göredir. Geçerli çalışma dizini geçerli modül dosyası ilişkin bir yol kullanarak bunu her zaman kötü bir seçimdir, çok büyük olasılıkla değil modül dosyası dizini ile aynı gibidir.

Mutlak yol kullanmak en iyi çözüm olmalıdır:

import os
package_dir = os.path.dirname(os.path.abspath(__file__))
thefile = os.path.join(package_dir,'test.cvs')

15

Genellikle buna benzer bir şey kullanırım:

import os
DATA_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), 'datadir'))

# if you have more paths to set, you might want to shorten this as
here = lambda x: os.path.abspath(os.path.join(os.path.dirname(__file__), x))
DATA_DIR = here('datadir') 

pathjoin = os.path.join
# ...
# later in script
for fn in os.listdir(DATA_DIR):
    f = open(pathjoin(DATA_DIR, fn))
    # ...

Değişken

__file__

bu kodu yazdığınız komut dosyasının dosya adını tutar, böylece komut dosyasına göre yollar oluşturabilirsiniz, ancak yine de mutlak yollarla yazabilirsiniz. Birkaç nedenden dolayı oldukça iyi çalışır:

  • yol mutlak, ama yine de göreceli
  • proje hala göreli bir kapsayıcıda konuşlandırılabilir

Ancak platform uyumluluğunu izlemeniz gerekir - Windows os.pathsep UNIX'ten farklıdır.


5
import os
cwd = os.getcwd()
path = os.path.join(cwd, "my_file")
f = open(path)

Ayrıca normalleştirmek için deneyin cwdkullanarak os.path.abspath(os.getcwd()). Daha fazla bilgi burada .


3
cwdbir modülün yolu olduğu çok az kullanım
cedbeu

bir paketin içinde çalışmaz, sadece kod tarafından ayarlanan aynı dizinden (veya çalışma dizininden).
alexandra

Kullanıcı programı farklı dizinden mutlak yol kullanarak çalıştırırsa bu çalışmaz. ör. python3 /usr/someone/test.py
sgrpwr

2

Build in __file__değişkenini kullanabilirsiniz . Geçerli dosyanın yolunu içerir. GetBaseOfProject projenizin kökündeki bir modülde uygulamak. Orada yol parçası almak __file__ve bunu dönecekti. Bu yöntem daha sonra projenizin her yerinde kullanılabilir.


0

Burada biraz güldüm. Bazı kaynak dosyalarını bir tekerlekli dosyaya paketlemek ve bunlara erişmek istedim. Manifest dosyası kullanarak paketleme yaptım, ancak pip install bir alt dizin olmadıkça yüklemiyordu. Bu sceen atışlarının umarız yardımcı olur

├── cnn_client
   ├── image_preprocessor.py
   ├── __init__.py
   ├── resources
      ├── mscoco_complete_label_map.pbtxt
      ├── retinanet_complete_label_map.pbtxt
      └── retinanet_label_map.py
   ├── tf_client.py

MANIFEST.in

recursive-include cnn_client/resources *

Standart setup.py kullanarak bir ses oluşturdu. pip tekerlek dosyasını kurdu. Kurulumdan sonra kaynakların kurulu olup olmadığını kontrol edin. Onlar

ls /usr/local/lib/python2.7/dist-packages/cnn_client/resources

mscoco_complete_label_map.pbtxt
retinanet_complete_label_map.pbtxt 
 retinanet_label_map.py  

Bu dosyalara erişmek için tfclient.py dosyasında. itibaren

templates_dir = os.path.join(os.path.dirname(__file__), 'resources')
 file_path = os.path.join(templates_dir, \
            'mscoco_complete_label_map.pbtxt')
        s = open(file_path, 'r').read()

Ve çalışıyor.


-5

Bunun cevabını bulmak için uzun zaman harcadım, ama sonunda anladım (ve aslında gerçekten basit):

import sys
import os
sys.path.append(os.getcwd() + '/your/subfolder/of/choice')

# now import whatever other modules you want, both the standard ones,
# as the ones supplied in your subfolders

Bu, alt klasörünüzün göreceli yolunu python'un bakması için dizinlere ekleyecektir. Çok hızlı ve kirli, ancak bir cazibe gibi çalışıyor :)


6
Bu yalnızca Python programını söz konusu .py dosyasıyla aynı dizinden çalıştırıyorsanız çalışır. Ve bu durumda, open('your/subfolder/of/choice')yine de yapabilirsin.
Paul Fisher

4
ve OP kodun hem Windows hem de Linux üzerinde çalışması gerektiğini belirtti. Bu olmayacak.
user183037
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.