1 satır kodda bir dosyayı aç ve kapat


128

Şimdi kullanıyorum:

pageHeadSectionFile = open('pagehead.section.htm','r')
output = pageHeadSectionFile.read()
pageHeadSectionFile.close()

Ancak kodun daha iyi görünmesi için şunları yapabilirim:

output = open('pagehead.section.htm','r').read()

Yukarıdaki sözdizimini kullanırken, sistem kaynaklarını boşaltmak için dosyayı nasıl kapatırım?


19
Tek gömleklerde doğası gereği daha çekici hiçbir şey yoktur. Kod, yazıldığından çok daha sık okunur ve "soğukkanlılık" için değil, anlaşılması için yazılmalıdır. Bunun tek istisnası, bir dilde iyi bilinen bir deyim olduğu zamandır, ancak bu durumda bir tanesinin farkında değilim.
drdwilcox

17
@drdwilcox: Şifreli tek satırlar kötüdür, bildirimsel tek satırlar iyidir. Çekirdekte tek bir işlev çağrısında bir dosyayı (bu kadar yaygın ihtiyaç) okumak için bir işlev sarmalayıcısı olmamasının bir nedeni yok (en azından bir tane göremiyorum). Gibi bir şey contents = os.readfile(path). Daha güzel bir şey yapmak isteseydim, tamam, mutlu bir şekilde kullanırdım with open(path) as fd: contents = fd.read(). Elbette kişi kendi sarmalayıcısını yazabilir, ancak programcılara soyutlamalara yararlı olanı sağlamak için çekirdek bunun içindir.
tokland

5
Kodun yazıldığından çok daha fazla okunduğu doğrudur, ancak daha uzun kodun kısa kod kadar iyi olduğu iması daha yanlış olamaz. Kodunuzu olabildiğince kısa yapmak için zaman ayırırsanız (anlaşılması zor akıllı hilelere başvurmadan), bu yatırım kod okunduğunda defalarca karşılığını alacaktır. Yazdığınız her satır, kodunuzu okuyan herkes için kötü bir hizmettir, bu nedenle mümkün olduğunca az yazmaya çalışmalısınız. Pascal'ın ünlü sözünü hatırlayın: "Bu mektubu daha uzun yaptım çünkü onu kısaltacak boş zamanım yoktu."
John Williams

Yanıtlar:


195

Gerçekten kapatmak zorunda değilsiniz - Python bunu çöp toplama sırasında veya programdan çıkarken otomatik olarak yapacaktır. Ancak @ delnan'ın da belirttiği gibi, çeşitli nedenlerle onu açıkça kapatmak daha iyi bir uygulamadır.

Öyleyse, kısa, basit ve açık bir şekilde tutmak için ne yapabilirsiniz?

with open('pagehead.section.htm','r') as f:
    output = f.read()

Şimdi sadece iki satır ve oldukça okunabilir olduğunu düşünüyorum.


2
@ 1qazxsw2 kullanırsanız withdeyimi dosya kaynak düzgün sizin için kapalı olacaktır.
David Alber

13
Tekrar ilk cümle: Python sonunda kapatacak . Ancak bu, kapatmayı unutmanız gerektiği anlamına gelmez. Yeniden sayımla bile, dosya sandığınızdan ve istediğinizden çok daha uzun süre açık kalabilir (örneğin, döngülerle başvurulursa). Bu, herhangi bir zamanda herhangi bir şeyin GC'ye tabi tutulacağına dair hiçbir garantinizin olmadığı, iyi bir GC'ye sahip Python uygulamalarında üç kez olur. CPython belgeleri bile böyle bir temizleme için GC'ye güvenmemeniz gerektiğini söylüyor. Cevabın son kısmı cesur olmalıdır.

6
Gerçekten tekoutput = f.read() satırlık bir şeye ihtiyacınız varsa , parçayı aynı satıra :.
Karl Knechtel

1
"aç 1 satır kodda bir dosyayı oku ve kapat" bu iki satırdır ve soruyu yanıtlamaz.
user5359531

1
Bu uygulamaya bağlıdır - Sven'in cevabına bakın.
Tim Pietzcker

71

Python Standart Kitaplık Pathlib modülü aradığınızı yapar:

Path('pagehead.section.htm').read_text()

Yolu içe aktarmayı unutmayın:

jsk@dev1:~$ python3
Python 3.5.2 (default, Sep 10 2016, 08:21:44)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from pathlib import Path
>>> (Path("/etc") / "hostname").read_text()
'dev1.example\n'

Python 27'de arka plana sahip pathlibveyapathlib2


8
Önerilen diğer cevaplar withiyidir, ancak withbir ifade değil, bir ifadedir. Bu pathlibcevap, bir Python ifadesine yerleştirilebilecek orijinal soruya verilen tek cevaptır. Gibi bir şeySECRET_KEY = os.environ.get('SECRET_KEY') or pathlib.Path('SECRET_KEY').read_bytes()
LeoRochael

24

CPython kullanarak, dosyanız satır çalıştırıldıktan hemen sonra kapatılır, çünkü dosya nesnesi hemen çöp toplanır. Yine de iki dezavantaj var:

  1. CPython'dan farklı Python uygulamalarında, dosya genellikle hemen kapatılmaz, bunun yerine daha sonra kontrolünüz dışında kapatılır.

  2. Python 3.2 veya üzerinde, bu ResourceWarning, etkinleştirilirse bir atacaktır .

Bir ek satır yatırmak daha iyidir:

with open('pagehead.section.htm','r') as f:
    output = f.read()

Bu, dosyanın her koşulda doğru şekilde kapatılmasını sağlayacaktır.


17

Bunu yapmak için herhangi bir özel kitaplığı içe aktarmanıza gerek yok.

Normal sözdizimini kullanın ve dosyayı okumak için açacak ve sonra kapatacaktır.

with open("/etc/hostname","r") as f: print f.read() 

veya

with open("/etc/hosts","r") as f: x = f.read().splitlines()

bu size satırları içeren bir x dizisi verir ve şu şekilde yazdırılabilir:

for line in x: print line

Bu tek gömlekler bakım için çok faydalıdır - temelde kendi kendini belgelendirir.


8

Yapabileceğiniz şey, withifadeyi kullanmak ve iki adımı tek satıra yazmaktır:

>>> with open('pagehead.section.htm', 'r') as fin: output = fin.read();
>>> print(output)
some content

withDeyimi çağrısına ilgilenir __exit__şey kötü Kodunuzdaki oldu bile verilen nesnenin işlevi; try... finallysözdizimine yakın . Tarafından döndürülen bir nesne için open, __exit__dosya kapağın tekabül eder.

Bu ifade Python 2.6 ile tanıtıldı.


Küçük bir açıklama: göre belgelerde with Python 2.5 tanıtılan, ancak gerekiyordu edildi açıkça ithal gelen __future__. Python 2.6'daki tüm bağlamlardan erişilebilir hale geldi.
David Alber

5

Kullanım iliyo : (satır içi io):

file open (), read (), close () yerine sadece bir işlev çağrısı.

from ilio import read

content = read('filename')

2
with open('pagehead.section.htm')as f:contents=f.read()

4
Bunun ilk 3 cevaptan farkı nedir?
Tüm İşçiler

4
En büyük fark, soruda belirtildiği gibi sadece bir satır olmasıdır. Şahsen ben bunun ötesini bulamıyorum ama soruya kendiniz katkıda bulunmaktansa çalışmalarımı eleştirmekte özgürüm.

3
Python'da bir dosyayı açmanın, okumanın ve kapatmanın en kısa, yerleşik yolu, 1 satıra sıkıştırılmış olsun ya da olmasın 2 mantıksal satır kullanmaktır. Bu yüzden bu cevabın 3 orijinal cevaptan etkili bir şekilde farklı olduğunu görmüyorum.
Tüm Çalışanlar Önemlidir

1
Etkili olarak farklı olup olmadığı önemli değil. Bu sayfaya python -ckomut satırında kullanılabilecek tek satırlık sözdizimini aradım , bu nedenle 2 satırlı yanıtlar göndermek yardımcı olmuyor.
user5359531

1
@ user5359531 Amacınızı anlamıyorum: python ifadelerini alıntı yapabileceğinizi ", ;iki talimat eklemek için kullanabileceğinizi ve ardından yeni satırı silebileceğinizi :biliyor musunuz? Aşağıdaki ifade benim için gayet iyi çalışıyor:$> python -c "with open('some file', 'r') as f: print(next(f))"
Joël

2

Bunu başarmanın en doğal yolunun bir işlevi tanımlamak olduğunu düşünüyorum.

def read(filename):
    f = open(filename, 'r')
    output = f.read()
    f.close()
    return output

Daha sonra şunları yapabilirsiniz:

output = read('pagehead.section.htm')

0

Bir günlük dosyasında greplediğim bir şeyi çevreleyen birkaç satır almam gerektiğinde sık sık böyle bir şey yapıyorum:

$ grep -n "xlrd" requirements.txt | awk -F ":" '{print $1}'
54

$ python -c "with open('requirements.txt') as file: print ''.join(file.readlines()[52:55])"
wsgiref==0.1.2
xlrd==0.9.2
xlwt==0.7.5

1
Tamamen orijinal konusuyla ilgili olmayan, ancak içine bakmak gerekir grep -A <n>, grep -B <n>ve grep -C <n>bu yararlı olup olmadığını. Daha fazla bilgi: stackoverflow.com/a/9083/1830159
Liam Stanley

0

Kullanarak more_itertools.with_iter, outputtek satırda bir eşdeğer açmak, okumak, kapatmak ve atamak mümkündür (import ifadesi hariç):

import more_itertools as mit


output = "".join(line for line in mit.with_iter(open("pagehead.section.htm", "r")))

Mümkün olsa da, bir dosyanın içeriğini bir değişkene atamaktan başka bir yaklaşım arayabilirim, yani tembel yineleme - bu geleneksel bir withblok kullanılarak veya yukarıdaki örnekte kaldırılarak join()ve yinelenerek yapılabilir output.


Oneliner'ın içine de aktarabilirsiniz. "".join(line for line in __import__('more_itertools').with_iter(open("pagehead.section.htm", "r")))Bu gayet iyi çalışıyor ve içe aktarma için bir satır ihtiyacını ortadan kaldırıyor.
melwil

1
Sana tamamen katılıyorum. Bununla birlikte, görevleri tek başlıklar ile çözmeyi tartışırken, kendimi çoğu zaman üzerinde anlaşılan sonucun yeni bir python kabuğuna yapıştırılmış tek bir kod satırı olması gerektiği tartışmalarda buldum. Bu tür zorluklar nadiren pep8 ile uyumludur. Bu, kod yazmak için hiçbir şekilde iyi bir uygulama değil, yalnızca içe aktarma ihtiyacını ortadan kaldırmak için bir ipucu olarak düşünüldü.
melwil

0

O sıcak ve bulanık hissi istiyorsanız, sadece gitmek ile .

Python 3.6 için bu iki programı yeni bir IDLE başlangıcı altında çalıştırdım ve şu çalışma sürelerini verdim:

0.002000093460083008  Test A
0.0020003318786621094 Test B: with guaranteed close

Yani pek bir fark yok.

#--------*---------*---------*---------*---------*---------*---------*---------*
# Desc: Test A for reading a text file line-by-line into a list
#--------*---------*---------*---------*---------*---------*---------*---------*

import sys
import time

#                                  # MAINLINE
if __name__ == '__main__':
    print("OK, starting program...")

    inTextFile = '/Users/Mike/Desktop/garbage.txt'

#                                  # Test: A: no 'with;
    c=[]
    start_time = time.time()
    c = open(inTextFile).read().splitlines()
    print("--- %s seconds ---" % (time.time() - start_time))

    print("OK, program execution has ended.")
    sys.exit()                     # END MAINLINE

ÇIKTI:

OK, starting program...
--- 0.002000093460083008 seconds ---
OK, program execution has ended.

#--------*---------*---------*---------*---------*---------*---------*---------*
# Desc: Test B for reading a text file line-by-line into a list
#--------*---------*---------*---------*---------*---------*---------*---------*

import sys
import time

#                                  # MAINLINE
if __name__ == '__main__':
    print("OK, starting program...")

    inTextFile = '/Users/Mike/Desktop/garbage.txt'

#                                  # Test: B: using 'with'
    c=[]
    start_time = time.time()
    with open(inTextFile) as D: c = D.read().splitlines()
    print("--- %s seconds ---" % (time.time() - start_time))

    print("OK, program execution has ended.")
    sys.exit()                     # END MAINLINE

ÇIKTI:

OK, starting program...
--- 0.0020003318786621094 seconds ---
OK, program execution has ended.
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.