python基础----函数的定义和调用、return语句、变量作用域、传参、函数嵌套、函数对象、闭包、递归函数
1、函数的定义:
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()。但你也可以自己创建函数,这被叫做用户自定义函数。
定义一个函数:
你可以定义一个由自己想要功能的函数,以下是简单的规则:
- 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号()。
- 任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数。
- 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
- 函数内容以冒号起始,并且缩进。
- return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
语法:
def 函数名(参数1,参数2,参数3,,,,):
“描述信息”
函数体
return #用来定义返回值,可以跟任意数据类型<br><br>
def print_line():
print("*"*13)
def print_msg():
print("alex lala")
print_line()
print_msg()
print_line()
*************
alex lala
*************
2、函数的调用:
1,定义时无参,调用时也无参(无参函数)
2,定义时有参,调用时需要传参(有参函数)
定义一个函数只给了函数一个名称,指定了函数里包含的参数,和代码块结构。
这个函数的基本结构完成以后,你可以通过另一个函数调用执行,也可以直接从Python提示符执行。
函数的参数介绍:
1,从实参角度分析
⑴按照位置传值
⑵按照关键字传值
⑶混着用(按照位置和关键字)
注意问题:①按位置传值必须在按关键字传值的前面
②对于一个形参只能赋值一次
2,从形参角度来分析
⑴位置参数(必须传值的参数)
⑵默认参数
默认参数必须注意的问题是:默认参数必须放到位置参数的后面
3、return语句
return语句[表达式]退出函数,选择性地向调用方返回一个表达式。
没有return返回None
return1返回1
return1,2,3返回(1,2,3)元组
多个return只返回第一个
4、变量的作用域:
一个程序的所有的变量并不是在哪个位置都可以访问的。访问权限决定于这个变量是在哪里赋值的。
变量的作用域决定了在哪一部分程序你可以访问哪个特定的变量名称。两种最基本的变量作用域如下:
- 全局变量:定义在函数外的拥有全局作用域
- 局部变量:定义在函数内部的变量
局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。
#内置名称空间
#全局名称空间
#局部名称空间
#!/usr/bin/python
# -*- coding: UTF- -*- total = ; # 这是一个全局变量
# 可写函数说明
def sum( arg1, arg2 ):
#返回2个参数的和."
total = arg1 + arg2; # total在这里是局部变量.
print "函数内是局部变量 : ", total
return total; #调用sum函数
sum( , );
print "函数外是全局变量 : ", total 上例输出的结果:
函数内是局部变量 :
函数外是全局变量 :
5、传参:
在实参的角度:
规则:按位置传值必须在按关键字传值的前面
对一个形参只能赋值一次
1.按照位置传值
2.按照关键字传值
3.混着用
在形参的角度:
规则:默认参数必须放到位置参数的后面
1.位置参数
2.默认参数
3.*args (接收位置传值)
4.**kwargs(接收关键字传值)
6、函数嵌套
#嵌套调用 def my_max(x,y)
res=x id x>y else y
return res
print(my_max(,)) def my_max1(a,b,c,d):
res1=my_max(a,b)
res2=my_max(res1,c)
res3=my_max(res2,d)
return res3
print(my_max1(,,,))
#嵌套定义 x=
def f1():
x=
print("----->f1",x)
def f2():
x=
print("---->f2",x)
def f3():
x=
print("--->f3",x)
f3()
f2()
f1()
7、函数对象
def foo():#foo代表函数的内存地址
print('foo')
print(foo)#打印出的是foo函数的内存地址,内存地址加括号就可以调用该函数 #函数可以被赋值
f=foo
print(f)#打印的是foo函数的内存地址
f()#等于foo() #把函数当成参数传递
def bar(func):
print(func)
func()
bar(foo)#传入的是foo函数的内存地址,运行结果是打印foo函数的内存地址和foo函数的运行结果 #把函数当成返回值
def bar(func):
print(func)
return func
f=bar(foo)
print(f)
f()
8、闭包
定义:首先必须是内部定义的函数,该函数包含对外部作用域而不是全局作用域名字的引用
#闭包
x=
def f1():
x=
y=
def f2():
print(x)
print(y)
return f2 #返回得f2不仅是返回了f2函数局部作用域还返回了引用的外部作用域的变量
f=f1()
print(f)
print(f.__closure__)#必须是闭包才能用此命令
print(f.__closure__[].cell_contents)#查看值
print(f.__closure__[].cell_contents)
-------------------------------------------------------------------------------------------------------------------------------
<function f1.<locals>.f2 at 0x0000000000A7E1E0>
(<cell at 0x0000000000686D08: int object at 0x000000005E5522D0>, <cell at 0x0000000000686D38: int object at 0x000000005E5522F0>)
#代表f2引用了,f1中的x=
#代表f2引用了,f2中的y=
闭包用途:爬虫
#爬虫
from urllib.request import urlopen
def get(url):
return urlopen(url).read()
print(get('http://www.baidu.com')) #专门爬百度页面
def f1(url):
def f2():
print(urlopen(url).read())
return f2 #返回的是f2的内存地址 和 url
baidu=f1('http://www.baifu.com')#等式右边就是return的值,也就是f2的内存地址 和 url<br><br>baidu()
9、递归函数
定义:在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
举个例子,我们来计算阶乘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
所以,fact(n)
可以表示为n x fact(n-1)
,只有n=1时需要特殊处理。
于是,fact(n)
用递归的方式写出来就是:
def fact(n):
if n==:
return
return n*fact(n-) #这种思想太牛逼了,感觉脑洞大开
print(fact())
我们在计算fact(5),可以根据函数定义看到计算过程如下:
===> fact()
===> * fact()
===> * ( * fact())
===> * ( * ( * fact()))
===> * ( * ( * ( * fact())))
===> * ( * ( * ( * )))
===> * ( * ( * ))
===> * ( * )
===> *
===>
递归函数的有点就是定义简单,逻辑清晰。理论上,所有的函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。可以试试fact(1000),最好别试。
解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。
尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。
上面的fact(n)
函数由于return n * fact(n - 1)
引入了乘法表达式,所以就不是尾递归了。要改成尾递归方式,需要多一点代码,主要是要把每一步的乘积传入到递归函数中:
def fact(n):
return fact_iter(n,)
def fact_iter(num,product):
if num == :
return product
return fact_iter(num-,num*product)
print(fact())
可以看到,return fact_iter(num - 1, num * product)
仅返回递归函数本身,num - 1
和num * product
在函数调用前就会被计算,不影响函数调用。
fact(5)
对应的fact_iter(5, 1)
的调用如下:
===> fact_iter(, )
===> fact_iter(, )
===> fact_iter(, )
===> fact_iter(, )
===> fact_iter(, )
===>
尾递归调用时,如果做了优化,栈不会增长,因此,无论多少次调用也不会导致栈溢出。
遗憾的是,大多数编程语言没有针对尾递归做优化,Python解释器也没有做优化,所以,即使把上面的fact(n)
函数改成尾递归方式,也会导致栈溢出。
总结:
使用递归函数的优点是逻辑简单清晰,缺点是过深的调用会导致栈溢出。
针对尾递归优化的语言可以通过尾递归防止栈溢出。尾递归事实上和循环是等价的,没有循环语句的编程语言只能通过尾递归实现循环。
Python标准的解释器没有针对尾递归做优化,任何递归函数都存在栈溢出的问题。
python基础----函数的定义和调用、return语句、变量作用域、传参、函数嵌套、函数对象、闭包、递归函数的更多相关文章
- Python函数的定义与调用、返回值、参数
一.函数是什么 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.比如print(),len()等.但你也可以自己创建函数,这被叫做用户自 ...
- Kotlin基础(二)函数的定义与调用
函数的定义与调用 一.预备知识:在Kotlin中创建集合 fun main(args: Array<String>) { //Kotlin中定义各自集合 val ,,,) val list ...
- 12_传智播客iOS视频教程_注释和函数的定义和调用
OC的注释和C语言的注释一模一样.它也分单行注释和多行注释. OC程序里面当然可以定义一个函数.并且定义的方式方法和调用的方式方法和我们C语言是一模一样的.OC有什么好学的?一样还学个什么呢? 重点是 ...
- js函数的定义和调用
函数的定义 函数使用function 声明,后跟一组参数以及函数体,语法如下: function functionName([age0,age1,......argn]){ statements } ...
- Python基础------列表,元组的调用方法
Python基础------列表,元组的调用方法@@@ 一. 列表 Python中的列表和歌曲列表类似,也是由一系列的按特定顺序排列的元素组成的,在内容上,可以将整数,实数,字符串,列表,元组等任何类 ...
- linux shell自定义函数(定义、返回值、变量作用域)介绍
http://www.jb51.net/article/33899.htm linux shell自定义函数(定义.返回值.变量作用域)介绍 linux shell 可以用户定义函数,然后在shell ...
- day03 函数基本语法及特性 2. 参数与局部变量 3. 返回值 嵌套函数 4.递归 5.匿名函数 6.函数式编程介绍 7.高阶函数 8.内置函数
本节内容 1. 函数基本语法及特性 2. 参数与局部变量 3. 返回值 嵌套函数 4.递归 5.匿名函数 6.函数式编程介绍 7.高阶函数 8.内置函数 温故知新 1. 集合 主要作用: 去重 关系测 ...
- python函数基础(函数的定义和调用)
函数的定义 python定义函数使用def关键字 return[表达式]语句用于退出函数,选择性的向调用方返回一个表达式,不带参数值的return语句返回none def 函数名(参数列表): 函数体 ...
- Python基础--函数的定义和调用
一.函数的作用: 提高代码的可读性,减少代码的冗余,方便调用和修改,组织结构清晰 二.函数的定义:函数遵循先定义后调用的原则 1.无参函数 def funcname(): #def 是关键字,后跟函数 ...
随机推荐
- TPO-18 C2 Possible participation in a sociology project
TPO-18 C2 Possible participation in a sociology project 第 1 段 1.listen to a conversation between a s ...
- Linux内核学习笔记(5)-- 进程调度概述
进程调度程序是多任务操作系统的基础,它是确保进程能有效工作的一个内核子系统,负责决定哪个进程投入运行.何时运行以及运行多长时间.只有通过进程调度程序的合理调度,系统资源才能够最大限度地发挥作用,多进程 ...
- 《JavaScript设计模式与开发实践》——第3章 闭包和高阶函数
闭包 变量的作用域和生存周期密切相关 高阶函数 函数可以作为参数被传递 函数可以作为返回值输出
- 软件工程android项目简介
我们的程序名字叫做“有爱”APP,英文名“you i”.意味着you and i,是一款旨在两人聊天,生活日记,记账工具,和对方通知的小软件. 1.首先我们的创意解决了用户什么需求? 答:在当今信息爆 ...
- UVALive 6913 I Want That Cake 博弈+dp
题目链接: http://acm.hust.edu.cn/vjudge/problem/96343 I Want That Cake Time Limit: 3000MS 64bit IO Forma ...
- spring复杂数据类型传递
1.VO对象与PO对象的区别: PO(persistant object) 持久对象:通常对应数据模型(数据库),本身还有部分业务逻辑的处理.可以看成是与数据库中的表相映射的java对象.最简单的PO ...
- 201621123037《Java程序设计》第二周学习总结
#Week02-Java基本语法与类库 1. 本周学习总结 关键词:常量池.对象.null.不可变性.string对象拼接.字符串池 关键概念之间的联系:Java中有常量池,超出常量池以外的就会新开辟 ...
- QLayout窗口布局
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QLayout窗口布局 本文地址:http://techieliang.com/201 ...
- 【BioCode】删除未算出PSSM与SS的蛋白质序列
代码说明: 由于一些原因(氨基酸序列过长),没有算出PSSM与SS,按照整理出来的未算出特征的文件,删除原来的蛋白质序列: 需删除的氨基酸文件732.txt(共732条氨基酸): 删除前 氨基酸共25 ...
- VSVC2010中常用的C++11特性
static_assert 声明 static_assert 声明在编译时测试软件断言,这与在运行时进行测试的其他断言机制不同. 如果断言失败,则编译也将失败,且系统将发出指定的错误消息. const ...