5 min read

Python Learning 4 函数与参数

Function功能将一堆代码抽象成一个函数,只有调用函数的时候,代码才会运行。函数的编辑使代码可以被一次编辑,多次调用。以下是Python中函数的定义语法:

def function_name(parameters):
    expressions

Python使用def(define)开始函数定义,紧接着是函数名,括号内部为函数的参数,冒号之后缩进的部分是函数内的代码块,如果想要函数有返回值,在expressions中的代码中用return返回。

# Defining a function
def myFunction():
    a = 1 + 2
    print(f"sum is {a}")

myFunction() # Calling a function
sum is 3

参数传递和返回值

def function_name(parameters):
    expressions

parameters的位置就是函数的参数,在调用的时候传入即可。

# Positional Arguments
def describe_person(name, age):
  print(f'{name} is {age} years old.')
describe_person('enoch', 25)

# Multiple Function Calls
describe_person('enoch', 23)
describe_person('enoch', 26)

# Order matters in positional arguments
describe_person('enoch', 25)

# Order doesn't matter if you specify keyword arguments
describe_person(age=25, name='enoch')
enoch is 25 years old.
enoch is 23 years old.
enoch is 26 years old.
enoch is 25 years old.
enoch is 25 years old.

我们也可以为函数提供备选的参数,在调用函数时,如果不传递参数,函数将会使用设定好的默认参数:注意=前后不能有空格

# Default values
def describe_pet(pet_name, animal_type='dog'):
  print(f'{pet_name} is a {animal_type}')

describe_pet('doudou')
describe_pet('duoduo', 'cat')
doudou is a dog
duoduo is a cat

除了基本的数据类型,我们也可以将列表等其他数据类型当做参数传入:

fruits = ["a", "b", "c"]
def myFun(food):
    for x in food:
        print(food)

# Modifying a List in a Function
def set_to_one(input):
  for i in range(0, len(input)):
    input[i] = 1

number_list = [1, 2, 3, 4, 5]
set_to_one(number_list)
print(number_list)

# Preventing a Function from modifying a list
# 进行切片操作,重新生成一个变量,这样不会改变原来的值
number_list2 = [1, 2, 3, 4, 5]
set_to_one(number_list2[:])
print(number_list2) 
[1, 1, 1, 1, 1]
[1, 2, 3, 4, 5]

可变参数

如果我们有很多参数要传入函数,可以将这些参数封装成一个list或tuple传入,但这样不够pythonic。我们可以使用可变参数,可变参数代表传入的参数量是不定量的。注意可变参数的定义不能出现在特定参数和默认参数前面,否则会吞噬掉这些参数,以下是可变参数的实例:

def report(name, *grades):
    total_grade = 0
    for grade in grades:
        total_grade += grade
    print(name, 'total grade is ', total_grade)

report('Ben', 80, 90, 85)
Ben total grade is  255

这里的参数grades前面有*修饰,代表该参数是一个可变参数。那么当我们调用函数的时候,我们可以在name之后输入多个参数,这些参数被调用的时候,就会被函数迭代。

  • 必须是最后一位

关键字参数

我们可以使用关键字参数传入任意个含参数名的参数,这些参数名在函数定义时不用指定,在函数内部这些参数会被自动封装成字典类型(dict):

def info(name, **kw):
    print('name is', name)
    for k,v in kw.items():
        print(k, v)

info('Mike', age=24, country='China', education='bachelor')
name is Mike
age 24
country China
education bachelor

Return语句

Return语句用于退出函数,并返回一个指定值。也就是将结果返回到调用的地方,并把程序控制权一起返回。不带参数值的return语句默认返回None。以下是return的演示:

# Returning a simple value
def get_formatted_name(first_name, last_name):
  return f'{last_name.title()} {first_name.title()}'

print(get_formatted_name('hao', 'zheng'))
Zheng Hao

使用条件判断,我们可以根据不同参数返回不同的内容:

# Making an argument optional
def proposal(name, age):
  if age >= 18:
    return f'{name}, I want to marry you.'
  else:
    return f'{name}, I can\'t marry you right now'

print(proposal('Emily', 16))
print(proposal('Emily', 20))
Emily, I can't marry you right now
Emily, I want to marry you.

返回一个字典:

# Returning a dictionary
def build_person(first_name, last_name):
  person = {'first': first_name, 'last': last_name}
  return person

musician = build_person('hao', 'zheng')
print(musician['first'] + ' ' + musician['last'])
hao zheng

函数名规范

如果你给一个变量设定默认值,那么等号的两边是不应该有空格的,调用的时候也是一样:

如果有很多参数,那么其他行参数的缩进应该与第一行的参数缩进对应:

def function_name(
    parameter_0, parameter_1, parameter_2,
    parameter_3, parameter_4, parameter_5):
    function body...

局部和全局变量

在def中,我们可以定义一个局部变量,这个变量x只能在函数fun中有效。出了函数,x就不能被调用了。而且即使在函数中修改了相同名字的变量,出了函数,修改是起不到作用的:

y = 2
def fun():
    x = 1
    y = 1
    print(x)

print(y)
print(x) 
2



---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)

d:\project\packages\Python\Python函数和参数.ipynb Cell 28 in <cell line: 8>()
      <a href='vscode-notebook-cell:/d%3A/project/packages/Python/Python%E5%87%BD%E6%95%B0%E5%92%8C%E5%8F%82%E6%95%B0.ipynb#ch0000047?line=4'>5</a>     print(x)
      <a href='vscode-notebook-cell:/d%3A/project/packages/Python/Python%E5%87%BD%E6%95%B0%E5%92%8C%E5%8F%82%E6%95%B0.ipynb#ch0000047?line=6'>7</a> print(y)
----> <a href='vscode-notebook-cell:/d%3A/project/packages/Python/Python%E5%87%BD%E6%95%B0%E5%92%8C%E5%8F%82%E6%95%B0.ipynb#ch0000047?line=7'>8</a> print(x)


NameError: name 'x' is not defined

如何在函数内部修改某个变量,并让这个修改保下去呢?我们在内部调用的时候,就要使用global关键字,这样我们在函数内部的操作也会保存下来:

x = 2
def fun():
    global x
    x = 1
fun()
print(x)
1

模块函数调用

如果我们想在其他文件调用pizza.py中的函数时,使用import语句就好了:

# Importing an Entire Module (pizza.py)
import pizza
pizza.make_pizza(16, 'pepperoni')

# Using as to Give a Module an Alias # 给模块取不同的名字
import pizza as p
p.make_pizza(16, 'cheese')

# Importing Specific Functions # 只想调用其中的一个函数
from pizza import make_pizza
make_pizza(16, 'cheese')

# Using as to Give a Function an Alias
from pizza import make_pizza as mp
mp(16, 'cheese')

# Importing All Functions in a Module
from pizza import *
make_pizza(16, 'green peppers')

Lamda函数

Lambda函数也叫做匿名函数,及没有具体名称的函数。一个Lambda函数可以使用任意多的参数,但是只能有一个表达式:

x = lambda a, b, c: a + b + c
print(x(5, 6, 2)) # 12
13

为什么使用Lamda函数?当我们把lambda函数放在一个函数内部使用的时候,lambda可以很简洁地帮助我们实现小功能

def myFun(n):
    return lambda a: a * n
myTripler = myFun(3)
print(myTripler(11))

递归函数

递归函数就是一个调用自己本身的函数。如果我们要计算阶乘 n! = 1 x 2 x 3 x … x n,用函数fact(n)表示则为:fact(n) = n! = 1 x 2 x 3 x … x (n-1) x n = (n-1)! x n = fact(n – 1) x n,用递归的方式写出来就是:

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

递归函数逻辑清晰,定义也简单。理论上所有递归函数都可以写成循环的方式,但逻辑不如递归清晰。

程序入口判断

有时我们希望某文件被当做模板引进的时候,部分代码不要被执行。如果当前脚本含有单元测试,那么我们在其他地方调用此脚本的时候,测试部分就没有必要了。我们可以做以下的条件判断:

if __name__ == '__main__':
    # statements

如果当前文件只是被作为模块引进的话,在程序运行时,statements部分的代码是不会被执行的。

Homework

list1 = [1, 2, 3]
list2 = [4, 5, 6]
list3 = [4, 5, 6, 7, 8]
def addSum(
    list1, list2
):
    sum = []
    length1 = len(list1)
    length2 = len(list2)
    if length1 <= length2:
        for i in range(length1):
            temp_sum = list1[i] + list2[i]
            sum.append(temp_sum)
        for j in range(length2-length1):
            sum.append(list2[length1+j])
        return sum
    if length1 > length2:
        for i in range(length2):
            temp_sum = list1[i] + list2[i]
            sum.append(temp_sum)
        for j in range(length2-length1):
            sum.append(list2[length1+j])
        return sum 


addSum(list1, list2)
addSum(list1, list3)
[5, 7, 9, 7, 8]
list1 = [1, 2, 3, 5]
list2 = [2, 4, 9, 10, 12, 48]
sum = []
def myFun(list1, list2, sum):
    shorterList, longerList = [], []
    if len(list1) <= len(list2):
        shorterList, longerList = list1, list2
    else:
        shorterList, longerList = list2, list1
    for i in range(len(shorterList)):
        sum.append(shorterList[i] + longerList[i])
    for i in range(len(shorterList), len(longerList)):
        sum.append(longerList[i])

myFun(list1, list2, sum)
print(sum)
[3, 6, 12, 15, 12, 48]