Try   HackMD

PYTHON and Discord Bot Tutorial

PYTHON 基礎語法

Prior Knowledge

  • PYTHON 的執行是直譯器(依照程式碼一行一行依序執行)。
  • 執行環境:IDLEAnaconda 等。

Beginning

print('hello, world')

print() 是輸出函數,
'hello, world' 是一字串型態的參數。

print(100)

100 是一整數型態的參數。

Type and Variable

print(type('hello, world')) # <class 'str'> print(type(123)) # <class 'int'>

變數型態

  • intinteger 整數型態。
  • strstring 字串型態,以 "" 或是 '' 包圍字串。
  • float : 小數型態(浮點數型態)。
  • boolboolean 布林值型態,True 代表 1False 代表 0
  • NoneType :沒有型態。
  • complex :複數型態,以 A+Bj 表示。

算術運算子

  • + 加法運算子: int, str, float, bool, complex
  • 減法運算子: int, float, bool, complex
  • 乘法運算子: int, str, float, bool, complex
  • / 除法運算子: int, float, bool, complex
  • // 整數除法運算子: int, float, bool, complex
  • % 餘數運算子: int, float, bool
  • ∗∗ 指數運算子: int, float, bool, complex

用法

  1. 字串形態的 + 加法運算僅限於兩字串形態相加,若「字串 + 整數」或「整數 + 字串」(整數可替換為其它形態),會發生執行錯誤。
print('hello, world' + 100) # TypeError: can only concatenate str (not "int") to str
  1. 字串形態的 乘法運算僅限於「字串 整數」或是「整數 字串」(只能整數)。
print('hello, world' * 2) # 意同於 print(2 * 'hello, world') # hello, worldhello, world
print('hello, world' * 2.5) # TypeError: can't multiply sequence by non-int of type 'float'
print('hello, world' * 'hello, world') # TypeError: can't multiply sequence by non-int of type 'str'

型態轉換

int('100') # 從字串轉為整數型態
str(2.5) # 從浮點數轉為字串型態

指定變數

n = 100 # 設定整數變數 n,並賦值為 100
s = 'hello, world' # 設定字串變數 s,並賦值為 'hello, world'
  • 變數名稱不可數字開頭。
  • 變數名稱可以用全形中文字命名(PYTHON 可以,其它語言大部分不行)。

讀入變數

s = input()
  • 讀入為字串形態。
  • 讀入為一整行,不會因讀到空白而停止。

算術、指定運算子結合

  • n = n + 2 n += 2
  • n = n − 2 n −= 2
  • n = n ∗ 2 n ∗= 2
  • n = n / 2 n /= 2
  • n = n // 2 n //= 2
  • n = n % 2 n %= 2

輸出

print(value, ..., sep = ' ', end = '\n')
  • 傳入多個參數,以逗號隔開。
  • 間隔預設是一個空白鍵,可以透過更改 sep 參數改變。
  • 結尾預設是一個換行字元,可以透過更改 end 參數改變。
print(1, 2, 3) # 1 2 3 print(1, 2, 3, sep = '_') # 1_2_3 print(1, 2, 3, end = '...') # 1 2 3...

If

關係運算子

  • > : 大於。
  • >= : 大於等於。
  • < : 小於。
  • <= : 小於等於。
  • == : 等於。
  • != : 不等於。

關係運算回傳值為布林值的 True 或 False 。

ans = (1 != 2) print(ans) # True
ans = (1 > 2) print(ans) # False

邏輯運算

  • and
True False
True
True
False
False
False
False
  • or
True False
True
True
True
False
True
False
  • not
True False
True
False
True

if 用法

if expression: statements
  • 如果 expressionTrue 就執行以下 statements
  • 待執行內容需要縮排(空四格 或是 Tab,不可混著使用)。

elif 和 else 用法

if expression1: statements1 elif expression2: statements2 elif expression3: statements3 else: statements4
  • elifelseif 的簡寫,意思是如果還有條件是否為 True
  • else 是所有條件皆不成立,才會執行。
  • 只要其中一個 expression 成立,執行完其 statements,即會跳出其它的 expression

用法

a = 1 b = 2 if a > b: maximum = a minimum = b else: maximum = b minimum = a print('maximum:', maximum) print('minimum:', minimum)
n = -1 if n > 0: print('positive') elif n < 0: print('negative') else: print('zero')
year = 2000 if year < 0: print('illegal') elif year % 4 == 0 and year % 100 != 0 or year % 400 == 0: print('leap year') else: print('normal year')

Loop

loop 稱為迴圈,分為兩種:

  1. while loop
  2. for loop

while loop

while expression: statements # update conditions

expression 成立時,
就一直重複執行縮排內的 statements
直到 expressionFalse 時即停止。

用法

# 計算 0 ~ 10 總和 i = 0 sum = 0 while i <= 10: sum += i i += 1 print(sum) # 55
# 輾轉相除法 a, b = 18, 24 while b != 0: a, b = b, a % b print(a) # 6

for loop

for i in iterable: statements

用一個變數 i 迭代一個可迭代的物件。
常見可迭代物件:

  • range : range(start, stop, step)
for i in range(3): print(i) ''' 0 1 2 '''
for i in range(3, 6): print(i) ''' 3 4 5 '''
for i in range(5, 10, 3): print(i) ''' 5 8 '''
  • map
    map : map(function, iterable) 回傳一個迭代器 (iterator),使用 iterable 的每個元素來計算函數。原文:(make an iterator that computes the function using arguments from each of iterables.)。
for i in map(lambda x: x ** 2, [1, 2, 3]): # 對於 [1, 2, 3] 每個元素回傳 x ** 2 print(i) ''' 1 4 9 '''
  • filter : filter(func or None, iterabe),返回一個迭代器,產生 iterablefunction(item)True 的項目,如果函數為 None,則返回為 True 的項目。(原文:return an iterator yielding those iems of iterable for which fucntion(item) is True. If function is None, return the item that are True)。
for i in filter(lambda x: x % 2 == 0, [1, 2, 3, 4]): # 過濾, 只取 x%2==0 的元素 print(i) ''' 2 4 '''
for i in filter(None, [0, 1, 0, 2, 0]): # 過濾, 只取為 True(不為 0) 的元素 print(i) ''' 1 2 '''
  • str : 字串。
  • list : 串列。
  • tuple
  • dict : 字典。

用法

# 九九乘法表 for i in range(1, 10): for j in range(2, 10): print(j, '*', i, '=', j * i, end = '\t') print()

Funtion

在了解 function 之前,
其實我們已經先用很多 function 了。

  • print()
  • input()
  • int(), str(), float() 等。
  • sum(), min(), max(), len() 等。
    其實就是有「函數名稱」、「括號(傳入參數)」,
    做特定的指令並回傳數值。
    然而,
    還有好多好用的內建 function 可以使用。
  • abs(value) : 回傳 value 的絕對值。
print(abs(-2.5)) # 2.5
  • bin(interger) : 回傳 interger 的二進位表示值。
print(bin(100)) # 0b1100100
  • divmod(x, y) : 回傳 tuple(x // y, x % y)
print(divmod(25, 4)) # (6, 1)
  • eval(string) : 評估給定的 string,對於 string 做給定的指令。(原文:evaluate the given source int the context of globlas and locals.)。
print(eval('1 * 2 + 3 - 4 // 2')) # 3
eval('print(100)') # 100
print(eval('len([1, 2, 3, 4, 5])')) # 5
  • oct(interger) : 回傳 interger 代表的八進位表示值。
print(oct(100)) # 0o144
  • pow(base, exp, mod) : 回傳
    baseexp%mod
    。若沒有傳入 mod 參數,則回傳
    baseexp
print(pow(2, 10, 5)) # 4
print(pow(2, 10)) # 1024
  • sorted(iterable, key = None, reverse = False) : 回傳一個排序好的 iterable 物件。可依照喜好的 key 和是否要 reverse 排序。
print(sorted([5, 1, 3, 2, 4])) # [1, 2, 3, 4, 5]
print(sorted([5, 1, 3, 2, 4], key = lambda z: (z % 3, z))) # [3, 1, 4, 2, 5]
print(sorted([5, 1, 3, 2, 4], reverse = True)) # [5, 4, 3, 2, 1]

我們也可以自己寫 function

用法

def add(a, b): # a, b 為傳入參數 return a + b # 回傳值 ans = add(1, 2) # 使用 function print(ans) # 3

預設參數(Default Argument)

def add(a = 10, b = 20): ''' 預設參數 a = 10, b = 20 若沒有傳入參數就用預設參數代替 ''' return a + b # 回傳值 print(add(1, 2)) # 3 print(add(1)) # 21 print(add()) # 30 print(add(b = 0)) # 10
  • 中間有預設引數但後面沒有會發生錯誤。
def add(a = 10, b, c = 20): return a + b + c # 回傳值 # SyntaxError: non-default argument follows default argument

function 看似多了個步驟,
用起來還要注意細節,
十分麻煩。
但其實 function 對於重複性質高程式碼,
可帶來很大的便利。

def isprime(n): if n == 2: return True if n % 2 == 0 or n < 2: return False for i in range(2, int(n ** 0.5) + 1): if n % i == 0: return False return True print(isprime(2)) # True print(isprime(10)) # False

還有「匿名函數(lambda function)」可以用。
冒號前面是參數,
冒號後面是回傳值。

mul = lambda a, b: a * b print(mul(10, 20)) # 200

對於只需使用一次的函數,
通常會用匿名函數表示。

# 使用 normal function def f(z): return (z % 3, z) # 根據 (z % 3, z) 排序 print(sorted([5, 1, 3, 2, 4], key = f)) # [3, 1, 4, 2, 5]
# 使用 lambda fuction print(sorted([5, 1, 3, 2, 4], key = lambda z: (z % 3, z))) # [3, 1, 4, 2, 5]

Import

import module
顧名思義就是導入模組,
由於簡化程式碼長度,
可以導入已經寫好的模組使用。
導入方式(以 math 為例) :

import math # 直接導入, 之後使用前要加 math
import math as m # 導入名稱以 m 代入, 之後使用前要加 m
from math import * # 導入 math 所有東西, 之後直接使用
  • datetime : 處理基本的日期和時間類型處理基本的日期和時間類型
import datetime # datetime.date(year, month, day) x = datetime.date(2020, 1, 1) # 2020 年 1 月 1 日 y = datetime.date(2020, 10, 10) # 2020 年 10 月 10 日 print((y - x).days) # 時間差幾天 # 283 print((y - x).seconds) # 0 # 沒有指定 second, 無法計算 print('----------') # datetime.datetime(year, month, day, hour, minute, second) x = datetime.datetime(2020, 1, 1, 1, 1, 1) y = datetime.datetime(2020, 10, 10, 10, 10, 10) print((y - x).days) # 時間差幾天 # 283 print((y - x).seconds) # 時間差幾秒 # 32949
  • itertools : 為高效循環而創建迭代器的函數。
import itertools lst = [1, 2, 3] # 排列 for i in itertools.permutations(lst, 2): # P 3 取 2 print(i) ''' (1, 2) (1, 3) (2, 1) (2, 3) (3, 1) (3, 2) ''' print('----------') # 組合 for i in itertools.combinations(lst, 2): # C 3 取 2 print(i) ''' (1, 2) (1, 3) (2, 3) ''' print('----------') # 笛卡爾積 for i in itertools.product(lst, repeat = 2): # list 相乘, 重複 2 次 print(i) ''' (1, 1) (1, 2) (1, 3) (2, 1) (2, 2) (2, 3) (3, 1) (3, 2) (3, 3) '''
  • math : 數學函數
import math # 常數 print(math.pi) # 3.141592653589793 print(math.e) # 2.718281828459045 print('----------') # 三角函數(弧度量) pi = math.pi print(math.sin(pi)) # 1.2246467991473532e-16 print(math.cos(pi)) # -1.0 print(math.tan(pi)) # -1.2246467991473532e-16 print('----------') # 反三角函數(弧度量) print(math.acos(-1)) # 3.141592653589793 print(math.asin(-1)) # -1.5707963267948966 print(math.atan(-1)) # -0.7853981633974483 print('----------') # 捨去, 進位 print(math.ceil(2.4)) # 向上取整 # 3 print(math.floor(2.4)) # 向下取整 # 2 print('----------') # 階乘 print(math.factorial(3)) # 6 print(math.factorial(10)) # 3628800 print('----------') # 最大公因數 print(math.gcd(18, 24)) # 6 print('----------') # 排列, 組合 print(math.perm(5, 2)) # P 5 取 2 # 20 print(math.comb(5, 2)) # C 5 取 2 # 10 print('----------') # 對數運算 print(math.log10(100)) # 2.0 print(math.log2(16)) # 4.0 print(math.log(10)) # 以 e 為底 # 2.302585092994046 print(math.log(27, 3)) # 以 3 為底 # 3.0
  • random : 生成隨機數。
import random lst = [1, 2, 3, 4, 5] print(random.choice(lst)) # 從 lst 隨機選取 print('----------') print(random.choices(lst, k = 2)) # 從 lst 隨機選取 2 個, 回傳一個 list print('----------') print(random.randint(1, 10)) # 從 [1, 10] 隨機選取 print('----------') print(random.randrange(1, 10, 3)) # range(1, 10, 3) 隨機選取 print('----------') print(random.random()) # 從 [0, 1) 隨機選取小數 print('----------') random.shuffle(lst) # 打亂 lst print(lst)

事實上,
還有很多模組要透過網路下載,
有些 OJ 並不能使用,
而這些模組就是 PYTHON 的精華所在。

PYTHON List

Assign

# 指定空 list lst = [] lst = list()
# 指定有元素的 list # 型態可不一樣 lst = [1, '1', 1.0] lst = [i for i in range(5)] # [0, 1, 2, 3, 4] lst = [0] * 5 # [0, 0, 0, 0, 0] # 不可這樣:lst = [[]] * 5, 址會一樣 lst = [int(x) for x in input().split()]

Index and Value

index 索引值

  • 主要作用為取值和修改。
  • 範圍 1 ~ len(list) - 1,大於 len(list) - 1 會發生錯誤。
  • 範圍 -1 ~ -len(list) , 小於 -len(list) 會發生錯誤。

value 值

  • index 所對應到的值。
  • 可為任意型態。

用法

lst = [2, '4', 6.0] print(lst[0]) # index: 0, value: 2 print(lst[1]) # index: 1, value: '4' print(lst[2]) # index: 2, value: 6.0

Slice

  • 取片段 list
  • lst[start: stop: step]stop 預設是 len(list)step 預設是 1

用法

lst = [1, 2, 3, 4, 5] print(lst[3:]) # [4, 5] # 從 index: 3 開始到結束 print(lst[: 3]) # [1, 2, 3] # 從頭開始到 index: 3 結束 print(lst[:: 2]) # [1, 3, 5] # 從頭到尾, 間隔為 2

Method

  • append(object) : 將 object 加到 list 的末尾。
lst = [] print(lst) # [] lst.append(1) print(lst) # [1] lst.append(2) print(lst) # [1, 2] lst.append(3) print(lst) # [1, 2, 3]
  • clear() : 從 list 刪除所有項目。
lst = [1, 2, 3] lst.clear() print(lst) # []
  • copy() : 回傳一個淺複製的 list
# 沒有使用 copy() lst_1 = [1, 2, 3] lst_2 = lst_1 lst_2[0] = 100 # 更改元素 print(lst_1) # [100, 2, 3] print(lst_2) # [100, 2, 3]
# 使用 copy() lst_1 = [1, 2, 3] lst_2 = lst_1.copy() lst_2[0] = 100 # 更改元素 print(lst_1) # [1, 2, 3] print(lst_2) # [100, 2, 3]
  • count(value) : 回傳 value 出現的次數。
lst = [1, 2, 2, 3, 3, 3] print(lst.count(1)) # 1 print(lst.count(2)) # 2 print(lst.count(3)) # 3 print(lst.count(4)) # 0
  • extend(iterable) : 透過附加的 iterable 的元素來拓展 list
lst = [1, 2] lst.extend([3, 4]) print(lst) # [1, 2, 3, 4]
  • index(value) : 回傳 valuelist 的第一個 index,若 value 不在 list,則會發生錯誤。
lst = [1, 2, 4] print(lst.index(1)) # 0 print(lst.index(2)) # 1 print(lst.index(3)) # ValueError: 3 is not in list
  • insert(index, object) : 插入objectindex 前。
lst = [0, 2, 8] lst.insert(2, 4) print(lst) # [0, 2, 4, 8] lst.insert(3, 6) print(lst) # [0, 2, 4, 6, 8]
  • pop() : 若無參數,則刪除尾端元素;反之,刪除指定 index 的元素。若指定 index 超過 list 的長度會發生錯誤。對於空的 list 使用 pop() 亦會發生錯誤。若成功執行,會回傳刪除的元素。
lst = [1, 2, 3, 4, 5] print(lst.pop()) # 5 print(lst) # [1, 2, 3, 4]
lst = [1, 2, 3, 4, 5] print(lst.pop(0)) # 1 print(lst) # [2, 3, 4, 5]
  • remove(value) : 刪除 valuelist 第一次出現的值。如果 value 不在 list 則會發生錯誤。
lst = [1, 2, 2, 3] lst.remove(2) print(lst) # [1, 2, 3]
lst = [1, 2, 3] lst.remove(4) # ValueError: list.remove(x): x not in list
  • reverse(value) : 刪除 valuelist 第一次出現的值。如果 value 不在 list 則會發生錯誤。
lst = [1, 2, 2, 3] lst.remove(2) print(lst) # [1, 2, 3]
lst = [1, 2, 3] lst.remove(4) # ValueError: list.remove(x): x not in list
  • reverse() : 將 list 反轉。
lst = [1, 2, 3] lst.reverse() print(lst) # [3, 2, 1]
  • sort() : 數字型態不可和字串形態排序。若無參數,則將 list 由小到大排序。參數可有 keyreversekey 可以依照喜好方法排序,reverse 預設是 False,可以改成 True,設為由大到小排序。
lst = [5, 1, 3, 2, 4] lst.sort() print(lst) # [1, 2, 3, 4, 5]
lst = [5, 1, 3, 2, 4] lst.sort(reverse = True) # 由大到小排序 print(lst) # [5, 4, 3, 2, 1]
lst = [5, 1, 3, 2, 4] lst.sort(key = lambda z: (z % 3, z)) # 根據 (z % 3, z) 排序 print(lst) # [3, 1, 4, 2, 5]

Function

  • len(list) : 回傳 list 的長度。
lst = [1, 2, 3, 4, 5] print(len(lst)) # 5
  • max(list) : 回傳 list 的最大值。
lst = [1, 2, 3, 4, 5] print(max(lst)) # 5
  • min(list) : 回傳 list 的最小值。
lst = [1, 2, 3, 4, 5] print(min(lst)) # 1
  • sum(list) : 回傳 list 的總和。
lst = [1, 2, 3, 4, 5] print(sum(lst)) # 15

Traversal

  • 使用 range()len()index
lst = [1, 2, 3, 4, 5] for i in range(len(lst)): print('index:', i, 'value:', lst[i]) ''' index: 0 value: 1 index: 1 value: 2 index: 2 value: 3 index: 3 value: 4 index: 4 value: 5 '''
  • 直接迭代。
lst = [1, 2, 3, 4, 5] for v in lst: print(v) ''' 1 2 3 4 5 '''
  • 使用 enumerateindexvalue 迭代。
lst = [1, 2, 3, 4, 5] for i, v in enumerate(lst): print('index:', i, 'value:', v) ''' index: 0 value: 1 index: 1 value: 2 index: 2 value: 3 index: 3 value: 4 index: 4 value: 5 '''

PYTHON String

Assign

  • 指定空字串
s = '' s = "" s = str()
  • 指定非空字串
s = 'abc' s = "abc"

Slice

list

Method

  • s.capitalize() :回傳第一個字元為大寫的 s 字串(不會更改 s)。
s = 'abc ABC 123' print(s.capitalize()) # Abc abc 123
  • s.upper() :回傳英文部分全部大寫(其餘部分不變)的 s 字串(不會更改 s)。
s = 'abc ABC 123' print(s.upper()) # ABC ABC 123
  • s.lower() :回傳英文部分全部小寫(其餘部分不變)的 s 字串(不會更改 s)。
s = 'abc ABC 123' print(s.lower()) # abc abc 123
  • s.isupper() :如果字串 s 的英文部分全為大寫則回傳 True ;反之 False
s = 'ABC 123' print(s.isupper()) # True
  • s.islower() :如果字串 s 的英文全為小寫則回傳 True ;反之 False 。
s = 'ABC 123' print(s.islower()) # False
  • s.isalpha() :如果字串 s 全由字母組成則回傳 True;反之 False
s = 'abcABC' print(s.isalpha()) # True
  • s.isdigit() :如果字串 s 全由數字組成則回傳 True;反之 False
s = 'abcABC' print(s.isdigit()) # False
  • s.count(sub, start, end) :回傳 subs[start: end] 出現的次數。若沒有傳入 startend 參數,則預設為 0len(s)
s = 'abc abc abc' print(s.count('abc')) # 3 print(s.count('abc', 4)) # 2 print(s.count('abc', 4, 7)) # 1
  • s.find(sub, start, end) :回傳 subs[start: end] 第一個出現的位置,若 sub 不在 s 裡面,則回傳 −1。若沒有傳入 startend 參數,則預設為 0len(s)
s = 'abc abc abc' print(s.find('abc')) # 0 print(s.find('abc', 3)) # 4 print(s.find('abc', 3, 4)) # -1
  • s.join(list) :在 list 內每一個字串插入 s,並回傳一個新字串。list 內的每一個元素型態一定要是 str,否則會出現錯誤。
s = '...' print(s.join(['a', 'b', 'c'])) # a...b...c
  • s.lstrip() :回傳移除左端不可見字元的字串 s (不會更改 s)。
s = ' abc ' print(s.lstrip()) # 'abc '
  • s.rstrip() :回傳移除右端不可見字元的字串 s(不會更改 s)。
s = ' abc ' print(s.rstrip()) # ' abc'
  • s.strip() :回傳移除兩端不可見字元的字串 s(不會更改 s)。
s = ' abc ' print(s.strip()) # 'abc'
  • s.replace(sa, sb, times) :回傳字串 ssa 取代成 sb 的字串,times 為次數(不會更改 s)。若沒有傳入 times 參數,則預設是 −1,也就是全部取代。
s = 'abc abc abc' print(s.replace('abc', 'ABC')) # ABC ABC ABC print(s.replace('abc', 'ABC', 1)) # ABC abc abc
  • s.split(sep, times) :使用 sep 作為分隔字串,times 為分隔次數,並回傳一個 list(不會更改 s)。若沒有傳入 sep 參數,則以空白字元為預設。若沒有傳入 times 參數,則預設值是 −1,也就是全部取代。
s = 'abc abc' print(s.split()) # ['abc', 'abc'] print(s.split(' ')) # ['abc', '', '', 'abc'] print(s.split(' ', 1)) # ['abc', ' abc']

Function

  • len(s) :回傳 s 的長度。
s = 'abc abc' print(len(s)) # 7

Traversal

list

PYTHON Dict

Assign

  • 指定空 dict
# 指定空 dict d = {} d = dict()
  • 指定有內容的 dict
# 指定有內容的 dict d = {'a': 1, 'b': 2} # a -> 1, b -> 2 d = {chr(i): i for i in range(65, 91)} # ASCII 表 # A -> 65, B -> 66, C -> 67, ..., Z -> 90

Usage

名詞

  • key :關鍵字,欲存取對應值的關鍵字。 key 必須是 hashable (如: list 不可當 key )。
  • value :值,關鍵字對應的值。value 可為任意型態

存取

d = {} d['a'] = 1 # a -> 1 print(d) # {'a': 1} d['b'] = 2 # b -> 2 print(d) # {'a': 1, 'b': 2}

修改

d = {} d['a'] = 1 # a -> 1 print(d) # {'a': 1} d['a'] = 2 print(d) # {'a': 2} d['a'] += 1 print(d) # {'a': 3}

取值

d = {'a': 1, 'b': 2} print(d['a']) # 1 print(d['b']) # 2 print(d['c']) # KeyError: 'c'

Method

  • clear() :從 dict 刪除所有項目。
d = {'a': 1, 'b': 2} d.clear() print(d) # {}
  • copy() :回傳一個淺複製的 dict
# 沒有使用 copy d1 = {'a': 1, 'b': 2} d2 = d1 d2['a'] = 10 print(d1) # {'a': 10, 'b': 2} print(d2) # {'a': 10, 'b': 2}
# 使用 copy d1 = {'a': 1, 'b': 2} d2 = d1.copy() d2['a'] = 10 print(d1) # {'a': 1, 'b': 2} print(d2) # {'a': 10, 'b': 2}
  • keys() :回傳一個所有 keysdict_keys(類似 list )。
d = {'a': 1, 'b': 2} print(d.keys()) # dict_keys(['a', 'b'])
  • values() :回傳一個所有 valuesdict_values (類似 list )。
d = {'a': 1, 'b': 2} print(d.values()) # dict_values([1, 2])
  • get(key) :則回傳 keydict 裡面對應的 value。若 key 不在 dict 裡面,則會回傳 None
d = {'a': 1, 'b': 2} print(d.get('a')) # 1 print(d.get('c')) # None
  • items() :回傳一個所有 keysvalues(每組數據是 tuple 型態) 的 dict_items(類似 list)。
d = {'a': 1, 'b': 2} print(d.items()) # dict_items([('a', 1), ('b', 2)])
  • pop(key) :則刪除該組 keyvalue ,並回傳 value 。若 key 不在 dict 裡面,則會發生錯誤。
d = {'a': 1, 'b': 2} print(d.pop('a')) # 1 print(d) # {'b': 2} print(d.pop('c')) # KeyError: 'c'
  • popitem() :刪除並返回最後加入(也就是 dict 的最後一項)的 (key, value) (tuple 型態)。若 dict 沒有元素,則會發生錯誤。
d = {'a': 1, 'b': 2} print(d.popitem()) # ('b', 2) print(d) # {'a': 1} print(d.popitem()) # ('a', 1) print(d) # {} print(d.popitem()) # KeyError: 'popitem(): dictionary is empty'

Function

  • len(dict) :回傳 dict 的長度。
d = {'a': 1, 'b': 2} print(len(d)) # 2

Traversal

  • 直接迭代,用 keydict[key] = value 方式呈現。
d = {'a': 1, 'b': 2} for key in d: # d 相當於 d.keys() print('key:', key, 'value:', d[key]) ''' key: a value: 1 key: b value: 2 '''
  • key, value 迭代 dict_items()
d = {'a': 1, 'b': 2} for key, value in d.items(): print('key:', key, 'value:', value) ''' key: a value: 1 key: b value: 2 '''
  • zip()d.keys()d.values() 壓縮起來一起迭代。
d = {'a': 1, 'b': 2} for key, value in zip(d.keys(), d.values()): print('key:', key, 'value:', value) ''' key: a value: 1 key: b value: 2 '''

Discord Bot Set up

  1. Register and log in Discord (也有手機 App 版)

  2. Enter in Discord Developer

  3. Click New Application

  4. Create an Application

  5. Click Bot

  6. Click Add Bot

  7. Back to Discord
    需要一個 server (伺服器、群組) 放 bot
    而這個必須擁有 管理者 的身分,
    可以自己創一個 server 就一定會有管理者的身分,
    別人的群組則大部分不會開管理者給成員。

  8. Click QAuth2

  9. Click bot

  10. Click these

  11. Click Copy

  12. 將連結貼至瀏覽器上

  13. 選擇一個 server 並按下 繼續

  14. Back to Discord, and the bot is ready.

修飾器

如果要將某個函式放入該函式的參數中,
可以使用修飾器。

Example

def modify_function(any_func): print(type(any_func)) return lambda: type(any_func) #型態只能是function @modify_function def func(): pass print(func()) # <class 'function'> # <class 'function'>

async 與 await - 協程 (coroutine)

async 意指異步執行,
await 則是用來驅動 async 函式的必須指令。
在 Python 3.5 之前,協程函式只能用以下方法實作:

import asyncio loop = asyncio.get_event_loop() @asyncio.coroutine def func(): return 10 print(loop.run_until_complete(func())) # 10

在協程函式中會放置 return 或是 yield from
兩者都會回傳 generator
要使用 loop.run_until_complete() 才能回傳真實結果。
Python 3.5 之後,
使用下列方法:

import asyncio loop = asyncio.get_event_loop() async def func(): return 10 print(loop.run_until_complete(func())) """ in async block -> print(await func()) """

如果在 async 區塊中使用協程時,可以使用 await

Start Coding

IDE(Integrated Development Environment) : repl.it

Import Modules

import nextcord from nextcord.ext import commands

Declaration a bot

bot = commands.Bot(command_prefix = '$') # 宣告 bot bot.remove_command('help') # 移除 built-in function
  • command_prefix : 指令前面要加的輸入
  • 因為 bot 也需要用到 help,所以把內建的 help 函數移除

Event

on_ready

@bot.event async def on_ready(): await bot.change_presence(status = nextcord.Status.dnd,\ activity = nextcord.Activity(name = '$help',\ type = nextcord.ActivityType.listening)) print('>> Bot is online ')
  • bot 開始執行時會進入這個函數
  • statusbot 的狀態
  • activitybot 的動作

Status

  • dnd (do_not_disturb) : 勿擾
  • idle : 閒置
  • offline : 下線
  • online : 上線
  • invisible : 不可見

Activity

  • Streaming
  • Activity
  • Game
import nextcord s = nextcord.Streaming(name="...", url="twich_url") # ... 實況中 """ playing: 正在玩 listening: 正在聽 watching: 正在看 """ a = nextcord.Activity(name="...", type=nextcord.ActivityType.something) # 正在{somthing} ... # 像是 正在玩 遊戲 # something 換成 playing , ... 換成遊戲

on_member_join

@bot.event async def on_member_join(member): channel = bot.get_channel('Channel') # 自己的 channel 不是字串喔 await channel.send(f'{member} welcome!')
  • 當有成員離開 server 時會進入這個函數
  • channel 是自己頻道的編號(也就是網址 url 的最後一個 / 後面一整串)

on_member_remove

@bot.event async def on_member_remove(member): channel = bot.get_channel('Channel') # 自己的 channel 不是字串喔 await channel.send(f'{member} leave!')
  • 當有成員進入 server 時會進入這個函數
  • channel 是自己頻道的編號(也就是網址 url 的最後一個 / 後面一整串)

on_message

@bot.event async def on_message(msg): if msg.author != bot.user: await msg.channel.send(msg.content) # 你說什麼,就會回傳什麼

on_message_delete

@bot.event async def on_message_delete(msg): await msg.channel.send(msg.content) # 將你刪除的訊息回傳

on_raw_reaction_add

@bot.event async def on_raw_reaction_add(payload): c = bot.get_channel(payload.channel_id) await c.send(payload.emoji.name) # 你在哪則訊息點了某個表情符號,它就會在訊息的頻道傳送那個表情符號

on_raw_reaction_remove

@bot.event async def on_raw_reaction_remove(payload): c = bot.get_channel(payload.channel_id) await c.send(payload.emoji.name) # 你在哪則訊息取消了某個表情符號,它就會在訊息的頻道傳送那個表情符號

Command

Format

@bot.command() async def func_name(ctx): await ctx.send('欲回傳的訊息')
  • func_name 是函數的名稱
  • ctx 是指 context 上下文
  • 欲回傳的訊息 必須是字串

Example

ping

  • latency 中文是等待時間,相當於 bot 的延遲。
@bot.command() async def ping(ctx): await ctx.send(f'{round(bot.latency * 1000)} (ms)')

now

  • 獲取現在時間 (UTC+8)。
import datetime def gettime(): x = datetime.datetime.now() err = datetime.timedelta(hours=8) x += err y = x.year m = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][x.month - 1] d = x.day h = x.hour mi = x.minute s = x.second w = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][(x.weekday() + 1) % 7] res = '{} {} {:02d} {:02d}:{:02d}:{:02d} {}'.format(w, m, d, h, mi, s, y) return res @bot.command() async def now(ctx): await ctx.send(gettime())

calc

  • 計算一條算式。
from math import * def operation(s): s = s.replace(' ', '') s = s.replace('^', '**') s = s.replace('log', 'log10') s = s.replace('ln', 'log') i, t = len(s) - 1, 0 while i >= 0: # 處理 "factorial 階乘" if s[i] == '!': if s[i - 1].isdigit(): t, i = i, i - 1 while s[i].isdigit(): i -= 1 tmp = s[i + 1: t] s = s[:i + 1] + 'factorial(' + tmp + ')' + s[t + 1:] else: t, right, i = i, 1, i - 2 while right: if s[i] == ')': right += 1 if s[i] == '(': right -= 1 i -= 1 tmp = s[i + 1:t] s = s[:i + 1] + 'factorital(' + tmp + ')' + s[t + 1:] i -= 1 # print(s) try: res = round(eval(s), 3) return res except: res = '(type error or too difficult)' return res @bot.command() async def calc(ctx, *, s): ans = func.operation(s) await ctx.send(f'result of ({s}) is {ans}')

guess

  • 隨機猜 [1, 5] 的整數,猜中了會回傳 True;反之,False
def Guess(n): tmp = randint(1, 5) a = ['false', 'true'] s = f'right ans is {tmp}, your ans is {a[n == tmp]}' return s @bot.command() async def guess(ctx, n : int): await ctx.send(Guess(n))

help

  • 可以告訴你這個 bot 有哪些功能。
  • 以表單的形式呈現。
bot.remove_command('help') # 要先移除原本的 help 指令 @bot.command() async def help(ctx): embed = nextcord.Embed(color = 0x86ff00) embed.set_author(name = jdata['FORM']) embed.set_thumbnail(url = jdata['STICKER']) embed.add_field(name = '$help',\ value = 'To get help',\ inline = False) embed.add_field(name = '$calc',\ value = 'To calculate your formula',\ inline = False) embed.add_field(name = '$now', value = 'To get the current time',\ inline = False) embed.add_field(name = '$ping',\ value = 'To get the ping delay',\ inline = False) embed.add_field(name = '$guess',\ value = 'To guess a number (range : 1 ~ 5)',\ inline = False) embed.add_field(name = '$hunt',\ value = 'To hunt your zerojudge data',\ inline = False) await ctx.send(embed = embed)

Keep Alive

完全參考 [Proladon] Code a discord bot - 如何讓Discord Bot 24小時在線

  1. 下載 雲端相關文件
  2. 進入 repl.it 並註冊帳號。
  3. 點擊左邊 + New repl,選擇 PYTHON 語言,打上這個專案的名字,按下 Create repl
  4. 將原本的程式碼和雲端文件的 keep_alive.py 貼至 main.py 裡面。
  5. main.py 最上面加入 import keep_alive
  6. main.py 加入 keep_alive.keep_alive(),位置如下:
if __name__ == "__main__": keep_alive.keep_alive() # 加在這裡 bot.run(jdata['TOKEN'])
  1. 儲存後按下 run (第一次需要下載套件,要等會兒)
  2. 進入監控 bot網站 ,註冊並登入帳號。
  3. 點擊左上角 +Add New MonitorMonitor TypeHTTP(s)URL (or IP)repl 右上方的網址 (如下圖 1.),Monitoring Interval監控間隔,用最短的 5 minutes 就好,Select "Alert Contacts To Notify"bot 有離線或重新上線是否需要 email 通知,視個人決定要不要勾選。最後會變成如下圖 2.,按下 Create Monitor。 (第一次需要一點時間抓取資料,要等會兒)
    圖 1.
    圖 2.
  4. 完成。

其它檔案

如果你的機器人在其它檔案,那你要如何載入呢?
有一個方法適用,
創建一個資料夾叫做 core
之後,在其中創建一個 classes.py 的檔案,
檔案架構如下:

 |   main.py
├───cmds
 |       cmd1.py
 |       cmd2.py
└───core
        classes.py

classes.py 的內容如下 :

import nextcord from nextcord.ext import commands class Cog_(commands.Cog): def __init__(self, bot): self.bot = bot def setup(bot): bot.add_cog(Cog_(bot))

其他檔案在 cmds 裡的檔案,
cmd1.pycmd2.py
則需要在開頭加入 from core.classes import Cog_
以及在結尾加入

def setup(bot): bot.add_cog(Your_Class(bot))

檔案內容寫法有些不同。
ping 來舉例,
要將程式碼改成如下才有辦法運作
會變成:

import nextcord from nextcord.ext import commands from core.classes import Cog_ class Your_Class(Cog_): @commands.command() async def ping(self, ctx): await ctx.send(f'{round(self.bot.latency*1000)} (ms)') def setup(bot): bot.add_cog(Your_Class(bot))

Your_Class 的名字能自己取,基本上你要自己取就自己取
現在,讓我問問你們,有哪裡不一樣了?

答案揭曉

  • 在修飾器中的 bot 變成 discord.ext 裡的 commands
  • bot 都改成 self.bot
  • 函式的參數多了一個 self

self 是自身的意思,
代表著這整個 class
self.bot 就等於這整個 classbot 這個屬性
所有 bot.command() 都要換成 commands.command()
bot.event 則是換成 commands.Cog.listener()

最後一個步驟則是在 main.py 裡加入下列程式碼,
以在開啟時能載入。

import os for filen in os.listdir('./cmds'): if filen.endswith('.py'): bot.load_extension(f'cmds.{filen[:-3]}')

Music (進階)

音樂最基本功能當然是播放歌曲啦 XD,
所以要來教你如何編寫 play 指令。

安裝套件

你可以安裝 Black_Lotus 寫的套件,
請使用指令 : pip install NPytdl==4.1.0b2 Source

p, play

import nextcord from nextcord.ext import commands from NPytdl import Pytdl ydl = Pytdl() OPTIONS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5',\ 'options': '-vn'} @bot.command(aliases=["p"]) async def play(ctx: commands.Context, *, url: str): if url.find("https://") != -1: if url.find("list=") != -1: List = await ydl.info(url) await List.create() songs = List.videos else: song = await ydl.info(url) await song.create() songs = [song] else: data = await (ydl.resultList(url))[0] song = await ydl.info(f"https://youtu.be/{data['id']}") await song.create() songs = [song] client = ctx.voice_client if client is None: for voice_client in self.bot.voice_clients: if voice_client.channel in ctx.guild.channels: client = voice_client if client is None: if ctx.author.voice is not None: client = await ctx.author.voice.channel.connect() if client is None: await ctx.send("你要加入頻道!!!") return source = discord.FFmpegOpusAudio(songs[0].voice_url, **OPTIONS) client.play(source)

此指令在以下情況可能會有錯誤產生:

  • 機器人已在播音樂
  • 爬蟲發生錯誤
  • 機器人未加入頻道
  • 電腦沒安裝FFmpeg
  • Python 未安裝 PyNaCl