Python

第四堂

Content

  • Review

  • function

  • recursion

  • decorator

  • lambda

  • class

  • 例外處理

  • 函式庫

Review

Dictionary

鍵 ( Key ) - 值 ( Value ) 對應,key 需唯一且不可變

d = {'a': 1, 'b': 2}
d1 = {[1, 2]: 1} #TypeError: unhashable type: 'list'

dict methods

d = {'b': 2}
d['a'] = 1
print(len(d)) #2
print(list(d.keys())) #['b', 'a']
print(list(d.values())) #[2, 1]
print(list(d.items())) #[('b', 2), ('a', 1)]
print(d.get('a', "Doesn't exist")) #1
print(d.copy()) #{'b': 2, 'a': 1}
del d['a']
print(d) #{'b': 2}

Format

將輸出內容格式化

a = "Hi, I am %s."
print(a % "pomelo") #Hi, I am pomelo.
b = "I have %d dollars."
print(b % 3.333) #I have 3 dollars.
c = "Now I have %f dollars."
print(c % 3.333) #Now I have 3.333000 dollars.

a = "Hello, I am {}, and I like to eat {}."
print(a.format("pomelo", "apple"))
#Hello, I am pomelo, and I like to eat apple.
b = "Hello, {:-^10s}."
print(b.format("world")) #Hello, --world---.

name = "pomelo"
age = 15.187
print(f"My name is {name}, I am {age} years old.")
#My name is pomelo, I am 15.187 years old.
print(f"Hello {name.upper()}, I am {age:-^.1f} years old.")
#Hello POMELO, I am 15.2 years old.

if - elif - else

條件判斷

a = 1
b = 2

if a > b:
    print("a > b")
elif a == b:
    print("a == b")
else:
    print("a < b")
#a < b    

print(a and b) #2
print(a or b) #1
print(0 and b or a) #0

for

for 變數 in 可迭代物件/range():

lst = [1, 3, 4]
for i in lst:
    if i > 2:
        print(i)
#3 4        

for i in range(0, 4, 2):
    print(i)
#0 2

while

while 條件:

n = 4

while n > 0:
    print(n, end=' ')
    n -= 1
#4 3 2 1

function

函式

f(x) = x^2 + 2x + 1 \\ f(1) = 4 \\ f(2) = 9 \\ ...

數學函式

給一個 x 值會對應到某個數值

程式函式

def f(x):
    result = x**2 + 2*x + 1
    return result
    
print(f(2)) #9

define,定義函式需要的開頭

函式名稱

要傳入的參數

回傳值

執行函式

Function

函式是一種有名稱且獨立的程式片段,可以接收任何型態的參數,處理完成後也可以輸出任何型態的結果

def 函式名稱(參數1, 參數2...): #定義函式
  要執行的程式
  return 回傳值

函式名稱(參數1, 參數2...) #執行函式

要先定義函式,才能執行

參數

可以放入多個參數,會按照順序處理

def f(a, b):
    return a - b
    
print(f(1, 2)) #-1 (a = 1, b = 2)
print(f(2, 1)) #1 (a = 2, b = 1)

最多只能輸入與參數數量一樣多的變數值

參數

也可以不放入參數

def f():
    return 6
    
print(f()) #6

關鍵字引數

可以用關鍵字引數設定特定參數內容

def mbi(weight, height):
    return weight / (height**2)
    
print(mbi(height=1.5, weight=45)) #20.0

順序不一樣也沒關係

回傳值

使用 return 回傳值

def f(x):
    all = 0
    for i in x:
        all += i
    return all
    
print(f([1, 2, 4])) #7

回傳值

也可以不回傳值

def f(name):
    print(f"Hello, {name}")
    
a = f("pomero") #Hello, pomero
print(a) #None

會回傳 None

回傳值

遇到 return 時會中止函式並回傳值

def f(x):
    all = 0
    for i in x:
        all += i
        if i % 5 == 0:
            return all
    return all
    
print(f([1, 3, 5, 6])) #9
print(f([1, 3, 4, 6])) #14

回傳值

def f(x):
    all = 0
    for i in x:
        all += i
        if i % 5 == 0:
            return all
    return all
    
print(f([1, 3, 5, 6])) #9
print(f([1, 3, 4, 6])) #14

all = 0

all = 1

all = 4

+1

+3

all = 9

+5

return

5 % 5 == 0

回傳值

def f(x):
    all = 0
    for i in x:
        all += i
        if i % 5 == 0:
            return all
    return all
    
print(f([1, 3, 5, 6])) #9
print(f([1, 3, 4, 6])) #14

all = 0

all = 1

all = 4

+1

+3

all = 8

+4

all = 14

+6

return

end for

回傳值

可以回傳多個結果

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

會回傳 tuple

回傳值

def f(x, y, z):
    return x+1, y+1, z+1
    
a, b, c = f(1, 2, 3)
print(f"a = {a}, b = {b}, c = {c}")
#a = 2, b = 3, c = 4

會回傳 tuple

可以 unpacking 給多個變數

變數範圍

a = 2

def f(a):
    a = 1
  
print(f"a is {a}")

變數範圍

在函式裡宣告的變數,生命只到函式結束,稱為區域 ( local ) 變數

在函式裡宣告的函式也一樣

def f1():
    def f2():
        print("Local: f2")
    f2()
  
f1() #Local: f2
f2() 
#NameError: name 'f2' is not defined

global

可以把區域變數變成全域 ( global ) 變數

a = 2
def f():
    global a
    a = 1 #不可寫作:global a = 1
    print(f"Global a in func: {a}")
    
print(f"Before f(), global a = {a}")
f()
print(f"After f(), global a = {a}")

# Before f(), global a = 2
# Global a in func: 1
# After f(), global a = 1

nonlocal

可以修改上層函式中定義的變數

def f1():
    a = 2
    print(f"Local variable a = {a} in f1")
    def f2():
        print(f"f2 calls a = {a}")
        def f3():
            nonlocal a
            a = 10
            print(f"f3 calls modified a = {a}")
        f3()
    f2()
    print(f"a in f1 = {a}")
    
f1()

# Local variable a = 2 in f1
# f2 calls a = 2
# f3 calls modified a = 10
# a in f1 = 10

nonlocal

def f1():
    a = 2
    print(f"Local variable a = {a} in f1")
    def f2():
        print(f"f2 calls a = {a}")
        def f3():
            nonlocal a
            a = 10
            print(f"f3 calls modified a = {a}")
        f3()
    f2()
    print(f"a in f1 = {a}")
    
f1()

# Local variable a = 2 in f1
# f2 calls a = 2
# f3 calls modified a = 10
# a in f1 = 10

函式若未先在函式被呼叫不會執行

一個函式執行完裡面全部的內容後,才會執行另一個函式

*args

可以傳入多個參數,傳入的參數會被轉為 tuple

def f(*s):
    print(s)
    
f(1, 2, 3, 'a', 'b', 'c')
# (1, 2, 3, 'a', 'b', 'c')

用法:*變數名

**kwargs

可以傳入多個參數,傳入的參數會被轉為 dict

def f(**s):
    print(s)
    
f(name='pomero', age=18, gender='g')
# {'name': 'pomero', 'age': 18, 'gender': 'g'}

用法:**變數名

使用之前要先賦值

* & **

若 *args 和 **kwargs 同時出現,會依照輸入的內容分別套用

def f(*args, **kwargs):
    print(f"args: {args}")
    print(f"kwargs: {kwargs}")
    
f([1, 2, 3], 4, x=1, y=2)
# args: ([1, 2, 3], 4)
# kwargs: {'x': 1, 'y': 2}

函式參數

可以把函式當參數

def plus(a, f):
    return a + f(a)
    
def square(a):
    return a**2
    
print(plus(2, square)) #6 (2 + 2**2)

Recursion

遞迴

Recursion

在函式裡呼叫自己或其他函數

def n(a):
    if a < 1:
        return 1
    return a + n(a-1)

Fibonacci

def fib(a):
    if a == 1 or a == 2:
        return 1
    return fib(a-1) + fib(a-2)
    
print(fib(5)) #5
a_{1}=1, a_{2}=1\\ a_{n}=a_{n-1}+a_{n-2}

fib(5)

fib(4) + fib(3)

fib(3) + fib(2)

fib(2) + fib(1)

fib(2) + fib(1)

return 1

return 1

return 1

return 1

return 1

return 2

return 3

return 2

return 5

Factorial

def fact(n):
    if n == 0 or n == 1:
        return 1
    return n * fact(n-1)
    
print(fact(5)) #120
a_{0}=1, a_{1}=1\\ a_{n}=n*a_{n-1}

lambda

匿名函式

lambda

  • 不需要定義名稱
  • 只能有一行運算式
  • 執行完後自動回傳結果
square = lambda x: x**2

print(square(2)) #4

lambda

使用:lambda 參數名稱: 內容

def hi():
    print("Hi")
    
hi() #Hi
p = lambda l: print(l)
p("Hi") #H1
(lambda l: print(l))("Hi") #Hi

第 4 行執行結果跟第 5 ~ 6. 7 行一樣

多個參數

不用使用小括號,需使用逗號分隔參數

POW = lambda x, y: x**y
print(POW(2, 4)) #16
f = lambda *args: print(args)
f(1, 2, 3) #(1, 2, 3)

也可以使用 *args

for

lambda 可以搭配 for 迴圈使用

def x(*args):
    lst = []
    for i in args:
        lst.append(i*2)
    return lst

y = lambda *args: [i*2 for i in args]

print(x(1, 2, 3)) #[2, 4, 6]
print(y(1, 2, 3)) #[2, 4, 6]

if

lambda 也可以搭配 if 使用

def x(n):
    if n < 10:
        return True
    else:
        return False

y = lambda n: True if n < 10 else False

print(x(11)) #False
print(y(11)) #False

lambda

為什麼不是印出 0, 1, 16 ?

square = []

for i in range(5):
    square.append(lambda : i**2)
    
print(square[0]()) #16
print(square[1]()) #16
print(square[4]()) #16

lambda

為什麼不是印出 0, 1, 16 ?

square = []

for i in range(5):
    square.append(lambda : i**2)
    
print(square[0]) #<function <lambda> at 0x7fcd4a364d30>
print(square[1]) #<function <lambda> at 0x7fcd4a364dc0>
print(square[4]) #<function <lambda> at 0x7fcd4a364f70>

square 裡存的是 lambda

lambda

為什麼不是印出 0, 1, 16 ?

square = []

for i in range(5):
    square.append(lambda : i**2)
    
print(i) #4
print(square[0]()) #16
print(square[1]()) #16

在迴圈結束後執行,i = 4

所以 lambda 裡的 i = 4,會回傳 4**2

lambda

為什麼不是印出 0, 1, 16 ?

square = []

for i in range(5):
    square.append(lambda : i**2)
    print(square[i]()) #0 1 4 9 16
    print(square[0]()) #0 1 4 9 16

如果在迴圈裡執行,會印出正確的結果

lambda

square = []

for i in range(5):
    square.append(lambda x=i: x**2)
    
print(square[0]()) #0
print(square[1]()) #1
print(square[4]()) #16

如果在迴圈裡執行,會印出正確的結果

如果想要在迴圈外執行,可以將參數設為另一個變數

map( )

a = [1, 2, 3, 4, 5, 6]
b = map(lambda i: i+1, a)

print(b) #<map object at 0x7f7a81b87130>
print(list(b)) #[2, 3, 4, 5, 6, 7]

map( function, iterable object )

map 會根據特定函式對指定的序列做映射

意思就是依據函式去改變後面序列的內容

filter( )

a = [1, 2, 3, 4, 5, 6]
b = filter(lambda i: i>3, a)

print(list(b)) #[4, 5, 6]

filter( function, iterable object )

filter 會根據特定函式對指定的序列做過濾

意思就是依據函式去過濾後面序列的內容,將回傳為 True 的項目留下

decorator

裝飾器

decorator

  • 讓程式碼達到精簡又漂亮的寫法
  • 讓其他函式或類別,在不需要做任何程式碼修改的前提下增加額外功能
  • 裝飾器的返回值是一個函式或類別

decorator

def a(func):
    print("a")
    return func
    
def b():
    print("b")
    
c = a(b) #a
print(c) #<function b at 0x7f7eebe74dc0>
c() #b

函數可以當作參數傳遞並執行

語法糖 @

def a(func):
    print("a")
    return func
  
#裝飾 b 
@a 
def b():
    print("b")
    
b()
#a
#b

用語法糖包裝來簡化

多個裝飾器

def a1(func):
    print(1)
    return func
    
def a2(func):
    print(2)
    return func
    
def a3(func):
    print(3)
    return func
    
@a1
@a2
@a3
def b():
    print("go!!!")
    
b()

用語法糖包裝來簡化

class

類別

class

可以建立一個自訂的型態

class class_name():
    a = 123
    def f():
        ...
    
class_name.a
class_name.f()

__init__

依附於類別的變數,用 __init__ 來定義

class person():
    def __init__(self, name, gender, age):
        self.name = name
        self.gender = gender
        self.age = age
    id = 1 #也可以這樣設定
    
a = person("poemro", "F", 18)
print(a.name, a.gender, a.age)
#poemro F 18

__init__

也可以用關鍵字參數

class person():
    def __init__(self, name, gender, age):
        self.name = name
        self.gender = gender
        self.age = age
    id = 1
    
a = person(name="pomero", age=18, gender="F")
print(a.name, a.gender, a.age)
#poemro F 18

函式

可以在 class 定義函式

class person():
    def __init__(self, name, money, weight):
        self.name = name
        self.money = money
        self.weight = weight
    id = 1
    def eat(self):
        self.money -= 100
        self.weight += 5

p = person("Hey", 1000, 50)
p.eat()
print(p.money, p.weight) #900 55

函式

可以用物件改物件

class person():
    def __init__(self, name, money, weight):
        self.name = name
        self.money = money
        self.weight = weight

class rest():
    def food(self, guest):
        guest.money -= 100
        guest.weight += 5
        
p = person("Hey", 1000, 50)
r = rest()
r.food(p)
print(p.money, p.weight) #900 55

覆寫屬性

如果從外部定義了和類別屬性名稱相同的屬性,就會被覆寫

class person():
    def __init__(self, name, money, weight):
        self.name = name
        self.money = money
        self.weight = weight
    def say(self, text):
        print(f"Hi, {text}")

        
p = person("Hey", 1000, 50)
p.say("hey") #Hi, hey
p.say = "???"
print(p.say) #???

getter & setter

用 getter 去讀取私有成員

用 setter 去修改私有成員

class person():
    def __init__(self, name, money, weight):
        self.name = name
        self.money = money
        self.weight = weight
    def get_salary(self):
        return self.__salary
    def set_salary(self, new_salary):
        self.__salary = new_salary
    __salary = 30000
        
p = person("Hey", 1000, 50)
print(p.get_salary()) #30000
p.set_salary(28000)
print(p.get_salary()) #28000

繼承

繼承 ( inheritance ) 可以延續利用父類別的特性並加以修改

class person():
    def __init__(self, name, money, weight):
        self.name = name
        self.money = money
        self.weight = weight
    
class student(person): #student 繼承 person
    id = 1 #新增 id
    def eat(self, m):
        self.money -= m
        self.weight += m #可以使用 person 的屬性
        
s = student("Hey", 1000, 50)
print(s.id) #1
s.eat(10)
print(s.money, s.weight) #990 60

super( )

可以繼承父類別的方法

class person():
    def __init__(self, name, money, weight):
        self.name = name
        self.money = money
        self.weight = weight
    
class student(person):
    def __init__(self, name, money, weight, id):
        super().__init__(name, money, weight)
        #繼承 parent 的 __init__
        self.id = id
        
        
s = student("Hey", 1000, 50, 1)
print(s.name, s.id) #Hey 1

多重繼承

class meat():
    def __init__(self, source, doneness, kg):
        self.source = source
        self.doneness = doneness
        self.kg = kg
    def cook(self, time):
        if time < self.doneness:
            print("Time is too short.")
            
class bread():
    def __init__(self, kind):
        self.kind = kind
        
class burger(meat, bread): #繼承 meat 跟 bread
    def __init__(self, source, doneness, kg, kind):
        meat.__init__(self, source, doneness, kg)
        bread.__init__(self, kind)
        
b = burger("USA", 7, 10, "rye")
b.cook(6) #Time is too short.

例外處理

try & except

例外處理

When an error occurs, or exception as we call it, Python will normally stop and generate an error message.

These exceptions can be handled using the try statement.

try & except

try: #如果 print(x) 可以執行
    print(x)
except: #如果 print(x) 會有錯誤
    print("Something wrong")
#Something wrong
print(x) #NameError: name 'x' is not defined

如果直接執行 print(x)

使用例外處理,讓程式能繼續運行

except

except 的錯誤訊息

錯誤訊息 說明
NameError 使用沒有被定義的對象
IndexError 索引值超過了序列的大小
TypeError 數據類型 ( type ) 錯誤
SyntaxError 語法規則錯誤
ValueError 傳入值錯誤
KeyboardInterrupt 當程式被手動強制中止
AssertionError 程式 asset 後面的條件不成立
KeyError 鍵發生錯誤
ZeroDivisionError 除以 0
AttributeError 使用不存在的屬性
IndentationError 語法錯誤 ( 沒有對齊 )
IOError Input/output異常
UnboundLocalError 區域變數和全域變數發生重複或錯誤

except

try:
    print(a)
except IndexError:
    print("IndexError")
except NameError:
    print("NameError")
#NameError

在 except 後放錯誤型別

try:
    print(a)
except IndexError:
    print("IndexError")
except Exception as e:
    print(e)
#name 'a' is not defined

except Exception as 變數

可以印出全部的錯誤訊息

pass

try:
    print(a)
except:
    pass

print("hello")
#hello

使用 pass 略過

else

a = input("Input: ")
try:
    a = int(a)
    print(a)
except:
    print("Error")
else:
    print("No error")

如果沒有錯誤,會執行 else

finally

a = input("Input: ")
try:
    a = int(a)
    print(a)
except:
    print("Error")
else:
    print("No error")
finally:
    print("Always print this")

不管有沒有錯誤,都會執行 finally

raise

a = input("Input: ")
print(a)
if not type(a) is int:
    raise TypeError("Only interger are allowed.")
print(f"{a} is int")

可以用 raise 強制中斷程式或拋出錯誤訊息

assert

try:
    a = int(input('Input 0~9:'))
    assert a <= 9, f"{a} is not in range"
    print(a)
except AssertionError as msg:
    print(msg)
except:
    print('sth wrong')
print('Continue')

assert 條件, 訊息

當條件為 False 時會執行

模組

modules

模組

包含 Python 程式碼的檔案,可以引入

import math #引入叫 math 的模組

print(math.floor(123.2)) #使用 math 裡的函式 floor

import

import 模組名稱

import datetime

print(datetime.date.today()) #2024-10-27

from

from 模組名稱 import 方法

from datetime import date

print(date.today()) #2024-10-27

只匯入模組中的某一段程式

as

import 模組名稱 as 別名

import datetime as dd

print(dd.date.today()) #2024-10-27

將模組賦予別名

import python file

可以 import 自己寫的 .py 檔案

.
└── module
    ├── main.py
    └── module.py

#module.py
def square(a, b):
    return a ** b

s = "String from hello"

class stu():
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def infor(self):
        return f"My name is {self.name}, I'm {self.age} years old."
#main.py
from module import square, s, stu

print(square(2, 4))

print(s)

stu1 = stu("pomero", 16)
print(stu1.infor())

印出來的結果:

結束啦 :D

Python - 4

By pomer0

Python - 4

  • 125