見出し画像

【Python】SimplePrograms line 9 ファイルアクセスと「with」ブロック

プログラム

9行プログラムです。

# indent your Python code to put into an email 
import glob 
# glob supports Unix style pathname extensions 
python_files = glob.glob('*.py') 
for file_name in sorted(python_files): 
    print (' ------' + file_name) 
    with open(file_name) as f: 
        for line in f: 
            print (' ' + line.rstrip()) 

実行結果

 ------binary_sequence.py
 a = b'ab cdef'
 print('type of a is' , type(a))
 for item in a:
     print(item)

 ------line9.py
 # indent your Python code to put into an email
 import glob
 # glob supports Unix style pathname extensions
 python_files = glob.glob('*.py')
 for file_name in sorted(python_files):
     print (' ------' + file_name)
     with open(file_name) as f:
         for line in f:
             print (' ' + line.rstrip())
         print()

 ------set.py
 a = {1, 2, 3}
 print('type of a is' , type(a))
 for item in a:
     print(item)

 ------text_sequence.py
 a = 'ab cdef'
 print('type of a is ' , type(a))
 for item in a:
     print(item)

解説

2、4行目 UNIXスタイルのファイル指定

ファイルアクセスです。
コメントは飛ばして、2行目と4行目。

import glob 
python_files = glob.glob('*.py') 

「glob」は、コメントにある通り「UNIXスタイルのファイル指定を可能にするライブラリ」です。「glob」というのはUNIX時代からの呼び名であるらしい。UNIX手法の踏襲は未だに多く見られます。「glob」は「グローバル・コマンド」の略称とのこと。ネーミングそのものがグローバルですが、定着してしまったのでしょう。

「glob」ライブラリの「glob」を呼び出して、カレントディレクトリの下にある「.py」に該当するファイルのファイル名を取り出しています。UNIXにおいて「*」はワイルドカードで、任意の長さの文字列を意味します。ですからこれは「.py」で終わる文字列のことになります。

この「glob.glob」の戻り値の型はなんでしょうか。

>>> import glob
>>> python_files = glob.glob('*.py') 
>>> type(python_files)
<class 'list'>
>>>

「list」型ですね。

ちなみに中身を表示してみると、ファイル名が文字列で設定されています。

>>> print(python_files)
['line5.py', 'line7.py', 'binary_sequence.py', 'text_sequence.py', 'set.py', 'line9.py']
>>>

5行目 for文(ファイルリスト)

for file_name in sorted(python_files):

「sorted」をなしにすると、こうなります。

for file_name in python_files:

「python_files」にはファイル名が1つずつ入っていますから、そのファイル名を1つずつ順番に処理することになります。

「sorted」を潜らせると、そのファイル名が並べ替えられることになります。

「sorted」するかしないかで、次のように変わります。

>>> print(python_files)
['line5.py', 'line7.py', 'binary_sequence.py', 'text_sequence.py', 'set.py', 'line9.py']
>>> print(sorted(python_files))
['binary_sequence.py', 'line5.py', 'line7.py', 'line9.py', 'set.py', 'text_sequence.py']
>>>

6行目

ここからは「for」文の中になります。

print (' ------' + file_name) 

これは、ファイル名を表示しているだけですね。

7行目 withブロック(open)

with open(file_name) as f: 

with」。
また、新しいキーワードだな。
これも、C言語にはなかったものですね。
VBにも「with」はあったけど、少し違うように見えます。

「with」というのは、「open/close」や「lock/unlock」など、後片付けが必要な処理をパッケージ化するためのものだそうです。
そう、このコードに「close」はないですね。

「with」ブロックを抜ける時に、自動的にクローズされることになります。

「with」ブロックなしで書いてみる

「with」を使うと「close」忘れという問題がなくなっていいのだけど、時には「オープンしたまま」というような使い方もしないではない。
「open」は「with」ブロックなしでも使えるのかな。

試してみた。

「with」ブロックなしでももちろん使えるようだ。

コード

f = open('set.py')
print('id(f) = ', id(f))
print('type(f) =', type(f))
print('f.name =', f.name)
print('f.closed =', f.closed)
print()

def show_py():
    print (' ------ show_py')     
    print('id(f) = ', id(f))
    print('type(f) =', type(f))
    print('f.name =', f.name)
    print('f.closed =', f.closed)
    print('f.tell() =', f.tell())
    f.seek(0)
    for line in f: 
        print (' ' + line.rstrip()) 
    print()

show_py()
show_py()
f.close()

実行結果

id(f) =  4009287472
type(f) = <class '_io.TextIOWrapper'>
f.name = set.py
f.closed = False

 ------ show_py
id(f) =  4009287472
type(f) = <class '_io.TextIOWrapper'>
f.name = set.py
f.closed = False
f.tell() = 0
 a = {1, 2, 3}
 print('type of a is' , type(a))
 for item in a:
     print(item)

 ------ show_py
id(f) =  4009287472
type(f) = <class '_io.TextIOWrapper'>
f.name = set.py
f.closed = False
f.tell() = 77
 a = {1, 2, 3}
 print('type of a is' , type(a))
 for item in a:
     print(item)

「with」ブロックを付けて書いてみる

前記のコードを「with」ブロックを付けて書いてみました。

やっぱり、クローズされてしまっているようです。

コード

with open('set.py') as f:
    print('id(f) = ', id(f))
    print('type(f) =', type(f))
    print('f.name =', f.name)
    print('f.closed =', f.closed)
print()

def show_py():
    print (' ------ show_py')     
    print('id(f) = ', id(f))
    print('type(f) =', type(f))
    print('f.name =', f.name)
    print('f.closed =', f.closed)
    print('f.tell() =', f.tell())
    f.seek(0)
    for line in f: 
        print (' ' + line.rstrip()) 
    print()

show_py()
show_py()
f.close()

実行結果

id(f) =  3867382704
type(f) = <class '_io.TextIOWrapper'>
f.name = set.py
f.closed = False

 ------ show_py
id(f) =  3867382704
type(f) = <class '_io.TextIOWrapper'>
f.name = set.py
f.closed = True
Traceback (most recent call last):
  File "/storage/emulated/0/qpython/.last_tmp.py", line 20, in <module>
    show_py()
  File "/storage/emulated/0/qpython/.last_tmp.py", line 14, in show_py
    print('f.tell() =', f.tell())
ValueError: I/O operation on closed file.
1|:/ $

8行目 ファイルから1行ずつ読み込み

    for line in f: 

ファイルから1行ずつ取り出しています。
「f.dir()」を実行してみると、「iter」も「next」も持っているようですから、イテラブルなオブジェクトのようです。

9行目

        print (' ' + line.rstrip()) 

読み出した1行を出力します。
「rstrip」は、「strip」は取り除く、「r」は「right」右。右側の(行の末尾の)文字を取り除きます。引数で取り除く文字を指定しますが、指定がなければ空白を取り除きます。

「rstrip()」は、「行の末尾の空白を取り除く
」ということを意味します。

いいなと思ったら応援しよう!