Python'daki çalışma dizinini nasıl değiştirebilirim?


Yanıtlar:


767

Çalışma dizinini aşağıdakilerle değiştirebilirsiniz:

import os

os.chdir(path)

Bu yöntemi kullanırken izlenecek en iyi iki uygulama vardır:

  1. Geçersiz yolda özel durumu (WindowsError, OSError) yakalayın. İstisna atılırsa, özellikle yıkıcı olanlar olmak üzere yinelemeli işlemler gerçekleştirmeyin. Yeni yolda değil, eski yolda çalışacaklar.
  2. İşiniz bittiğinde eski dizininize dönün. Bu, chdir çağrınızı Brian M. Hunt'ın cevabında yaptığı gibi bir bağlam yöneticisine sararak istisnai bir şekilde yapılabilir .

Alt işlemde geçerli çalışma dizinini değiştirmek, üst işlemdeki geçerli çalışma dizinini değiştirmez. Bu Python yorumlayıcısı için de geçerlidir. os.chdir()Çağıran işlemin CWD'sini değiştirmek için kullanamazsınız .


3
cdunn2001'in hafif dekoratör tabanlı cevabı modern Python için ideal bir yaklaşımdır. Yukarıdaki cevap bunun nedenini göstermektedir. Ne yaptığınızı bildiğinizi düşünmedikçe asla os.chdir()içerik yöneticisinin dışına çıkmayın. ( Muhtemelen bilmiyorsun. )
Cecil Curry

6
Bence bu interaktif bir kabukta en kolay yol. Windows'da, eğik çizgi kullanmanız gerektiğini unutmayın, örneğinos.chdir("C:/path/to/location")
Josiah

Dikkat edilmesi gereken tek şey, python programınızı yürütülebilir bir hale getirir ve cron'da çalıştırırsanız, ana dizininizde başlayacağıdır. Bu yüzden tam nitelikli bir yol kullanmak en iyisidir. Bu kesinlikle işe yarıyor, yine de Python'dan çağırabileceğim herhangi bir komut dosyasında tam nitelikli yollar kullanıyorum, çünkü bunun Python programının dışında uygulanacağına dair bir garanti yok.
SDsolar

310

Çalışma dizinini değiştirmek için bir bağlam yöneticisi örneği. Başka bir yerde atıfta bulunulan bir ActiveState versiyonundan daha basittir , ancak bu işi yapar.

İçerik Yöneticisi: cd

import os

class cd:
    """Context manager for changing the current working directory"""
    def __init__(self, newPath):
        self.newPath = os.path.expanduser(newPath)

    def __enter__(self):
        self.savedPath = os.getcwd()
        os.chdir(self.newPath)

    def __exit__(self, etype, value, traceback):
        os.chdir(self.savedPath)

Veya ContextManager'ı kullanarak daha kısa eşdeğeri (aşağıda) deneyin .

Misal

import subprocess # just to call an arbitrary command e.g. 'ls'

# enter the directory like this:
with cd("~/Library"):
   # we are in ~/Library
   subprocess.call("ls")

# outside the context manager we are back wherever we started.

Hangi dizinden FROM değiştirdiğinizi bilmeniz gerekiyorsa return self, sonuna ekleyebilirsiniz __enter__. Bu şekilde bir with cd('foo') as cm:önceki dire erişebilir ve erişebilirsinizcm.savedPath
Sam F

Eski dizine ("savePath" dizininde saklanan) geri dönmenin mümkün olmadığı durumlar olduğunu unutmayın. Örneğin, daha ayrıcalıklı bir işlem daha az ayrıcalıklı bir işlem yürütürse, ikinci işlem ilk işlem çalışma dizinini devralır, bu durumda ikinci işlemin kendi çalışma dizinleriyle kendi çalışma dizinine giremediği durumlarda bile.
Kai Petzke

141

Ben os.chdirböyle kullanmak istiyorum:

os.chdir("/path/to/change/to")

Bu arada, mevcut yolunuzu bulmanız gerekiyorsa, kullanın os.getcwd().

Daha fazlası burada


117

cd() bir jeneratör ve dekoratör kullanarak yazmak kolaydır.

from contextlib import contextmanager
import os

@contextmanager
def cd(newdir):
    prevdir = os.getcwd()
    os.chdir(os.path.expanduser(newdir))
    try:
        yield
    finally:
        os.chdir(prevdir)

Daha sonra, bir istisna atıldıktan sonra bile dizin geri döndürülür:

os.chdir('/home')

with cd('/tmp'):
    # ...
    raise Exception("There's no place like home.")
# Directory is now back to '/home'.

3
Ayrıca, bu potansiyel gaf (unutmayın try/finally).
cdunn2001

5
Brilliance! Kabul edilen cevaptan giriş yorumu bu cevaba enjekte edilmiş olsaydı, bu ölçülemeyecek kadar ideal olurdu. Yine de, bu yanıtın özlü, Pythonically safe uygulaması vermek zorunda olduğum tüm upvotes garanti eder.
Cecil Curry

3
Neden yieldolmasın return? Bunun bir jeneratör olması mı gerekiyor?
EKons

Lütfen getirinin vs getiriyle ilgisi hakkında yorum yapın!
NicoBerrogorry

1
@NicoBerrogorry, bu bir jeneratör. Contextlib.contextmanager üzerindeki dokümanlara bakın . Bu, Python'da öğrenmeye değer çok yararlı bir kalıptır.
cdunn2001

25

Eğer Python nispeten yeni bir sürümünü kullanıyorsanız, ayrıca gibi bir bağlam yöneticisini kullanabilirsiniz bu bir :

from __future__ import with_statement
from grizzled.os import working_directory

with working_directory(path_to_directory):
    # code in here occurs within the directory

# code here is in the original directory

GÜNCELLEME

Kendinizinkini yuvarlamayı tercih ederseniz:

import os
from contextlib import contextmanager

@contextmanager
def working_directory(directory):
    owd = os.getcwd()
    try:
        os.chdir(directory)
        yield directory
    finally:
        os.chdir(owd)

1
İyi genel fikir. Burada başka bağımlılıkları olmayan bir Activestate tarifi .
cfi

4
Bağımlılıklar kötü. Python'un yerleşik contextlib.contextmanagerdekoratörü iyidir. Bkz cdunn2001 'ın dekoratör tabanlı cevap ideal şimdi kabul cevap olurdu.
Cecil Curry

14

Başkaları tarafından zaten belirtildiği gibi, yukarıdaki tüm çözümler sadece mevcut sürecin çalışma dizinini değiştirir. Unix kabuğuna geri döndüğünüzde bu kaybolur. Umutsuz Eğer yapabilirsiniz bu korkunç kesmek ile Unix üzerinde ebeveyn kabuk dizini değiştirin:

def quote_against_shell_expansion(s):
    import pipes
    return pipes.quote(s)

def put_text_back_into_terminal_input_buffer(text):
    # use of this means that it only works in an interactive session
    # (and if the user types while it runs they could insert characters between the characters in 'text'!)
    import fcntl, termios
    for c in text:
        fcntl.ioctl(1, termios.TIOCSTI, c)

def change_parent_process_directory(dest):
    # the horror
    put_text_back_into_terminal_input_buffer("cd "+quote_against_shell_expansion(dest)+"\n")

4
Deli, kırılgan kesmek zorunlu upvotes alır. Bunu hiç kimse yapmamalıdır, özellikle de "ve kullanıcı çalışırken yazıyorsa ..." uyarısı. Yine de, ana CWD değişen görmek içimdeki asi neckbeard titillates olan sıralama-ama gerçekten mümkün değildir. Upvotes! Herkes için upvotes!
Cecil Curry


11

os.chdir()adlı kullanıcının Pythonic sürümüdür cd.


8
import os

abs_path = 'C://a/b/c'
rel_path = './folder'

os.chdir(abs_path)
os.chdir(rel_path)

Her ikisini de os.chdir (abs_path) veya os.chdir (rel_path) ile kullanabilirsiniz, göreli bir yol kullanmak için os.getcwd () öğesini çağırmanıza gerek yoktur.


İyi çalışıyor. Bir dizini değiştirmeden önce ve sonra mevcut dizini doğrulamak için os.getcwd () kullanabilirsiniz ..
vinsinraw

6

Daha ileri Brian tarafından işaret ve sh (1.0.8+) dayalı

from sh import cd, ls

cd('/tmp')
print ls()

3

"Cd .." seçeneği gibi bir şey yapmak istiyorsanız, şunu yazın:

os.chdir ( "..")

Windows cmd: cd'deki ile aynıdır. Tabii ki import os gereklidir (örneğin, kodunuzun 1. satırı olarak yazın)


0

Spyder ve love GUI kullanıyorsanız, ekranınızın sağ üst köşesindeki klasör düğmesine tıklayabilir ve geçerli dizin olarak istediğiniz klasörler / dizinler arasında gezinebilirsiniz. Bunu yaptıktan sonra, spyder IDE'deki pencerenin dosya gezgini sekmesine gidebilir ve orada bulunan tüm dosyaları / klasörleri görebilirsiniz. geçerli çalışma dizininizi kontrol etmek için spyder IDE konsoluna gidin ve

pwd

daha önce seçtiğinizle aynı yolu yazdırır.


-1

Komut dosyası işleminin geçerli dizinini değiştirmek önemsizdir. Soru aslında nasıl bir python komut dosyası çağrılır, hangi komut penceresinin geçerli dizini değiştirmek olduğunu düşünüyorum, bu çok zor. Windows'daki bir Bat komut dosyası veya Bash kabuğundaki bir Bash komut dosyası, bunu sıradan bir cd komutuyla yapabilir, çünkü kabuğun kendisi yorumlayıcıdır. Hem Windows hem de Linux Python bir programdır ve hiçbir program ebeveyninin ortamını doğrudan değiştiremez. Bununla birlikte, basit bir kabuk komut dosyasının, zor şeylerin çoğunu yapan bir Python komut dosyası ile kombinasyonu, istenen sonucu elde edebilir. Örneğin, geri / ileri / select revisit için geçiş geçmişine sahip genişletilmiş bir cd komutu yapmak için, basit bir yarasa komut dosyası tarafından çağrılan nispeten karmaşık bir Python betiği yazdım. Geçiş listesi bir dosyada saklanır, hedef dizini ilk satırda. Python betiği döndüğünde, yarasa betiği dosyanın ilk satırını okur ve cd'ye argüman yapar. Tam yarasa betiği (kısalık için eksi yorumlar):

if _%1 == _. goto cdDone
if _%1 == _? goto help
if /i _%1 NEQ _-H goto doCd
:help
echo d.bat and dSup.py 2016.03.05. Extended chdir.
echo -C = clear traversal list.
echo -B or nothing = backward (to previous dir).
echo -F or - = forward (to next dir).
echo -R = remove current from list and return to previous.
echo -S = select from list.
echo -H, -h, ? = help.
echo . = make window title current directory.
echo Anything else = target directory.
goto done

:doCd
%~dp0dSup.py %1
for /F %%d in ( %~dp0dSupList ) do (
    cd %%d
    if errorlevel 1 ( %~dp0dSup.py -R )
    goto cdDone
)
:cdDone
title %CD%
:done

Python betiği, dSup.py:

import sys, os, msvcrt

def indexNoCase ( slist, s ) :
    for idx in range( len( slist )) :
        if slist[idx].upper() == s.upper() :
            return idx
    raise ValueError

# .........main process ...................
if len( sys.argv ) < 2 :
    cmd = 1 # No argument defaults to -B, the most common operation
elif sys.argv[1][0] == '-':
    if len(sys.argv[1]) == 1 :
        cmd = 2 # '-' alone defaults to -F, second most common operation.
    else :
        cmd = 'CBFRS'.find( sys.argv[1][1:2].upper())
else :
    cmd = -1
    dir = os.path.abspath( sys.argv[1] ) + '\n'

# cmd is -1 = path, 0 = C, 1 = B, 2 = F, 3 = R, 4 = S

fo = open( os.path.dirname( sys.argv[0] ) + '\\dSupList', mode = 'a+t' )
fo.seek( 0 )
dlist = fo.readlines( -1 )
if len( dlist ) == 0 :
    dlist.append( os.getcwd() + '\n' ) # Prime new directory list with current.

if cmd == 1 : # B: move backward, i.e. to previous
    target = dlist.pop(0)
    dlist.append( target )
elif cmd == 2 : # F: move forward, i.e. to next
    target = dlist.pop( len( dlist ) - 1 )
    dlist.insert( 0, target )
elif cmd == 3 : # R: remove current from list. This forces cd to previous, a
                # desireable side-effect
    dlist.pop( 0 )
elif cmd == 4 : # S: select from list
# The current directory (dlist[0]) is included essentially as ESC.
    for idx in range( len( dlist )) :
        print( '(' + str( idx ) + ')', dlist[ idx ][:-1])
    while True :
        inp = msvcrt.getche()
        if inp.isdigit() :
            inp = int( inp )
            if inp < len( dlist ) :
                print( '' ) # Print the newline we didn't get from getche.
                break
        print( ' is out of range' )
# Select 0 means the current directory and the list is not changed. Otherwise
# the selected directory is moved to the top of the list. This can be done by
# either rotating the whole list until the selection is at the head or pop it
# and insert it to 0. It isn't obvious which would be better for the user but
# since pop-insert is simpler, it is used.
    if inp > 0 :
        dlist.insert( 0, dlist.pop( inp ))

elif cmd == -1 : # -1: dir is the requested new directory.
# If it is already in the list then remove it before inserting it at the head.
# This takes care of both the common case of it having been recently visited
# and the less common case of user mistakenly requesting current, in which
# case it is already at the head. Deleting and putting it back is a trivial
# inefficiency.
    try:
        dlist.pop( indexNoCase( dlist, dir ))
    except ValueError :
        pass
    dlist = dlist[:9] # Control list length by removing older dirs (should be
                      # no more than one).
    dlist.insert( 0, dir ) 

fo.truncate( 0 )
if cmd != 0 : # C: clear the list
    fo.writelines( dlist )

fo.close()
exit(0)

Güzel bir cevap olsa da, OP ana sürecin CWD'sini değiştirmekle ilgili olmadığını belirten bir cevap seçti. Bu, sorunun ne anlama geldiğiyle ilgili olası karışıklıkları giderir.
Tin Man

Tin Man'a-- bu cevabı önerimi göndermeden önce seçildi. Geniş kapsamlı cevapların kafa karıştırıcı olabileceğini düşünüyorum. verilen bir süreç içinde cd (yani bir python komut dosyası) öylesine basit ki neden kimse sormak bilmiyorum.
David McCracken

1
Aslında bu cevap yıllar önce seçildi . Eğer uygun olmasaydı o zamandan beri birçok kez çağrılmış olurdu.
Tin Man

Bence bu karışıklık devam ediyor. Daha yakın zamanlarda, "linux'un" cd "komutunu python'da simüle etmek ve programdan [duplicate] çıktıktan sonra dizin değişikliğini sürdürmek" sorusu burada yanıtlandığı için reddedildi, ancak aslında bu soru seçilen cevap tarafından ele alınmadı. Benim önerim Windows için ama sorunlar Linux'ta aynı.
David McCracken
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.