python函数的目的与意义_python函数与作用域

##函数

– 函数

— 数学定义:y=f(x),y是x的函数,x是自变量

— python函数:由若干语句组成的语句块、函数名称、参数列表构成,它是组织代码的最小单元;完成一定的功能

– 函数的作用

— 结构化编程对代码的最基本的封装,一般按照功能组织一段代码

— 封装的目的是为了复用,减少冗余代码

— 代码简洁,美观

– 函数的分类

— 内建函数,如min()

— 库函数,如math.ceil()等

##函数定义、调用

– def语句定义函数

def函数名(参数列表)

函数体(代码块)

[return 返回值]

— 函数名就是标识符,命名要求一样

— 语句块必须缩进,约定4个空格

— Python的函数没有return语句,隐式会返回一个None值

— 定义中的参数列表成为形式参数,只是一种符号表达,简称形参

– 调用

— 函数定义,只是声明了一个函数,它不会被执行,需要调用

— 调用的方式,就是函数名加上小括号,括号内写上参数

— 调用时写的参数是实际参数,是传入的值,成为实参

##函数参数

– 参数调用时传入的参数要和定义的个数相匹配(可变参数例外)

– 位置参数

— def f(x,y,z) 调用使用f(1,3,5)

— 按照参数定义顺序传入参数

– 关键字参数

— def f(x,y,z)调用使用f(x=1,y=3,z=5)

— 使用形参的名字来出入实参的方式,如果使用了形参名字,那么传参就可以和定义顺序不同

— 传参 f(z=None,y=10,x=[1]) 要求位置参数必须在关键字参数之前传入,位置参数是按位置对应的

##函数参数默认值

— 定义时,在形参后面跟上一个值

def add(x=4,y=5)

return x+y

— 作用 参数的默认值可以在未传入足够的实参的时候,对没有给定的参数赋默认值

def login(host=’127.0.0.1′,port=’8080′,username=’wayne’,passwor=’magedu’):

print(‘{}:{}@{}/{}’.format(host, port, username, password))

login()

login(‘127.0.0.1’, 80, ‘tom’, ‘tom’)

login(port=80, password=’magedu’, host=’www’)

##可变参数

– 可变参数

— 一个参数可以匹配任意个参数

– 位置参数的可变参数

— 在形参前使用*表示该形参是可变参数,可以接收多个实参

— 收集多个实参为一个tuple

– 关键字参数的可变参数

— 配置信息打印

def showconfig(**kwargs):

for k,v in kwargs.items():

print(‘{}={}’.format(k,v))

showconfig(host=’127.0.0.1′,port=’8080′,username=’wayne’,password=’magedu’)

— 形参前使用**符号,表示可以接收多个关键字参数

— 收集的实参名称和值组成一个字典

– 总结

— 有位置可变参数和关键字可变参数

— 位置可变参数在形参前使用一个*

— 关键字可变参数在形参前使用两个星号**

— 位置可变参数和关键字可变参数都可以收集若干个实参,位置可变参数收集形成一个tuple,关键字可变参数收集形成一个dict

— 混合使用参数的时候,可变参数要放到参数列表的最后,普通参数需要放到参数列表前面,位置可变参数需要在关键字可变参数之前

-举例

def fn(x,y,*args,**kwargs):

print(x)

print(y)

print(args)

print(kwargs)

fn(1,2,3,4,5,a=1,b=”abc”)

fn(3,5)

fn(3,2,a=1,b=’abc’)

fn(2,3,x=5,y=6,a=1,b=”asf”) #由于x,y重复赋值 错误

def fn(*args, x, y, **kwargs):

print(x)

print(y)

print(args)

print(kwargs)

fn(3,5) #错误

fn(3,4,5) #错误

fn(3,5,a=1,b=’python’) #错误

fn(7,9,y=5,x=3,a=1,b=’python’) #正确

– keyword-only参数

— 如果在一个星号参数后,或者一个位置可变参数后,出现的普通参数,实际上已经不是普通的参数了,而是keyword-only参数

def fn(*args, x):

print(x)

print(args)

fn(3,5) #错误 缺少x

fn(3,5,7) #错误 缺少x

fn(3,5,x=7) #正确

— 出现def fn(**kwargs,x) 这个情况是错误的。

– keyword-only 另一种形式

— def fn(*,x,y) ‘*’之后的普通参数都变成必须给的keyword-only参数

##函数参数

– 参数规则

— 参数列表一般顺序是,普通参数,缺省参数,可变位置参数,keyword-only参数,可变关键字参数

def fn(x, y, z=3, *arg, m=4, n, **kwargs):

print(x,y,z,m,n)

print(args)

print(kwargs)

##参数解构

– 给参数提供实参的时候,可以在集合类型前使用*或者**,把集合类型的结构解开,提取出所有元素作为函数的实参

– 非字典类型中使用*解构成位置参数

– 字典类型使用**解构成关键字参数

– 提取出来的元素数目要和参数的要求匹配,也要和参数的类型匹配

##练习

-编写一个函数能够接收至少2个参数,返回最小值和最大值

import random

def show(*nums):

print(nums)

return max(nums),min(nums)

print(*show(*[random.randint(1,100) for _ in range(5)]))

-编写一个函数,接收一个参数n,n为正整数,两种打印方式,必须对齐。

上三角

def show(n): #法一

tail = ‘ ‘.join([str(i) for i in range(n,0,-1)])

width = len(tail)

for i in range(1,n):

print(“{:>{}}”.format(” “.join([str(j) for j in range(i,0,-1)]),width))

print(tail)

show(12)

def fn(n): #法二

for i in range(1,n+1):

for j in range(n,0,-1):

if i >= j:

print(‘{}’.format(str(j)),end=” “)

else:

print(‘{}’.format(‘ ‘*len(str(j))),end=” “)

print()

fn(12)

下三角

def showtail(n): #法一

tail = ” “.join([str(i) for i in range(n,0,-1)])

print(tail)

for i in range(len(tail)):

if tail[i] == ‘ ‘:

print(‘ ‘*i,tail[i+1:])

showtail(12)

def fn(n): #法二

for i in range(n,0,-1):

for j in range(n,0,-1):

if i >= j:

print(‘{}’.format(str(j)),end=” “)

else:

print(‘{}’.format(‘ ‘*len(str(j))),end=” “)

print()

fn(12)

##插入排序

– 原理

— 在未排序序列中,构建一个子排序序列,直至全部数据排序完成;将待排序的数,插入到已经排序的序列中合适的位置;增加一个哨兵,放入待比较的值,让它和后面已经排好的序列比较,找到合适的插入点

– 性能

— 最好的情况,n-1次;最差的情况n(n-1)/2;

— 使用两层嵌套循环,时间复杂度O(n^2)

— 稳定排序算法

— 使用在小规模的数据比较

— 可以用二分法来优化

实现

lst = [1,5,2,9,7,8,4,6,3]

lst = [0] + lst

for i in range(2,len(lst)):

lst[0] = lst[i]

j = i – 1

if lst[j] > lst[0]:

while lst[j] > lst[0]:

lst[j+1] = lst[j]

j -= 1

lst[j+1] = lst[0]

print(lst[1:])

##函数返回值

– python函数使用return语句返回“返回值”

– 所有函数都有返回值,如果没有return语句,隐式调用return None

– return语句不一定是函数的语句块的最后一条语句

– 一个函数可以存在多个return语句,但是只有一条可以被执行。

– return None可以简写成return

– 如果函数执行return语句,函数就会返回,当前被执行的return语句之后的其它语句就不会被执行了

– 作用:结束函数调用、返回值

– return [1,3,5] 是指返回了一个列表,是一个列表对象

– return 1,3,5 其实是被python封装成了一个元组

## 解构

def showlist():

return 1,2,3

x,y,z = showlist() #使用解构提取更为方便

## 举例

def fn(x):

for i in range(x):

if i > 3:

return i

else:

print(‘{} is not greater than 3′.format(x))

# print(fn(5)) 结果返回了4

# print(fn(3)) 结果是3 is not greater than 3

##函数嵌套

– 在一个函数中定义了另外一个函数

##

def outer():

def inner(): #内部函数不能被外部直接使用,会抛出NameError异常

print(“inner”)

print(“outer”)

inner()

outer()

inner()

##作用域

– 一个标识符的可见范围,这就是标识符的作用域。一般常说的是变量的作用域

– 全局作用域:整个程序运行环境中都可见

– 局部作用域:在函数、类等内部可见,局部变量使用范围不能超过其所在的局部作用域

##

def outer1():

o = 65

def inner():

print(“inner {}”.format(o)) #此处的o调用outer1函数里的o

print(chr(o))

print(“outer {}”.format(o))

inner()

outer1()

def outer2(): #

o = 65

def inner():

o = 97 #这个o是重新定义的,没有覆盖上面的o

print(“inner {}”.format(o)) #此处的o调用本地o的值97

print(chr(o))

print(“outer {}”.format(o))

inner()

outer2()

**错误举例**

![](leanote://file/getImage?fileId=59deda9e1b524f2c5b000001)

– 它相当于在foo函数内部定义了局部变量x,所以foo内部所有x都是这个局部变量x。但是这个x还没有被完成赋值,就做加1操作。发生错误

**改变方法:global**

##

x=5

def foo():

global x #全局变量

x = 10 #赋值即定义,把x重新变成10

x += 1

print(x) #输出11

print(x)

##global使用原则

– 外部作用域变量会内部作用域可见,但也不要在这个内部的局部作用域中直接使用,因为函数的目的就是为了封装,尽量与外界隔离

– 如果函数需要使用外部全局变量,请使用函数的形参传参解决

##闭包

– 自由变量:未在本地作用域中定义的变量。例如定义在内层函数外的外层函数的作用域中的变量

– 闭包:内层函数引用到了外层函数的自由变量,就形成了闭包。

##例子

def counter():

c = [0]

def inc():

c[0] += 1 #c已经定义,inc中的使用方式为c的元素修改值

return c[0]

return inc

foo = counter()

print(foo(),foo()) # 打印 1 2

c = 100

print(foo()) # 打印 3 它引用的是inc中的变量c

##**nonlocal关键字**

– 使用nonlocal关键字,将变量标记为在上级的局部作用域中定义,但不能全局中定义

##举例

def counter():

count = 0

def inc():

nonlocal count #它声明count变量在上一级作用域中

count += 1 #形成了闭包

return count

return inc

foo = counter()

foo()

foo()

##默认值的作用域

##举例

def foo(xyz = []):

xyz.append(1)

print(xyz)

foo() # [1]

foo() # [1,1]

print(xyz) #报错,xyz没有定义

#为什么打出[1,1]因为,函数也是对象,python把函数的默认值放在了属性中,这个属性就伴随着这个函数对象的整个生命周期。查看foo.__defaults__

## 默认值引用类型

def foo(xyz=[], u=’abc’, z=123):

xyz.append(1) # xyz默认值是引用类型,元组不会变化。

return xyz

print(foo(), id(foo))

print(foo.__defaults__)

print(foo(), id(foo))

print(foo.__defaults__)

## 默认值的作用域

– 可变类型默认值,如果使用默认值,就可能修改这个默认值

– 有时候这个特性好,但是有副作用

##解决方法两种

def foo(xyz=[], u=’abc’, z=123):

xyz = xyz[:] # 影子拷贝

xyz.append(1) # xyz都是传入参数或者默认参数副本,不能修改原参数

print(xyz)

foo()

print(foo.__defaults__)

foo()

print(foo.__defaults__)

foo([10])

print(foo.__defaults__)

foo([10,5])

print(foo.__defaults__)

(2)

def foo(xyz=None, u=’abc’, z=123):

if xyz is None: #使用不可变类型的默认值

xyz = [] # 若缺省值None就创建一个列表

xyz.append(1) #如果传入一个列表,就修改这个列表

print(xyz)

##函数的销毁

### 全局销毁

– 重新定义同名函数

– del语句销毁函数对象

– 程序结束时

### 局部销毁

– 重新再上级作用域定义同名函数

– del语句删除

– 上级作用域销毁时

本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/87921

你可能感兴趣的:(python函数的目的与意义)