Function & Class

Python - Lesson 4

講師:溫室蔡

什麼是函式

什麼是函式

f (x) = 2x + 3

f (3) = 9

f (7) = 17

Python 中的函式

def f(x):
    return 2*x + 3

print(f(3)) # 9
print(f(7)) # 17

函式語法

def 函數名稱(參數1, 參數2, ...):
    # 你要做的事情
    # ...
    # ...
    return 回傳值

P.S. "def" 是 "define"(定義)的意思

函式不一定要回傳值

def greet(name):
    s = 'Hello, ' + name + '!'
    print(s)

greet('John') # Hello, John!
greet('Mike') # Hello, Mike!

變數作用範圍

def greet(name):
    s = 'Hello, ' + name + '!'
    print(s)

greet('John') # Hello, John!
greet('Mike') # Hello, Mike!

print(s) # NameError: name 's' is not defined

在函式內定義的變數

只作用於函式範圍內

遞迴(recursion)

def fact(n):
    if n == 1:
        return 1
    return n * fact(n-1)

在函式當中呼叫自己

遞迴範例:階乘

def fact(n):
    if n == 1:
        return 1
    return n * fact(n-1)

1! = 1

n! = n (n – 1)!

4! = 4×3×2×1

    = 4×3!

遞迴範例:費氏數列

a1 = 1

a2 = 1

an = an–1 + an–2

1, 1, 2, 3, 5, 8, 13, 21, 34, ...

遞迴範例:費氏數列

a1 = 1

a2 = 1

an = an–1 + an–2

def fib(n):
    if n == 1 or n == 2:
        return 1
    return fib(n-1) + fib(n-2)

Python 函式小技巧

回傳多個值

def max_min(n):
    a = max(n)
    b = min(n)
    return a, b

n = [8, 4, 3, 7, 1]
x, y = max_min(n)
print(x) # 8
print(y) # 1

參數預設值

def greet(name, time='morning'):
    print(f'Good {time}, {name}!')

greet('John') # Good morning, John!

greet('John', 'evening')
# Good evening, John!

greet('John', 'night')
# Good night, John!

不定數目參數

def double(*a):
    for i in a:
        print(i*2)

double(3) # 6
double(2, 3, 4)
# 4
# 6
# 8

把函式當參數

def vfunc(a, f):
    n = []
    for i in a:
        n.append(f(i))
    return n

def plus_one(x):
    return x+1

def square(x):
    return x*x

x = [1, 2, 3]
print(vfunc(x, plus_one)) # [2, 3, 4]
print(vfunc(x, square))   # [1, 4, 9]

Class(類別)

定義一個物件(object)

每個物件會有自己的變數

稱為屬性(attribute)

以及自己的函式

稱為方法(method)

例:人有名字(屬性,字串)

體重(屬性,數字)

會吃東西(方法)

寫一個 Class

class Person:
    def __init__(self, name, height, weight, money):
        self.name = name
        self.height = height
        self.weight = weight
        self.bmi = weight / (height/100)**2
        self.money = money

p = Person('Justin', 170, 60, 1000)
print(p.name)   # Justin
print(p.height) # 170
print(p.weight) # 60
print(p.bmi)    # 20.76
print(p.money)  # 1000

Class 語法

class 類別名稱:
    def __init__(self, 參數1, 參數2, ...):
        self.屬性1 = 值1
        self.屬性2 = 值2
        # ...
        # 其他一開始要做的事

變數 = 類別名稱(參數1, 參數2, ...)

__init__() 是 initialization 的意思

也就是「初始化」

在物件被建立的時候

先做一些設定之類的事

Class 範例:Food

class Food:
    def __init__(self, name, price, kcal):
        self.name = name
        self.price = price
        self.kcal = kcal

foods = []
foods.append(Food('apple', 50, 70))
foods.append(Food('banana', 30, 100))
foods.append(Food('orange', 40, 50))

print(foods[0].name)  # apple
print(foods[1].price) # 30
print(foods[2].kcal)  # 50

寫一個方法

class Person:
    def __init__(self, name, height, weight, money):
        self.name = name
        # 以下略
    def eat(self, food):
        if self.money < food.price:
            print('Too expensive')
            return
        self.money -= food.price
        self.weight += food.kcal / 100
        print(f'{name} ate a {food.name}!')

p = Person('Justin', 170, 60, 1000)
f = Food('apple', 50, 70)
p.eat(f)        # Justin ate a apple!
print(p.money)  # 950
print(p.weight) # 60.7

寫一個方法

class Person:
    # ...
# ...
p.eat(f)
print(p.weight) # 60.7 (增加了)
print(p.bmi)    # 20.7 (沒跟著改)

self.bmi 與 self.weight 連動

self.eat() 改了 self.weight

但沒改到 self.bmi

成員權限

其中 private 成員只能被自己內部存取

前面加兩條下劃線可讓成員變成 private

class Example:
    def __init__(self):
        self.x = 10   # public
        self.__y = 20 # private

a = Example()
print(a.x)   # 10
print(a.y)   # AttributeError
print(a.__y) # AttributeError

class 的成員分成 public 跟 private

成員權限

class Example:
    def __init__(self):
        self.x = 10   # public
        self.__y = 20 # private

    def y():          # Getter
        return self.__y
    
    def set_y(value): # Setter
        self.__y = value

a = Example()
print(a.y()) # 20
a.set_y(37)
print(a.y()) # 37

如果要存取 private 成員

就要寫 getter 跟 setter

分別用來取值與賦值

成員權限

class Person:
    def __init__(self, name, height, weight, money):
        # ...
        self.__weight = weight
        # ...
    def weight():           # Getter
        return self.__weight

    def set_weight(weight): # Setter
        self.__weight = weight
        self.bmi = weight / (self.height/100)**2

    def eat(self, food):
        # ...
        self.set_weight(self.weight() + food.kcal / 100)
        # ...
# ...
p.eat(f)          # Justin ate a apple!
print(p.weight)   # AttributeError: type object 'Person' has no attribute 'weight'
print(p.__weight) # AttributeError: type object 'Person' has no attribute '__weight'
print(p.weight()) # 60.7
print(p.bmi)      # 21.0

繼承(inheritance)

若 B 繼承了 A

B 會有 A 的

所有屬性與方法

同時還能

再為 B 定義

專屬的成員

class A:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def do_a(self):
        print('I can do A')

class B(A):
    def __init__(self, x, y, z):
        super().__init__(x, y)
        self.z = z
        
    def do_b(self):
        print('It is possible for me to do B')

p = A(1, 2)
q = B(3, 4, 5)
print(p.x) # 1
print(q.x) # 3
print(q.z) # 5
p.do_a() # I can do A
q.do_a() # I can do A
q.do_b() # It is possible for me to do B

繼承語法

class 類別名稱B(被繼承的類別A):
    def __init__(self, A的參數, B自己的參數):
        super().__init__(A的參數) # 跑一遍 A 的 __init__()
        self.B自己的參數1 = 值1    # 自己的參數自己 init
        self.B自己的參數2 = 值2
        # ...
        
    # 自己的方法自己寫
    def B自己的方法1(self, 參數1, 參數2, ...):
        # ...
    
    def B自己的方法2(self, 參數1, 參數2, ...):
        # ...
    #...

繼承範例:Student

class Person:
    # ...

class Student(Person):
    def __init__(self, name, height, weight, money, iq):
        super().__init__(name, height, weight, money)
        self.iq = iq
        self.grades = {}
        
    def study(self, hours):
        self.iq += hours / 10
        
    def take_test(self, subject, luck):
        score = int(iq/150 * 100 * luck)
        self.grades[subject] = score
        if (score > 80):
            money += 100

s = Student('Justin', 170, 60, 300, 120)
s.eat(Food('apple', 50, 70)) # Justin ate a apple!
s.study(2)
print(s.iq)                  # 120.2
s.take_test('math', 0.9)
print(s.grades['math'])      # 72

謝幕

講到這邊也夠了

如果想學更多物件導向的話

歡迎來上星期三的專案建置小社