print関数のつかいかた


:::note warn
Python3.12 での情報です
今後様々な改善がなされていくと考えられます
:::


## Print文完全形
```python
print(*objects, sep=' ', end='\n', file=None, flush=False)
```
オプションがそれぞれ明記されていない時、
sepは` ` (Space) endは`\n`(改行)、fileは`None`、flushは`Flase`となっている
なお、`*objects`の`*`は、アンパック演算子と呼ばれる。 

### アンパック演算子
`*objects`によって、objectsの内容を分解することができる
```python
print(*range(3))
# 0 1 2

print(*"abc")
# a b c

def f(x, y , z):
    return x**2+y*x+z
a = 1, 1, 2
print(f(*a))
# 4

def f(x, y, z):
    return x ** 2 + y * x + z

a = [1, 1, 2]
print(a)
print(f(*a))
# [1, 1, 2]
# 4
```

## 引数解説
### sep
`print(a, b, c, d, e, sep="--")` で、a,b,c,d,eのそれぞれの要素を表示するとき、その要素間に`--`を入れ込むという意味になる
また、`sep`は、オブジェクト同士の連結に使う文字列を指定することができるため、1つのオブジェクトに対して`sep`を適用しても何も起きない
```python
a = "h"
b = "e"
c = "l"
d = "l"
e = "o"
print(a, b, c, d, e)
> h e l l o

print(a, b, c, d, e, sep="")
> hello

print(a, b, c, d, e, sep="_")
> h_e_l_l_o

# 下のような"*"と組み合わせた使い方もできる
f = "helloworld"
print(*f, sep="_")
> h_e_l_l_o_w_o_r_l_d

# ただし、
a = "h"
b = "e"
c = "l"
d = "l"
e = "o"
print(a+b+c+d+e, sep="_")
> hello
# なぜならば、sepは、オブジェクト間の連結に使う文字列を指定する機能であり、
# "+"で足し合わせた文字列は1つのオブジェクトになっているため、sepは適用されない
# (その証拠に...)
g = "Hello World"
print(g, sep="_")
> Hello World
```
### end
これは簡単
文字列出力の後に何を出力するかを指定する
```python
print("Hello")
print("World")
> Hello
> World
print("Hello", end=" ")
print("World")
> Hello World
```
### file
ノーマルではNoneになっていて、shellに出力されている
何かしらのパッケージを利用して出力先のファイルパスを指定し、そこにprintさせる
`with open`を使うことが多いと思う
```python
file_path = 'output.txt'
# with open(file_path, w)のwは、writeの権限を与える、という意味
# w : 書き込み, r : 読み込み, a : 末尾に書き込み
# r+ : 両用, w+ : 既存ファイルの読み書きを上書き, a+ : ファイルの読み書きを末尾追加(ファイルが存在しなければ、新規作成)
with open(file_path, 'w') as f:
    print(*"Hello World", sep="_", end="", file=f)

> 
# shellに対する出力なし
```
```output.txt
H_e_l_l_o_ _W_o_r_l_d
```

### flush
`flush=True` にするとバッファからの書き込みではなく、出力が即時書き込みになる

<details><summary>flushを使わない場合の長所</summary>

処理速度が速い：バッファリングにより、I/O操作が最適化されます。
システムリソースの使用が少ない：頻繁なI/O操作を避けられます。
</details>

<details><summary>flushを使わない場合の短所</summary>

リアルタイムの更新がない：ユーザーは処理の進捗を確認できない。
予期せぬエラーやクラッシュ時にデータが失われる可能性がある：バッファ内のデータがディスクに書き込まれる前に問題が発生した場合。
</details>

<details><summary>flushを使う場合の長所</summary>

リアルタイムの更新：ユーザーに即時フィードバックを提供できる。
データの即時性：重要なデータがすぐに書き込まれることを保証する。
デバッグが容易：問題が発生した時点での正確な状態を把握しやすい。
</details>

<details><summary>flushを使う場合の短所</summary>

処理速度が遅くなる可能性がある：特に頻繁なI/O操作を行う場合。
システムリソースの使用が増える：特に大量のデータを扱う場合。
</details>

比較にどーぞ



```python
import sys
import time


def output_with_flush():
    start_time = time.time()
    for i in range(1000):
        print(f"\rProcessing: {i}/1000", end="", flush=True)
        time.sleep(0.001)
    end_time = time.time()
    print(f"\nTime taken with flush: {end_time - start_time:.4f} seconds")


def output_without_flush():
    start_time = time.time()
    for i in range(1000):
        print(f"\rProcessing: {i}/1000", end="")
        time.sleep(0.001)
    end_time = time.time()
    print(f"\nTime taken without flush: {end_time - start_time:.4f} seconds")


print("Running with flush:")
output_with_flush()

print("\nRunning without flush:")
output_without_flush()

print("\nNow, let's force a flush at the end of the without_flush version:")
start_time = time.time()
for i in range(1000):
    print(f"\rProcessing: {i}/1000", end="")
    time.sleep(0.001)
sys.stdout.flush()
end_time = time.time()
print(f"\nTime taken with final flush: {end_time - start_time:.4f} seconds")

```
</details>

***

**参考**

https://docs.python.org/ja/3/library/functions.html#print