1. I/O 编程
I/O
Input
/を指しますOutput
。
Input Stream
外部(ディスク、ネットワーク)からメモリに流れ込みます。
Output Stream
記憶から外部への流れ。
同步 I/O
CPU はI/O
完了を待ち、プログラムは後続の実行を中断します。
异步 I/O
CPU はI/O
完了を待ちませんが、最初に他のことを行い、コールバックまたはポーリングによってフォローアップを処理しますI/O
。
ファイルの読み書き
ディスク上のファイルを読み書きする機能はオペレーティング システムによって提供されます。最新のオペレーティング システムでは、通常のプログラムがディスクを直接操作することはできません。
ファイル ストリームの操作方法
方法 | 例証する |
---|---|
開ける() | 指定されたモードでファイル オブジェクトを開きます。パラメーターは文件名 と模式标示符 、オプションのパラメーターencoding (encoding) errors (エンコード エラー処理メソッド) |
読む() | ファイルのすべての内容を一度に読み取り、str オブジェクトを返す |
読み取り(サイズ) | size 一度にバイトを読み取る |
読み込まれた行() | 一度に 1 行ずつ読み取る |
readlines() | 一度にすべてを読み取り、行区切りを返しますlist |
書く() | 書き込む内容をメモリキャッシュに書き込み、close 呼び出し時に実際に内容を書き出す |
近い() | ファイルを閉じ、閉じる前にメモリ キャッシュの内容をすべて書き出します。 |
ファイル オブジェクト モード
キャラクター | 意味 |
---|---|
r |
読み取り (デフォルト) |
w |
書き込み、最初にファイルを切り捨てます |
x |
排他的な作成、ファイルが既に存在する場合は失敗 |
a |
ファイルが既に存在する場合は、ファイルの最後に書き込み、追加します |
b |
バイナリモデル |
t |
テキストモード (デフォルト) |
+ |
更新 (読み書き) |
ファイルを読む
with open('/Users/aurelius/test.txt', 'r') as f:
print(f.read())
with
このステートメントは、open
ファイルが最終的に保存されることを保証できます。close
try ... finally
finally
close
ファイルを書き込む
with open('/User/aurelius/test.txt', 'w') as f:
f.write('hello, world.')
StringIO と BytesIO
文字列IO
メモリの読み取りと書き込みには、str
ファイルの読み取りと書き込みと一貫したインターフェイスがあります。
from io import StringIO
# InputStream
f = StringIO()
f.write('hello')
# 读取写入的 str
f.getvalue()
# OutputStream
f = StringIO('hello, 中国')
f.read()
バイトIO
メモリの読み取りと書き込みbytes
from io import BytesIO
# InputStream
f = BytesIO()
f.write('中文'.encode('utf-8'))
print(f.getvalue())
# OutputStream
f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')
print(f.read().decode('utf-8'))
ファイルとディレクトリの操作
Python の組み込みos
モジュールは、システムが提供するインターフェイス関数を直接呼び出して、ファイルとディレクトリを操作できます。
>>> import os
>>> os.name
nt
環境変数
os.environ # 全部环境变量 (Class<Environ>)
os.environ.get('key', 'default') # 指定的环境变量,default 可选
ファイルとディレクトリの操作
関数 | 効果 |
---|---|
os.path.abspath('.') | 現在のパスの絶対パス |
os.path.join(r'd:\a', 'b') | パス 2 ( b ) をパス 1 ( d:\a ) に接続し、パス 2 が絶対パスの場合は、パス 2 を直接返します |
os.mkdir(r'd:\test') | ディレクトリを作成する |
os.mkdir(r'd:\test') | ディレクトリを削除する |
os.path.split(r'd:\test\file.txt') | 最後のレベルのディレクトリとファイル名に分割 |
os.path.splitext(r'd:\test\file.txt') | 分割ファイル拡張子 |
os.rename('test.txt', 'text.py') | ファイルの名前を変更 |
os.remove('test.py') | ファイルの削除 |
os.listdir('.') | 指定されたパスを一覧表示する |
os.path.isdir('d:\test') | パスかどうかを判断する |
os.path.isfile('d:\test\test.txt') | ファイルかどうかの判定 |
shutil
このモジュールは、ファイルコピー機能を提供するos
機能を補足します。copyfile()
シリアル化
メモリからストレージまたは転送に変数を変更するプロセスはシリアライゼーションと呼ばれpickling
、シリアライズされたオブジェクトをメモリに再読み込みすることはデシリアライゼーションと呼ばれますunpickling
。
ピクルス
- ダンプ/ダンプ
>>> import pickle
>>> d = dict(name='中国人', age=18, score=99)
# pickle.dumps 把任意对象序列化成 bytes
>>> pickle.dumps(d)
b'\x80\x04\x95*\x00\x00\x00\x00\x00\x00\x00}\x94(\x8c\x04name\x94\x8c\t\xe4\xb8\xad\xe5\x9b\xbd\xe4\xba\xba\x94\x8c\x03age\x94K\x12\x8c\x05score\x94Kcu.'
# pickle.dump 直接把对象序列化后写入 file-like Ojbect
>>> with open('dump.txt', 'wb') as w:
... pickle.dump(d, w)
- 負荷/負荷
>>> with open('dump.txt', 'rb') as r:
... d = pickle.load(r)
...
>>> d
{
'name': 'Aurelius', 'age': 18, 'score': 99}
pickle
逆シリアル化によって得られた変数は、元の変数とは何の関係もありませんが、値は同じです。
pickle
シリアル化は Python でのみ利用可能であり、異なるバージョンは相互に互換性がありません。
JSON
異なるプログラミング言語間の転送に適したシリアライゼーションの標準形式で、標準エンコーディングは UTF-8 を使用します。
- JSON 型の関係
JSON タイプ | パイソン型 |
---|---|
{} | 口述 |
[] | リスト |
弦 | 力 |
int/float | int/float |
真/偽 | 真/偽 |
null | None |
>>> import json
>>> d = dict(name='Aurelius', age=18, score=99)
>>> json_str = json.dumps(d)
>>> json_str
'{"name": "Aurelius", "age": 18, "score": 99}'
>>> json.loads(json_str)
{
'name': 'Aurelius', 'age': 18, 'score': 99}
dumps
/dump
的ensure_ascii
参数可以决定是否统一将返回的str
对象编码为ascii
字符;
JSON 进阶
自定义类的对象不能直接序列化,需要实现dumps
/dump
的default
参数对应的方法,将该对象转化成dict
对象;
json.dumps(o, default=object2dict)
通常class
都有__dict__
属性,存储着实例的变量(定义了__solts__
除外),因此可以直接如此调用;
json.dumps(o, default=lambda o: o.__dict__)
loads
/load
在反序列化自定义类型时也需传入object_hook
相应方法,将dict
对象转化为自定义类型的对象;
json.loads(json_str, object_hook=dict2object)
2. 正则表达式
用一种描述性的语言给字符串定义一个规则,用这种规则匹配字符串;
描述符 | 作用 | 示例 |
---|---|---|
\d | 匹配数字 | ‘00\d’ 匹配 ‘007’ |
\w | 字母或数字 | ‘\w\w\d’ 匹配 ‘py3’ |
. | 任意字符 | ‘py.’ 匹配 ‘pyc’、‘py!’ |
* | 人一个字符串(包括 0 个) | |
+ | 至少 1 个字符 | |
? | 0 个或 1 个字符 | |
{n} | n 个字符 | ‘\d{3}’ 匹配 ‘010’ |
{n,m} | n ~ m 个字符 | ‘\d{3,8}’ 匹配 ‘1234567’ |
\ | 转义字符 | ‘\d{3}-\d{3,8}’ 匹配 ‘010-12345’ |
\s | 空格、空位符 |
进阶
描述符 | 作用 | 示例 |
---|---|---|
[] | 表示范围 | ‘[0-9a-zA-Z_]’ 匹配任意一个数字、字母或下划线 |
A|B | 匹配 A 或 B | |
^ | 行的开头 | ‘^\d’ 表示以数字开头 |
$ | 行的结束 | ‘\d$’ 表示以数字结束 |
re 模块
Python 字符串本身用\
转义,正则表达式也用\
转义,在拼写正则表达式时使用r
前缀可以忽略掉 Python 本身字符串的转义;
match
>>> import re
>>> re.match(r'^\d{3}\-\d{3,8}$', '010-12345')
<re.Match object; span=(0, 9), match='010-12345'>
>>> re.match(r'^\d{3}\-\d{3,8}$', '010 12345')
>>>
当匹配成功时,返回一个 Match 对象,否则返回 None;
split
>>> re.split(r'\s+', 'a b c')
['a', 'b', 'c']
>>> re.split(r'[\s\,\;]+', 'a,b;; c d')
['a', 'b', 'c', 'd']
通过模式分割字符串,返回分割的数组;
group
>>> m = re.match(r'^(\d{3})-(\d{3,8})$', '010-12345')
>>> m
<re.Match object; span=(0, 9), match='010-12345'>
>>> m.group(2)
'12345'
>>> m.group(1)
'010'
>>> m.group(0)
'010-12345'
通过()
提取分组子串,group(0)
表示匹配的全部字符串,group(n)
表示第 n 个子串;
贪婪匹配
匹配尽可能多的字符
>>> re.match(r'^(\d+)(0*)$', '102300').groups()
('102300', '')
>>> re.match(r'^(\d+)(0+)$', '102300').groups()
('10230', '0')
正则匹配默认是贪婪匹配,想要非贪婪匹配(尽可能少匹配),在\d+
后加?
;
>>> re.match(r'^(\d+?)(0*)$', '102300').groups()
('1023', '00')
编译
re
模块执行步骤:
- 编译正则表达式,不合法则报错;
- 用编译后的正则表达式匹配字符串;
- 预编译
>>> import re
>>> re_telephone = re.compile(r'^(\d{3})-(\d{3,8})$')
>>> re_telephone.match('010-12345').groups()
('010', '12345')
>>> re_telephone.match('010-8086').groups()
('010', '8086')
匹配简单邮箱
def is_valid_email(addr):
if re.match(r'(^[a-zA-Z\.]+)\@(gmail|microsoft)\.com$', addr):
return True
else:
return False
匹配带名称邮箱,提取名称
def name_of_email(addr):
# 提取邮箱前缀
m = re.match(r'^([a-zA-Z\d\s\<\>]+)\@(voyager|example)\.(org|com)$', addr)
if not m:
return None
# 提取前缀中 <> 里面的名称,若不存在,则取全名
m = re.match(r'^\<([a-zA-Z\s]+)\>[\s]+[a-zA-Z\d]+|([a-zA-Z\d]+)$', m.group(1))
return m.group(1) if m and m.group(1) else m.group(2)
- 上一篇:「Python 基础」错误、调试与测试
- 下一篇:「Python 基础」进程与线程
PS:感谢每一位志同道合者的阅读,欢迎关注、评论、赞!