初识函数
认识函数:在一个完整的项目中,某些功能会反复的使用,那么会将功能封装成函数,当我们要使用的时候直接调用函数即可
本质:对功能的封装
优点:
简化代码结构,增加了代码的复用度
如果想要修改某些功能或者debug,只需要修改对应的函数即可
定义函数
#格式:
def 函数名(参数列表):
语句
return 表达式
函数名:遵循标识符规则
参数列表(参数1,参数2,参数3……,参数n):调用者给函数的信息,任何传入参数(变量)必须放在小括号中,以逗号分隔
():参数列表的开始和结束
语句:函数封装的功能
return:结束函数,并返回信息给函数的调用者
表达式:要返回给调用的信息
注意:最后的return 表达式 可以不写
def myPrint():
print("sunck is a good man!")
无参无返回值函数
def myPrint():
print("sunck is a good man!")
函数的调用
格式:函数名(参数列表)
函数调用的本质:实参给形参赋值的过程
含参函数
需求,编写一个函数,给函数一个字符串和一个年龄,在函数内部打印出来
def myPrint(str, age):
print(str,age)
实参(实际参数):调用函数时给函数传递的数据,本质是值
形参(形式参数):定义函数时小括号中的变量,本质是变量
传参的过程实际上是实参给形参赋值的过程
参数必须按顺序传递,个数目前来看要对应
含返回值函数
需求:给函数两个数,返回这两个数的和
def add(num1, num2):
return num1 + num2
res = add(1,3)
print(res)
传递参数
- 分类
- 值传递:传递的是不可变类型,如tuple,string,number
- 引用传递:传递的可变类型,如list,set,dict
#值传递
def func1(num):
num = 10
temp = 20
func1(temp)
print(temp)
#引用传递
def func2(myList):
myList[0] = 100
list1 = [1,2,3,4,5]
func2(list1)
print(list1)
注意:对于大多数开发语言来说,基本数据类型的变量都存在栈区,对象类型的都存在堆区,常量存在常量区,代码存在代码段
对于常量,存储在常量区,变量存储的是数据的地址,如果两个变量的值相同,则指向常量区的同一个数据,故如果用id()打印两个变量的地址,结果相同
a = 10
b = 10
print(id(a),id(b)) #输出结果相同
关键字参数
允许函数调用的时参数的顺序与定义时不一样,python解释器能够用参数名字匹配匹配参数
- 是否显示指定参数,要一方便自己阅读为目的
def myPrint(str,age):
print(str,age)
myPrint(age=18,str="sunck is a good man")
默认参数
概念:调用函数时,如果没有传递参数,则使用默认参数
如果要用默认参数,最好将默认参数放到最后
def myPrint(str="sunck is a good man", age = 18)
print(str,age)
myPrint()
def myPrint2(str, age = 18):
print(str,age)
myPrint2("sunck is a good man")
不定长参数
def:能处理比定义时更多的参数
形式一
def func(name, *arr): #arr可以为任意符合规范的标识符
print(name)
for x in arr:
print(x)
加了星号(*)的变量存放所有的未命名的变量参数,如果在函数调用时没有指定参数,它就是一个空元组
def mySum(*arr):
sum = 0
for x in arr:
sum += x
return sum
print(1,2,3,5,6)
形式二
必须以关键字形式传递参数
**代表键值对的参数字典,和*所代表的意义类似
def func2(**kwargs): #kwargs为字典
print(kwargs)
print(type(kwargs))
func2(x=1,y=2)
小结
def f(*t):
print(t)
f(*(1,2,3,4)) # *在此处相当于拆包,在形式参数位置相当于打包,**类似
def ff(**kw):
print(kw)
ff(**{"name":"aodongbiao","age":23})
可以接受任意参数
def func3(*args, **kwargs):
pass
匿名函数
概念:不使用def这样的语句定义函数,使用lambda来创建匿名函数,返回值就是表达的结果
- 特点:
- lambda只是一个表达式,函数体比def简单
- lambda的主体是一个表达式,而不是代码块,仅仅只能在lambda表达式中封装简单的逻辑
3.lambda函数有自己的命名空间,且不能访问自由参数列表之外的或全局命名空间里的参数 - 虽然lambda是一个表达式,而且看起来只能写一行,但是与C和C++里面的内联函数不同
格式:lambda 参数1,参数2……,参数n:epxreesion
#求两个数的和
sum = lambda num1,num2:num1+num2
print(sum(1,2))
stus=[{"name":"zhangsan","age":23,"sex":"male"},
{"name":"lisi","age":12,"sex":"femaile"}
]
print("排序前:",stus)
# 根据年龄排序
res=sorted(stus,key=lambda x:x["age"])
#x:将stus中的元素挨个传给lambda函数,将其中单个元素的整体传给x,x["age"]即字典中的age的值。再把age的值作为参数用于比较
print("排序后:",res)
#动态输入函数
#coding=utf-8
def test(a,b,func):
return func(a,b)
func = input("please input a function:") #这是python2中的写法,如果是python3中,func = evla(input("please input a function:")) #eval即可将输入的语句转为python2中的形式
#假设输入了:lambda x,y:x+y
print(11,22,func)
#则test函数可以计算两个数的和
翻外篇
- 之import
格式:from modename import name1, name2
- "_"
如果for循环里面的临时变量在循环体里面并没有用到,则可以用"_",告诉读者该临时变量在循环体里面并没有被使用
for _ in range(10):
pass
- 之函数补充
函数也可以看做一种数据类型
def sum(a,b):
return a+b
f = sum
print(f(1,2))
- 之作用域与闭包
- python中,变量的作用域时以函数为单位的
- global修饰变量时,说明使用的是最外层的全局变量
- nonlocal 修饰时,说明使用的是嵌套层的变量,即非局部变量
- 如果不使用nonlocal或者global关键字,则内部函数不能可以访问但是不能修改外部的量,使用了关键字则可以进行更改
闭包
在一个函数里面又定义了一个函数,且这个函数用到了外面的变量。那么里边的这个函数及用到的外面的变量统称为闭包。闭包的本质是函数的嵌套,外层函数返回内层函数的地址。
def test(number):
def test_in():
print(number+100)
return test_in
ret = test(100) #返回test_in,并将test_in里面的number用100替换
ret() #输出200
#ps:也可以给test在定义时添加形参,则在ret调用时必须进行传参。
- 闭包的应用及详解
def test(a,b):
def test_in(x):
print(a*x + b)
return test_in
line1 = test(1,1) #令line1指向test_in的空间,此时test_in里面用的a是1,b是1
line1(0)
line2 = test(10,4) #如果发现没有指向test_in的引用,则直接将原来空间里面的a、b进行修改。但是此时有引用指向test_in,就重新开辟一块空间,将原来的test拷贝进去,但是将a赋值为10,b赋值为4,然后将这里面的test_in返回给line2
line2(0)
之递归
def:函数自己调用自己
编写递归或循环时,一般先考虑出口(结束条件)问题
之高阶函数
def:函数的参数或函数的返回值是函数的函数
def handle(func, *param):
return func(*param)
def my_sum(*param):
sum = 0
for i in param:
sum += i
return sum
print(handle(my_sum,1,2,3,4,5))
之函数的本质
对于函数,实际上在一块空间内存储了函数体,而函数名(不加括号)指向该空间。
因此可以将函数名看做一个普通的变量,进行赋值等操作。而在其他语言(如C、C++中),就必须通过函数指针进行。
之弱引用
新增一个变量时,变量计数器不会增加
class A:
pass
from sys import getrefcount
a = A()
b = a
print(getrefcount(a))#会输出3,因为self是一个,a也是一个,b也是也个
import weakref
c = weakref.ref(a)
print(getrefcount(a))
print(getrefcount(c)) #始终输出2,因为当c只是一个对象,c()的时候才是真正的引用
d = c() #d不是弱引用
print(getrefcount(a))
print(getrefcount(c))