跳至主要内容

Python 函數

函數陷阱

預設值是 function 創建後產生的一個物件,
會存在於 function 所在的 scope,形成類似全域的一個變數。
須小心 multable default value,會間接造成預設值不斷改變。

function: multable default value

# function multable default value: list
def string_builder(element: str, arr=[]):
arr.append(element)
print(arr) # 印出當前資料內容
return arr


x = string_builder('A')
# ['A']
y = string_builder('B')
# ['A', 'B'], 資料出現異常累加
z = string_builder('C')
# ['A', 'B', 'C'], 資料再次出現異常累加


# ==> 發生 multable 內容累加情形
print(x)
# ['A', 'B', 'C']
print(y)
# ['A', 'B', 'C']
print(z)
# ['A', 'B', 'C']

函數註釋(Annotation)寫法

Python 雖被定義為直譯式語言且可動態型別綁定,但為了將來好維護,
我還是期待能為函數與變數簡單定義目的預期待型別,並作為團隊慣例。
如此,才能較放心的簡化函數的型別檢查,不然光檢查輸入資料格式就應接不暇。

Annotations Syntax

  • 目前測試變數註釋時發現:
    • 型別或變數敘述似乎只能二擇一
    • 回傳值似乎只能指定型別
    • 匿名函數(lambda 無法寫註釋),冒號被用做定義函數區塊用了

# 變數註解: 變數名:註解=預設值
# 回傳值: 直接填入型別或 None

# 變數敘述
def funcName(varName:'desc'=defaultValue) -> retType:
pass

# 變數型別
def funcName2(varName:int=defaultValuue) -> retType:
pass

Annotations Example


def area(w: 'width' = 10, l: 'length' = 10) -> int:
return w * l
print(area.__annotations__)
# {'w': 'width', 'l': 'length', 'return': <class 'int'>}


def area(w: 'width' = 10, l:int = 10) -> int:
return w * l
print(area.__annotations__)
# {'w': 'width', 'l': <class 'int'>, 'return': <class 'int'>}

Python 函數的屬性(Attributes)

類似"靜態本地"變數(static local)
直接為函數指定一個靜態變數。
必須先為桿變數初始化並賦值後才能使用。

使用情境:
Python 中函數可以是一級成員(first-class object),
所以這邊應該是 Python 以函數抽象物件時的另種作法。

Static Variable: 直接餵 static variable 給一級成員

  • 範例中的變數 count
  • 注意 static 變數的命名方式: 要冠上函數名稱: circleArea.pi
def circleArea(radius: int):
pi = 3.14 # 宣告一個變數 pi
circleArea.pi = pi # 將 pi 轉成 static 成員,且每次初始化時會 reset
pass

circleArea.pi = 3.14159
# define count variable, and init
# or init by invoking foo(x) first
# otherwise: AttributeError: 'function' object has no attribute 'count'

print(circleArea.pi)
print(vars(circleArea))
# 3.14159
# {'radius': 3.14159}

y = circleArea
y.pi += 1 # 導向共用的靜態變數
print(circleArea.pi)
print(vars(circleArea))
# 4.14159
# {'radius': 4.14159}

z = circleArea(10) # reset
print(circleArea.pi)
print(vars(circleArea))
# 3.14
# {'radius': 3.14}

Static functions: 函數一級成員下的 static function

def area():
pi = 3.14

def cricleArea(radius: int):
print("Circle Area = ")
return pi * radius * radius

def squareArea(width: int):
print("Square Area = ")
return width * width

# 此區將成員宣告為 static members
area.cricle = cricleArea
area.square = squareArea
area.pi = pi
return area


a = area()

print(a.square(10))
# Square Area =
# 100

print(a.cricle(10))
# Circle Area =
# 314.0

print(a.pi)
# 3.14

Bound and Unbound Method

函數也可依據綁定關係(Binding)分類:
Bounding 指的是: Method 是否與 class instance 相互綁定

  • binding :
    • method 的 signature 中有 self
    • 使用時需先建立 instance
    • Python 中的 Simple Method
  • Unbinding:
    • method 的 signature 中沒有 self
    • method 冠 @staticmethod annotation
    • Python 中的 Simple Method
    • 使用時部需先建立 instance

同樣是靜態成員: 常數