Python 全攻略 第8節:Chapter4 - Functions and Methods (54-66)

▌Functions (函式) and Methods (方法)

Functions
Functions are not associated with any object.
ex. range() is a function

Methods
Methods are associated with the objects of the class they belog to.
ex. string.spilt(“”) is method of string
物件可做的事情就是methods

▌help() 使用方法

若為 Functions 可以直接使用函式名稱進行查詢,若為 Methods 必須加上物件,才能進行查詢,因此可以利用help()簡便辨別兩者。

help(range)

Help on class range in module builtins:

class range(object)
| range(stop) → range object
| range(start, stop[, step]) → range object

help(.split)

SyntaxError: invalid syntax

help(str.split)

Help on method_descriptor:

split(self, /, sep=None, maxsplit=-1)
Return a list of the words in the string, using sep as the delimiter string.

help(.append)

SyntaxError: invalid syntax

help(list.append)

Help on method_descriptor:

append(self, object, /)
Append object to the end of the list.

▌ 參數 (Parameter) vs. 引數 (Argument)

def funtionName(input1, input2, …):
funtion code here

def addition(x, y, z): # x, y, z are parameters(參數)
      print(x + y + z)
    
addition(2, 3, 5) # 2, 3, 5 are the arguments(引數)

▌Copy by value vs. Copy by reference

Inputs are the local variables in the function; they are either copy by value or reference.

Copy by value Copy by reference
int, float, str, bool list, dict, tuple, set
當b = a時,b與a指向相同的記憶體位置,Copy by value 與 Copy by reference區別在於,當a是不可變的(immutable)數值時,a修改內容會創造一個新的記憶體位址,而原本的b仍指向原本的位址,所以b的數值不會隨a的修改而改變,因此屬於 Copy by value (參照的數值無法改變,算直接copy value) 當a是可變的(mutable)數值時,a會在原記憶體位址修改內容,當b指向時,會參照到修改後的內容,因此屬於 Copy by reference (參照的數值會隨著修改內容改變)

Copy by value

# id() 函數可以取得物件的識別碼,它會回傳一個整數,代表該物件在記憶體中的位置。
a = 20
id(a) # 4369161280
b = a
id(b) # 4369161280
a = 30
id(a) # 4369161600
id(b) # 4369161280

Copy by reference

# id() 函數可以取得物件的識別碼,它會回傳一個整數,代表該物件在記憶體中的位置。
a = [1, 2, 3, 4]
id(a) # 4372402368
b = a
id(b) # 4372402368
a.append(100)
a # [1, 2, 3, 4, 100]
id(a) # 4372402368
b # [1, 2, 3, 4, 100]

▌global variables (全域變數) vs. local variables (區域變數)

a = 10 # global variable

# parameters (inputs) are Local variables in the function
def change(num):
    num = 25 # local variable 
		     # num = a (copy by value => num = 10)
change(a)
print(a) # 10
a = [1, 2, 3, 4]

def change(lst):
    lst[0] = 100 # lst = a (copy by reference => a = [100, 2, 3, 4])

change(a)
print(a) # [100, 2, 3, 4]

如果想在函式中修改全域變數中所存放的值,就要先對該變數用 global 陳述句宣告。

def spam():
    global eggs
    eggs = 'spam' # this is the global

def bacon():
    eggs = 'bacon' # this is a local

def ham():
    print(eggs) #this is the global

eggs = 42 # this is the global
spam()
print(eggs) # spam

▌Return 用法

return 之後的程式碼都不會被執行

def myAddition(a, b):
    result = a + b
    return result
    print(result) # 這行要移到 return 前面,才會 print 出值為 7
    
myAddition(3, 4) # 回傳為空

return 出現在nested loop會使程式強制中止

def myAddition(a, b):
    for i in range(a):
        for j in range(b):
            if i == 2 and j == 1:
                return
            print(i, j)

myAddition(3, 3) # 00 01 02 10 11 12 20

▌*args 與 **kwargs 使用方式

  • *args (arguments) is used when we want to send an arbitrary number of non-keyworded inputs to function.
  • **kwargs (keyworded arguments) is used when we want to send an arbitrary number of keyworded inputs to a function.
  • You can change the names of args and kwargs. (*args → *apple, **kwargs → **pear)
  • Function input definition order should be (1) normal parameters (2) default parameters (3) *args (4) **kwargs
def sum(*args):
    print(type(args))
    result = 0
    for number in args:
        result += number
    return result

print(sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) 
# <class 'tuple'>
# 55
def myfunc(**kwargs):
    print(type(kwargs))
    print(kwargs)

myfunc(name="Wilson", age=25, address="Taiwan")
#'<class 'dict'>
#{'name': 'Wilson', 'age': 25, 'address': 'Taiwan'}
def myfunc(*args, **kwargs):
    print("{} would like to eat {} {}".format(kwargs["name"], args[1], kwargs["food"]))

myfunc(14, 17, 23, name="Wilson", food="eggs")
# Wilson would like to eat 17 eggs
# 1. normal argument (p1, p2)
# 2. default argument (p3="three")
# 3. *args
# 4. **kwargs

def func(p1, p2, p3="three", *args, **kwargs):
    print(p1, p2, p3, args, kwargs)

func(1, 2, 5, 6, 7, x=1, y=3)
# 1 2 5 (6, 7) {'x': 1, 'y': 3}

▌Lambda Expression

  • We use lambda functions when we require a nameless function for a short period of time.
  • The value computed by lambda expression will be returned automatically.
lambda 參數: return 表達式
lambda input1, input2, ...: operation

def func(input1, input2, ...):
    operation
    return value
def square(x):
    square = x ** 2
    print(square)

square = lambda x: x ** 2
square(3) # 9
def abs_number(x):
    if x >= 0:
        print(x)
    else:
        print(-x)

abs_number = lambda x : x if x >= 0 else -x
abs_number(-10) # 10

應用 list comprehension

'''
new_list = [new_item for item in list if test]
'''
lst = [1, 2, 3, 4, 5]
lst2 = [x*2 for x in lst]
print(lst2) 
#[2, 4, 6, 8, 10]

使用 map() 搭配 lambda

'''
map(func, *iterables) --> map object
'''
lst = [1, 2, 3, 4, 5]
print(list(map(lambda x: x*2, lst))) # [2, 4, 6, 8, 10]
#[2, 4, 6, 8, 10]

把內有「anonymous」的字串標記出來

txt = ['lambda functions are anonymous functions.',
       'anonymous functions dont have a name.',
       'functions are objects in Python.']

mark = [(True, s) if 'anonymous' in s else (False, s) for s in txt]
print(list(mark))
# [(True, 'lambda functions are anonymous functions.'), 
# (True, 'anonymous functions dont have a name.'), 
# (False, 'functions are objects in Python.')]

可以使用 lambda 搭配 map() 改寫

mark = map(lambda s: (True, s) if 'anonymous' in s else (False, s), txt)
print(list(mark))
# [(True, 'lambda functions are anonymous functions.'), 
# (True, 'anonymous functions dont have a name.'), 
# (False, 'functions are objects in Python.')]

▌LEGB rule (variable由內而外找 Local→Enclosing→Global→Built-in)

Local scope
Local scope refers to the name(variable, function and so on) that is defined inside the function. It means it is accessible within the point at it is defined until the end of the function. That particular scope can’t be modified or even accessed outside of the function.

var = 'global'    
def L():    
    var = 'local'        
    print(var)

L()  # 當function有定義local scope時,會優先使用local scope 
     # local

Enclosing scope
Enclosing scope is kind of scope that exists only in nested functions (A function defined inside another function is called a nested function). The enclosing scope is visible only for inner and enclosing functions.

var = 'global'
def LE():    
    var = 'enclosed'    
    def inner():        
        print(var)    
    inner()

LE()  # 當function沒有local scope時,會往外找enclosed scope
      # enclosed

Global scope
Global scope contains all the names(variables, functions, objects and so on) that you define at the highest level in your program. It means that we can use that names from anywhere we wish.

var = 'global'
def LEG():    
    print(var)

LEG()  # 當local和enclosed都沒有時,會往外找global
       # global

Built-in Scope
Built-in scope has the widest accessibility among other scopes. We can give examples such as keywords, functions, and other attributes that are built into Python(We can call the keywords anywhere within our program without defining them).

def id(var):    
    return 'global id()'

def LEGB(var):    
    print(id(var))    
    print(str(var))
        
LEGB('Build-in str()')  # 當有定義global function,會呼叫global function,否則會呼叫 Build-in function
                        # global id()
                        # Build-in str()

▌參考資料

**初學 Python Day Seven— Copied by Value and Copied by Reference**

https://medium.com/@g0972222165/初學-python-day-seven-copied-by-value-and-copied-by-reference-916b5383133d

程式界的哈姆雷特 —— Pass by value, or Pass by reference?

[Python] pythonic 思維:lambda, map

https://medium.com/程式乾貨/python-pythonic-思維-lambda-map-8034fd8bc493

namespace與LEGB scope規則

https://qiubite31.github.io/2016/11/02/namespace與LEGB-scope規則/

[書籍] Python 自動化的樂趣

https://www.gotop.com.tw/books/bookdetails.aspx?types=a&bn=ACL058100

[書籍] Python 不廢話,一行程式碼

https://www.gotop.com.tw/books/BookDetails.aspx?Types=v&bn=ACL060300

3 Likes