引言
眾所周知,打算法競賽最頻繁使用的語言是 C++。然而,對於那些不卡復雜度的題目,可以考慮使用 Python 編寫(因為 Python 真的好寫)。
本文將簡單地介紹一些 Python 使用技巧和語法糖。
一些技巧
框架
初學 Python 時,由於 Python 著名的交互性,大家可能會直接逐行編寫 Python 語句。然而,這樣便於代碼邏輯組織和函數的編寫。如同 C++ 中的 int main() { ... } 一樣,Python 中也可以構建類似的程序框架。
def foo():
    print("Hello")
def main():
    foo()
if __name__ == '__main__':
    main()
 
        最后一句的意義為:
- 當執行本文件時,正常運行 
main()函數; - 當從外部調用文件時,可以導入本文件中編寫的函數,而不執行 
main()函數。 
這樣,保證了編寫的代碼既可以執行,又可以外部調用。
全局變量
Python 中的全局變量需要在函數中用 global 命令聲明后才能進行修改,例子如下。
x = 0
def foo():
    x += 10
def bar():
    global x
    x += 10
def main():
    foo()
    bar()
 
        調用 foo() 會拋出 UnboundLocalError: local variable 'x' referenced before assignment。
具體原因參看 Python中的global關鍵字,你了解嗎
重定向輸入輸出
如同 C++ 中的 freopen() 函數,Python 中也有將標准 I/O 重定向到文件的命令。
import sys
sys.stdin = open(r'hack.txt', 'r')
sys.stdout = open(r'hack.out', 'w')
 
        這樣就可以把樣例放到 hack.txt 中,輸出到 hack.out 中了。
_debug_
Python 中有一個內置常量 __debug__,其默認值為 True。當編譯命令中開啟 -O 時,其值為 False。
我用這個技巧來替代 C++ 中的 #if(n)def ... #else ... #endif 語句(不同於 C/C++,Python 沒有預編譯過程,故也沒有完全對應的命令)。
默認 OJ 是不會開啟 -O 命令的(不過還是在提交前查看 OJ 對應的語言編譯命令說明為好),所以我們可以定義一個常量
LOCAL = not __debug__ # True if compile option '-O'
 
        這樣我們在本地運行開啟 -O 命令之后,就可以使用
if LOCAL:
    print("Hello")
 
        來指定本地編寫時執行但 OJ 不執行的命令。
例如將上一節的重定向可以加上這句,就不用擔心由於忘記注釋掉重定向而收獲一發 RE 了
斷言
Python 的斷言關鍵字與 C++ 相同,都是 assert;在拋出 AssertionError 時可以指定報錯信息。例子如下:
a, b = 1, 2
assert a == b, f'{a} != {b}'
 
        終端會拋出 AssertionError: 1 != 2
隨機數生成器與對拍
隨機數生成
例如生成 A+B problem 的隨機數據。生成的數據直接輸出到 hack.txt 中。
import sys
from random import *
# seed(12345)
sys.stdout = open(r'hack.txt', 'w')
n = int(1e3)
print(n)
for i in range(n):
    a = randint(-1e9, 1e9)
    b = randint(-1e9, 1e9)
    print(a, b)
 
        對拍
檢驗兩個程序是否有相同輸出,構造樣例和 debug 時常用。
不一定是兩個
*.exe,只要是有輸入輸出的東西都可以拍。
from os import system
while True:
    system("python3 randgen.py")
    system("true.exe < ../hack.txt > true.txt")
    system("false.exe < ../hack.txt > false.txt")
    if system("fc true.txt false.txt"):
        system("pause")
 
        更進階的用法,考慮使用 洛谷推出的對拍工具 CYaRon,使用 pip 直接安裝即可。
代碼運行計時
使用標准庫中的 time 模塊
import time
if __name__ == '__main__':
    T1 = time.time()
    main()
    T2 = time.time()
    print("Runtime: %.3f s." % (T2 - T1), file=sys.stderr)
 
        print() 的 kwg 中指定 file=sys.stderr 使得運行時間在終端輸出。這樣當重定向輸入輸出時,該語句不受影響。
不過通常來講,選擇使用 Python 編寫時,基本都是對運行時間要求不高的題目。
模板
貼上自用的 Python 模板
#!/usr/bin/python3
import sys
import os
import time
from functools import reduce
from math import *
LOCAL = not __debug__  # True if compile option '-O'
def main():
    pass
if __name__ == "__main__":
    T1 = time.time()
    if LOCAL:
        sys.stdin = open(r"hack.txt", "r")
        sys.stdout = open(r"hack.out", "w")
    t = int(input())  # 1
    for i in range(t):
        print(f"Case #{i+1}:", end=' ')
        main()
    T2 = time.time()
    print("Runtime: %.3f s." % (T2 - T1), file=sys.stderr)
 
        我的賽前模板倉庫
git clone git@github.com:RivTian/Python-Content.git
 
        參考
- Python 3 官方文檔 - 中文 https://docs.python.org/zh-cn/3/
 - Python 中的 global 關鍵字,你了解嗎?https://zhuanlan.zhihu.com/p/111284408
 
