---
# System prepended metadata

title: Python note

---

Python note
===

```python=
exit(0) 強制離開

print(f'{(7.0/2.0):.2f}')
or
print('{:.2f}'.format(7.0/2.0))
輸出自定義浮點數

if __name__ == '__main__':
此區塊只有當作檔案時候才會執行，當作模組不會執行。

print('hello\nworld')
顯示包含跳脫字元

print(r'hello\nworld')
忽略跳脫字元

type()看型別
id()  看記憶體位置
chr() 數字轉字元
ord() 字元轉數字
len() 看長度
int() 轉成整數
input() 輸入
print() 顯示

as		關鍵字代表 alias

字串
a = a[::-1]     做 reverse 反向字串

字串內取代 replace
a = a.replace('a', 'b')

[] 代表 list 的意思，可以增加跟移除
.append()			 增加
.append([x, y, z])	 增加一個 list 到 list 內
.extend([x,y])       增加 x 和 y 元素到 list 內
.insert(i, x)		 指定第某個位置插入
.remove(x)			 移除某個值 
.pop()				 移除最後一個
.pop(N)				 第N個移除
.sort()				 排序
.sort(reverse = True)     反轉排序
.sort(key = str.upper)    大寫排序
.sort(key = str.lower)    小寫排序
.reverse()            反轉順序
.index(N)            指出第N個
.count(x)            計算出共有幾個

刪除重覆的
list2 = []
for i in list1:
    if i not in list2:
        list2.append(i)

max(list)			求最大的
min(list)			求最小的
sum(list)			求和
any(list)			如果都是 0 才會 False
all(list)			有一個 0 的就會 False

將 list 都轉成 int
line = list(map(int, line))
或
line = [int(i) for i in line]


注意:
map(function, iterable) 將 function 用於 iterable 的每個元素

from collections import namedtuple
Data = namedtunple('Data', ['attribute1', 'attribute2', 'attribute3'])
storage = Data('intel', 'AMD', 'Apple')
print(Data.attribute1)

set([1,2,3]) = {1,2,3} 是 set 的兩種表達方式，沒有順序而且是唯一性

sorted()	排序，可以對 list 跟 dict 使用
sorted([1,2,3], reverse= True)		逆向排序
new_list = sorted(my_list, key = max)	小到大排序

set_a.intersection(set_b)			交集的列出
set_a.union(set_b)					所有的列出
set_a.difference(set_b)				只有遮罩
set_a.symmetric_difference(set_b)	遮罩後並加上沒有被遮罩的

dict_test = {
	'key':value,
	'key':value
}

dict_test = dict(name='XX', grade='OO')

dict_test['key'] = value	新增或異動
del dict_test['key']		刪除 dictionary 的一筆資料

for i in dict_test:
    print(f'{i} | {dict_test[i]}')

sort key 印出 key 跟 value (dictionary)

for i in sorted(dict_test):
    print((i, dict_test[i]), end = ' ')         
或
[(k, d[k]) for k in sorted(d.keys())]

sort value 印出 key 跟 value (dictionary)
print(sorted(dict_test.items(), key = lambda token:(token[1], token[0])))    
或
[v for v in sorted(d.values())]

for i in line:
	token = i.split(':')
	dict_test[token[0]] = token[1]    做出一個 dict

test = dict_test.get(key) 用 dict 取值
test = dict_test[key]

for key in data:          用 dict 做統計，get 找 key 如果沒有就回傳第二個參數
    dict_test[key] = dict_test.get(key, 0) + 1

print(f'{ToStringPart} is test') 將 {} 內的東西變成字串
或是使用運算
print(f'{2*2=}')    顯示出 2*2=4

name = 'apple'
print(f'{names}')	顯示出 string
number = 10
print(f'{number:d}')	顯示出十進制
print(f'{number:b}')	顯示出二進制
print(f'{number:x}')	顯示出十六進制小寫
print(f'{number:X}')	顯示出十六進制大寫
print(f'{number:e}')	顯示出科學表示進制
print(f'{number:f}')	顯示出浮點數
print(f'{number:.2f}')	顯示出浮點數小數後兩位
print(f'{number:03d}')	顯示出十進制三位

if z < x < y:	在 python 可以這樣設定，不需要用 and 去作連接
if a and b:	    在 python 內，邏輯用小寫 and or not
if a or b:
if not a:

my_bool = True	在 python 內，布林使用第一字大寫
my_bool = False

membership 以 list 為例子
apple_list = ['macOS', 'iOS', 'iPadOS']
if 'iOS' in apple_list:
	print("Yes")

membership 以 字串 為例子
str1 = 'apple is good'	
if 'bird' in str1:
	print('YES')

    
membership 只能找 key 不能找 value
my_dict = {}
my_dict = {'A': 1, 'B':2, 'C':3}			
if 3 in my_dict:
	print("YES")

可以用 is 或 is not 去判斷，通常使用 id() 去判斷
if x is y:									
if x is not z:

三目運算
my_var = exp1 if (condition) else exp2		

random.seed(value)      用 value 產生亂數

random.randint(0, 5)    產生亂數，範圍是 0 到 5
num *= x + y    代表 num = num * (x + y)

for loop:
for var in container:	普通 for loop

for c in container:		for loop 用於 dict
	print(f'{c} have value {container[c]}')

reversed()				反轉 container 順序

import edit_distance

字元變化量少於 2。
for name in name_list:
	if edit_distance.distance(name, input_name) < 2:	
		print("less than 2")

----------------------------
def distance(a,b):
    '''
    Calculates the Levenshtein distance between a and b.
    '''
    n, m = len(a), len(b)
    if n > m:
        # Make sure n <= m, to use O(min(n,m)) space
        a,b = b,a
        n,m = m,n

    current = range(n+1)
    for i in range(1,m+1):
        previous, current = current, [i]+[0]*n
        for j in range(1,n+1):
            add, delete = previous[j]+1, current[j-1]+1
            change = previous[j-1]
            if a[j-1] != b[i-1]:
                change = change + 1
            current[j] = min(add, delete, change)

    return current[n]
----------------------------
        
        
        
nums = [4, 8, 10]

for index in range(len(nums)):
	value = nums[index]
	print(f'{index}:{value}')

for value in nums:
	index = nums.index(value)
	print(f'{index}:{value}')

for (index, value) in enumerate(nums):
	print(f'{index}:{value}')

str = 'appleisgood'
x = str[5:8]			x 就是 isg

print(f'{"hello":20}')	就是格式化 20 個空格，只放入 hello，左邊(文字靠左)
print(f'{50:20}')		就是格式化 20 個空格，只放入 50，右邊(數字靠右)

print(f'{"hello":<20}')	就是格式化 20 個空格，只放入 hello，靠左對齊
print(f'{"hello":>20}')	就是格式化 20 個空格，只放入 hello，靠又對齊
print(f'{"hello":^20}')	就是格式化 20 個空格，只放入 hello，至中對齊

print(f'{score:0>4}')	格式化後，靠右，顯示四個單位，其餘空間補0
print(f'{score:*>4}')	格式化後，靠右，顯示四個單位，其餘空間補*

str.find('xxx')			找目標位於第幾個
str.find('xxx', 2)		從第二個位置開始找目標
str.find('xxx', 2, 4)	從第二個位置開始找目標，停於第四個位置
str.rfind('xxx')		從尾部找
str.count('xxx')		計算有幾個目標

str.isalnum()				是否字母或數字
str.isdigit()				是否數字
str.islower()				是否小寫
str.isupper()				是否大寫
str.isspace()				是否空白
str.startswith()			是否以xxx開始
str.endswith()				是否以xxx結束

str.capitalize()			首字母大寫
str.lower()					都小寫
str.upper()					都大寫
str.strip()					空格移除
str.strip('\n')                         移除換行
str.title()					第一個字

str.split()					以空白分割成 list
str.split('#')				以 # 分割成 list
str = '@'.join(list)		將 list 間隔用 @ 黏起來成一個字串

str = ''
for x in list:				用 for loop 把 list 內串成一個字串
	str += x


def test_this_part():		用於測試，傳出 None
	pass

def neet_to_do():			用於測試錯誤，會停住
	raise NotImplementedError


def get_name():	
	global the_name    # global 關鍵字，就是讓它成為全域變數
	the_name = input('Enter the name')


print(globals())			全域變數的 namespace
print(locals())				區域變數的 namespace


def modify(num_list):
	pass

modify(my_list[:])	代表傳入一個 list 的 copy，這樣不會影響到原本的 list 值

def test_this(title, year, author):

支援參數指定，這樣可以不用按照順序
test_this(year = 2021, author = "Eric", title = "UCLA")	

預設開一個 list，之後用預設會延續上一個
def append_list(value, my_list = []):

預設開一個空的，之後要指定才會延續上一個
def append_list(value, my_list = None):
	if my_list == None:
		my_list = []

args 參數變成一個 list container 來使用
def print_a(bread, meat, *args):
print_a('wheat', 'ham', 'apple', 'tomato')

kwargs 參數變成一個 dictionary container 來使用
def print_b(bread, meat, **kwargs):
print_b('wheat', 'ham', sauce1='test1', sauce2='test2')

return a, b		回傳一個 tuple a, b
return (a, b)	回傳一個 tuple a, b 這樣比較推薦，看起來比較清楚
return [a, b]	回傳一個 list a, b

docstrings	使用方法，單行就是 """   """ 同一行
			多行就是，結尾會留一行空白。

help()		會將 docstrings 列出來

my_list[5] = [10]	在 list 第五個位置放上 10

my_list[len(my_list):] = [10] 
就是在 list 最後自訂一個值，自訂的值外面是有 [] 包住。

list2 = list1			兩個指向同一個物件，會互相干擾。
list2 = list1[:]		list2 是複製 list1 物件，互相不干擾
list2 = list1.copy()	list2 是複製 list1 物件，互相不干擾

new_list = [expression for loop_variable_name in iterable]

new_list = [expression for loop_variable_name in iterable if condition]

import sys

program = sys.argv[0]
name = sys.argv[1]
age = int(sys.argv[2])


argparse and getopt 是參數研究

my_dict = {}
my_dict.clear()	清除所有
my_dict.setdefault('key', 'value')    新增
my_dict.get(key, default)    查 value，查不到回傳 default (通常是設為 0)
my_dict.update({'key':'value'})	更新 key value，如果沒有就新增
my_dict.pop('key', default)	移除 key，查不到回傳 default (通常是 0)

my_dict.items()	    回傳 key, value
my_dict.keys()		回傳 key
my_dict.values()	回傳 value
my_dict['key']
del my_dict['key']
my_dict2 = my_dict.copy()

my_dict = {'a':1, 'b':2}
if my_dict.__contains__('a'):    會顯示出 yes，如果改成 'c' 則會顯示出 no
    print('Yes')                    
else:
    print('No')

class Time:				建立一個類雛形與基礎的 constructor
	gmt_offset = 0

	def __init__(self):
		self.hours = 0
		self.minutes = 0

	def __init__(self, hours = 0, minutes = 0):	初始化的 constructor
		self.hours = hours
		self.minutes = minutes

	def __str__(self):		設計給 print 使用
		return (f'{self.hours} and {self.minutes}')

time1 = Time()	    使用一個物件，用類形成
time1.hours = 7
time1.minutes = 8


Time.gmt_offset = -8 這個會讓之後所有用到 Time() 物件有影響

print(time1) 直接顯示這個物件的字串

重載使用 overload

def __lt__(self, other):			(<)

def __le__(self, other):			(<=)

def __gt__(self, other):			(>)

def __ge__(self, other):			(>=)

def __eq__(self, other):			(==)

def __ne__(self, other):			(!=)


try:	這樣可以避免一些問題。
	BLOCK
exception:
	BLOCK


try:	這樣可以避免一些問題。
	BLOCK
exception error_type1:
	BLOCK
exception error_type2:
	BLOCK
exception error_type3:
	BLOCK
exception:
	BLOCK

--------------------
def get_age():
    age = int(input())
    # TODO: Raise excpetion for invalid ages
    if age < 18 or age > 75:
        raise ValueError('Invalid age.')
    return age

# TODO: Complete fat_burning_heart_rate() function
def fat_burning_heart_rate(age):
    heart_rate = (220 - age) * 0.7
    return heart_rate

if __name__ == "__main__":
    # TODO: Modify to call get_age() and fat_burning_heart_rate()
    #       and handle the exception
    try:
        age = get_age()
        print(f'Fat burning heart rate for a {age} year-old: {fat_burning_heart_rate(age):.1f} bpm')
    except ValueError as e:
        print(e)
        print('Could not calculate heart rate info.')
--------------------




try:	這樣可以避免一些問題。
	BLOCK
exception (error_type1, error_type2):
	BLOCK
exception (error_type3, error_type4):
	BLOCK

Error type: https://docs.python.org/3/library/exceptions.html

EOFError: end of file
KeyError: dictionary key
ZeroDivisionError: divide by zero
ValueError: invalid value
IndexError: index out of bounds
AttributeError: does not exist in an imported module


try:
	weight = int(input())
	if weight < 0:
		raise ValueError('xxx')	自訂文字，可以把 raise 想成 goto

except ValueError as e:
	print(e)				    顯示自訂的文字


設定在方法內

def get_weight():
	weight = int(input())
	if weight < 0:
		raise ValueError('Invalid weight')
	return weight

try:
	weight = get_weight()		方法出現問題會直接跳出來
	print(weight)

except ValueError as e:
	print(e)

使用最後 finally，一定會執行的

try:
	BLOCK
except:
	BLOCK
finally:
	BLOCK


read file 讀檔案配合 try 跟 except

1.txt:
100
200
300

1.py:
nums = []
rd_nums = -1
my_file = input('Enter file name: ')

try:
    print('Opening', my_file)
    rd_nums = open(my_file, 'r')        # Might cause IOError

    for line in rd_nums:
        nums.append(int(line))          # Might cause ValueError
except IOError:
    print('Could not find', my_file)
except ValueError:
    print('Could not read number from', my_file)
finally:
    print('Closing', my_file)
    if rd_nums != -1:
        rd_nums.close()
    print('Numbers found:', ' '.join([str(n) for n in nums]))

客製化 exception type:
1.py:
class LessThanZeroError(Exception):   客製化的 exception
    def __init__(self, value):
        self.value = value

my_num = int(input('Enter number: '))

if my_num < 0:
    raise LessThanZeroError('my_num must be greater than 0')
else:
    print('my_num:', my_num)


偷懶的方法就是
class LessThanZeroError(Exception):  客製化的 exception
    def __init__(self, value):
        pass


import MODULE
from NAME import MODULE

md5 範例:
from hashlib import md5, sha1

text = input("Enter text to hash ('q' to quit): ")

while text != 'q':
    algorithm = input('Enter algorithm (md5/sha1): ')
    if algorithm == 'md5':
        output = md5(text.encode('utf-8'))
    elif algorithm == 'sha1':
        output = sha1(text.encode('utf-8'))
    else:
        output = 'Invalid algorithm selection'
    print('Hash value:', output.hexdigest())

    text = input("\nEnter text to hash ('q' to quit): ")


測試是 module 或是 script

if __name__ == "__main__":
    # file executed as a script

if __name__ == "MODULE_NAME"
    # file executed as a module

https://docs.python.org/3/library/datetime.html
https://docs.python.org/3/library/random.html
https://docs.python.org/3/library/copy.html
https://docs.python.org/3/library/time.html
https://docs.python.org/3/library/math.html
https://docs.python.org/3/library/os.html
https://docs.python.org/3/library/sys.html
https://docs.python.org/3/library/pdb.html
https://docs.python.org/3/library/urllib.html


date practice:
import datetime

# Create a new date object representing the current date (May 30, 2016)
today = datetime.date.today()

days_from_now = int(input('Enter number of days from now: '))

# Create a new timedelta object that represents a difference in the 
# number of days between dates.
day_difference = datetime.timedelta(days = days_from_now)

# Calculate new date
future_date = today + day_difference

print(days_from_now, 'days from now is', future_date.strftime('%B %d, %Y'))


deck:
import random

# Create a shuffled card deck with 4 suites of cards 2-10, and face cards
deck = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K', 'A'] * 4
random.shuffle(deck)

num_drawn = 0
game_over = False
user_input = input("Press any key to draw a card ('q' to quit): ")
while user_input != 'q' and not game_over:

    # Draw a random card, and remove card from the deck
    card = random.choice(deck)
    deck.remove(card)
    num_drawn += 1

    print('\nCard drawn:', card)

    # Game is over if an ace was drawn
    if card == 'A':
        game_over = True
    else:
        user_input = input("Press any key to draw a card ('q' to quit): ")

if user_input == 'q':
    print("\nGame was quit")
else:
    print(num_drawn, 'card(s) were drawn to find an ace.')


檔案讀取:
f = open('FILE')        打開檔案成一個物件
text = f.read()         讀檔案成一個字串
text = f.read(512)      讀檔案上到 512 bytes
text = f.readline()     讀檔案只讀一行字串
text = f.readlines()    讀檔案成一個 list 的字串
print(text)             印出讀到的檔案
f.close()               關閉檔案

----
filename = input()
b1 = input()
b2 = input()

data = open(filename)
lines = data.readlines()

for i in lines:
    i = i.replace('\n', '')
    if i >= b1 and i <= b2:
        print(i)
    
data.close()
----


f = open('FILE')        沒有參數，預設是 r
text = f.readlines()
for x in text:
    print(x, end='')
f.close()

寫入:
f = open('FILE', 'w')
f.write('Example\n')
f.close()

寫入必須是字串，所以數字或是浮點數就要用 str() 去變成字串去寫入
import os
f = open('FILE', 'w')
f.write('Please\n')
f.flush()
os.fsync(f.fileno())      通常 f.flush() 和 os.fsync(f.fileno()) 一起搭配
f.close()

# build a path string using current OS path separator
file_path = os.path.join('storage','log.txt')

# build a tuple (head and tail) means (path, fileName)
print(os.path.split(file_path))

# whether file exists
if (os.path.exists(file_path)):
    
# whether that is a file or directory
if (os.path.isfile(file_path)):
    
# bytes
print(os.path.getsize(file_path))               

for dirname, subdirs, files in os.walk(path):
dirname 就是目前目錄
subdirs 子目錄
files   檔案

f = open('FILE', 'rb')                  以二進制讀取

#creates a sequence of bytes by encoding the string using ASCII
my_str = b'this is a book'
bytes('this is a book', 'ascii')


import struct                           struct.pack 輸入數字轉2進制
print(struct.pack('>h', 5))             b'\x00\x05'             靠右
print(struct.pack('<h', 5))             b'\x05\x00'             靠左
print(struct.pack('>h', 256))           b'\x01\x00'
print(struct.pack('>hh', 5, 256))       b'\x00\x05\x01\x00'

h: 2 bytes
b: 1 byte
l: 4 bytes
s: a string

print(struct.unpack('>h', b'\x00\x05')) struct.unpack 輸入二進制轉數字
print(repr('\x00\x05'))                 將進制轉成字串，可以輸出，否則無法輸出

command-line:
import sys
import os

if len(sys.argv) != 2:
    print(f'Usage: {sys.argv[0]} input_file')
    sys.exit(1)  # 1 indicates error

print(f'Opening file {sys.argv[1]}.')

if not os.path.exists(sys.argv[1]):  # Make sure file exists
    print('File does not exist.')
    sys.exit(1)  # 1 indicates error

f = open(sys.argv[1], 'r')
# Input files should contain two integers on separate lines

print('Reading two integers.')
num1 = int(f.readline())
num2 = int(f.readline())

print(f'Closing file {sys.argv[1]}')
f.close()  # Done with the file, so close it

print(f'\nnum1: {num1}')

print(f'num2: {num2}')

print(f'num1 + num2: {num1 + num2}')

1.txt:
100
200

with 的功能就是加強版的 open，因為執行完 block 會自動關閉
以前是
f = open(sys.argv[1], 'r+')
現在是
with open(sys.argv[1], 'r+') as f:
    num1 = int(f.readline())
    num2 = int(f.readline())
    result = num1 + num2
    f.write(str(result))

# 此程式結束這區快會自動 close

CSV example (comma separate value files):
讀取 csv 檔
import csv

with open('grades.csv', 'r') as c_file:
    row_num = 1
    data = csv.reader(c_file, delimiter = ',')
    for row in data:
        print(f'row{row_num}:', row)
        row_num += 1


with open('file.csv', 'r') as c_file:
    user_file = csv.reader(c_file, delimiter = ',')
    for data in user_file:
        for i in data:
            print(i)



寫入 csv 檔
import csv

r1 = ['100', '50', '29']
r2 = ['76', '32', '330']

with open('test.csv', 'w') as c_file:
    x = csv.writer(c_file)

    x.writerow(r1)              # 寫入單行
    x.writerow(r2)
    x.writerow('')              # 寫入空行(換行)
    x.writerows([r1, r2])       # 寫入多行，但是用 list 方式寫入


計算 csv 檔
grades.csv:
name,hw1,hw2,midterm,final
Petr Little,9,8,85,78
Sam Tarley,10,10,99,100
Joff King,4,2,55,61

csv_example3.py:
import csv

# Dictionary that maps student names to a list of scores
grades = {}

# Use with statement to guarantee file closure
with open('grades.csv', 'r') as csvfile:
    grades_reader = csv.reader(csvfile, delimiter=',')

    first_row = True
    for row in grades_reader:
        # Skip the first row with column names
        if first_row:
            first_row = False
            continue

        ## Calculate final student grade ##
        name = row[0]

        # Convert score strings into floats
        scores = [float(cell) for cell in row[1:]]
        hw1_weighted = scores[0]/10 * 0.05
        hw2_weighted = scores[1]/10 * 0.05
        mid_weighted = scores[2]/100 * 0.40
        fin_weighted = scores[3]/100 * 0.50
        result = hw1_weighted + hw2_weighted + mid_weighted + fin_weighted
        grades[name] = result * 100

for student, score in grades.items():
    print(f'{student} earned {score:.1f}%')



繼承
derived class or inherit class:
class Item:
    def __init__(self):
        self.name = ''
        self.quantity = 0

    def set_name(self, nm):
        self.name = nm

    def set_quantity(self, qnty):
        self.quantity = qnty

    def display(self):
        print(self.name, self.quantity)


class Produce(Item):  # Derived from Item
    def __init__(self):
        Item.__init__(self)  # Call base class constructor
        self.expiration = ''

    def set_expiration(self, expir):
        self.expiration = expir

    def get_expiration(self):
        return self.expiration

item1 = Item()
item1.set_name('Smith Cereal')
item1.set_quantity(9)
item1.display()

item2 = Produce()
item2.set_name('Apples')
item2.set_quantity(40)
item2.set_expiration('May 5, 2012')
item2.display()
print(f'(Expires:({item2.get_expiration()}))')

-------
class Pet:
    def __init__(self):
        self.name = ''
        self.age = 0

    def print_info(self):
        print('Pet Information:')
        print('   Name:', self.name)
        print('   Age:', self.age)

class Dog(Pet):
    def __init__(self):
        Pet.__init__(self) 
        self.breed = ''
        
    def print_info(self):
        Pet.print_info(self)
        print('   Breed:', self.breed)

my_pet = Pet()
my_dog = Dog()

pet_name = input()
pet_age = int(input())
dog_name = input()
dog_age = int(input())
dog_breed = input()

# TODO: Create generic pet (using pet_name, pet_age) 
#       and then call print_info()
my_pet.name = pet_name
my_pet.age = pet_age
my_pet.print_info()

# TODO: Create dog pet (using dog_name, dog_age, dog_breed) 
#       and then call print_info()
my_dog.name = dog_name
my_dog.age = dog_age
my_dog.breed = dog_breed
my_dog.print_info()
-------

has a 沒有繼承，is a 是有繼承

# 這個就是 has a，child object has a string object
class Child:                        
    def __init__(self):
        self.name = ''
        self.birthdate = ''
        self.schoolname = ''

--------------------------------
# 這個就是 is a，child object is a kind of person
class Person:                       
    def __init__(self):
        self.name = ''
        self.birthdate = ''

class Child(Person):
    def __init__(self):
        Person.__init__(self)
        self.schoolname = ''

多重繼承:
class BMW(vehicle, person):

--------------------------------
class Artist:
    # TODO: Define constructor with parameters to initialize 
    #       instance attributes
    #       (name, birth_year, death_year)
    def __init__(self, name = 'None', birth_year = 0, death_year = 0):
        self.name = name
        self.birth_year = birth_year
        self.death_year = death_year

    # TODO: Define print_info() method. 
    #       If death_year is -1, only print birth_year
    def print_info(self):
        if self.death_year == -1:
            print(f'Artist: {self.name}, born {self.birth_year}')
        else:
            age = self.birth_year}-{self.death_year
            print(f'Artist: {self.name} ({age})')
      
class Artwork:
    # TODO: Define constructor with parameters to initialize 
    #       instance attributes
    #       (title, year_created, artist) # 繼承
    def __init__(self, title='None', year_created=0, artist=Artist()):
        self.title = title
        self.year_created = year_created
        self.artist = artist

    # TODO: Define print_info() method
    def print_info(self):
        self.artist.print_info()
        print(f'Title: {self.title}, {self.year_created}')


--------------------------------
recursive:
def print_num_pattern(num1, num2):
    if num1 <= 0:
        print(num1, end = ' ')
        return
    print(num1, end = ' ')
    print_num_pattern(num1 - num2, num2)
    print(num1, end = ' ')

if __name__ == "__main__":
    num1 = int(input())
    num2 = int(input())
    print_num_pattern(num1, num2)
--------------------------------
sort:
def selection_sort_descend_trace(numbers):
    for i in range(len(numbers) - 1):
        max_num = max(numbers[i:])
        index = numbers.index(max(numbers[i:]))
        tmp = numbers[i]
        
        numbers[i] = max_num
        numbers[index] = tmp
        for j in numbers:
            print(j, end = ' ')
        print()

if __name__ == "__main__":
    nlist = input().split()
    numbers = [int(i) for i in nlist]
    selection_sort_descend_trace(numbers)
--------------------------------
quick sort:
# Global variable
num_calls = 0

# TODO: Write the partitioning algorithm - pick the middle element
#       as the pivot, compare the values using two index 
#       variables l and h (low and high), initialized to the left 
#       and right sides of the current elements being sorted,
#       and determine if a swap is necessary
def partition(user_ids, i, k):
    # Pick middle value as pivot
    midpoint = i + (k - i) // 2
    pivot = user_ids[midpoint]
    
    # Initialize variables
    done = False    
    l = i
    h = k
    while not done:
        # Increment l while user_ids[l] < pivot
        while user_ids[l] < pivot:
            l = l + 1
        # Decrement h while pivot < user_ids[h]
        while pivot < user_ids[h]:
            h = h - 1
    
        # If there are zero or one items remaining,
        #    all items are partitioned. Return h
        if l >= h:
            done = True
        else:
            # Swap user_ids[l] and user_ids[h], update l and h 
            temp = user_ids[l]
            user_ids[l] = user_ids[h]
            user_ids[h] = temp
            l = l + 1
            h = h - 1
    return h
    
# TODO: Write the quicksort algorithm that recursively 
#       sorts the low and high partitions.
#       Add 1 to num_calls each time quisksort() is called
def quicksort(user_ids, i, k):
    global num_calls
    num_calls += 1
    
    # Base case: If 1 or zero elements, partition is already sorted
    if i >= k:
       return
 
    # Partition the list. Value j is the location of last
    #   element in low partition
    j = partition(user_ids, i, k)
 
    # Recursively sort low and high partitions
    quicksort(user_ids, i, j)
    quicksort(user_ids, j + 1, k)
 
    return

if __name__ == "__main__":
    user_ids = []
    user_id = input()
    while user_id != "-1":
        user_ids.append(user_id)
        user_id = input()
        
    # Initial call to quicksort 
    quicksort(user_ids, 0, len(user_ids) - 1)
    
    # Print number of calls to quicksort
    print(num_calls)
    
    # Print sorted user ids
    for user_id in user_ids:
        print(user_id)
--------------------------------
remove duplicate:
mylist = ["a", "b", "a", "c", "c"]
mylist = list(dict.fromkeys(mylist))
print(mylist)
--------------------------------
def all_permutations(permList, nameList):
    size = len(nameList)

    if size == 0:
        for i in permList:
            print(i, end = ' ')
        print()
    else:
        for i in range(size):
            newPerm = permList.copy()
            newPerm.append(nameList[i])
            newName = nameList.copy()
            newName.pop(i)
            all_permutations(newPerm, newName)

if __name__ == "__main__":
    nameList = input().split()
    permList = []
    all_permutations(permList, nameList)
--------------------------------
import itertools as its             # 用現成的工具

data = list(its.permutations([1,2,3]))

for i in data:
    for j in list(i):
        print(j, end = ' ')
    print()
--------------------------------
unittest

方法                        檢查項目
assertEqual(a, b)           a == b
assertNotEqual(a, b)        a != b
assertTrue(x)               bool(x) is True
assertFalse(x)              bool(x) is False
assertIs(a, b)              a is b
assertIsNot(a, b)           a is not b
assertIsNone(x)             x is None
assertIsNotNone(x)          x is not None
assertIn(a, b)              a in b
assertNotIn(a, b)           a not in b
assertAlmostEqual(a, b)     round(a - b, 7) == 0 by default. 
# assertAlmostEqual(first, second, places = 7, msg = None, delta = None)
assertGreater(a, b)         a > b
assertGreaterEqual(a, b)    a >= b
assertLess(a, b)            a < b
assertLessEqual(a, b)       a <= b

密技:
進制轉換
int('string', base)

a = 79
bin_a = bin(a)
print(bin_a)                0b1001111
print(int(bin_a, 2))        79

oct_a = oct(a)
print(oct_a)                0o117
print(int(oct_a, 8))        79

hex_a = hex(a)
print(hex_a)                0x4f
print(int(hex_a, 16))       79

---
from math import factorial
factorial(10)
---
from math import sqrt
sqrt(100)
---
from time import sleep
sleep(10)
---
from math import pi
pi
---
def isprime(num):
    for n in range(2, sqrt(num) + 1):
        if num % n == 0:
            return False
    return True
---
ff = lambda a, b, c, d: a * b * c * d
相當於
def ff(a, b, c, d):
    return a * b * c *d

print(ff(1,2,3,4))

```