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 是关键字,后跟函数 ...
随机推荐
- 180723-Quick-Task 动态脚本支持框架之结构设计篇
文章链接:https://liuyueyi.github.io/hexblog/2018/07/23/180723-Quick-Task-动态脚本支持框架之结构设计篇/ Quick-Task 动态脚本 ...
- JSP整理
JSP全称Java Server Pages,是一种动态网页开发技术.它使用JSP标签在HTML网页中插入Java代码.标签通常以<%开头以%>结束. JSP是一种Java servlet ...
- Linux内核学习笔记(6)-- 进程优先级详解(prio、static_prio、normal_prio、rt_priority)
Linux 中采用了两种不同的优先级范围,一种是 nice 值,一种是实时优先级.在上一篇粗略的说了一下 nice 值和实时优先级,仍有不少疑问,本文来详细说明一下进程优先级.linux 内核版本为 ...
- linux源码学习-for_each_cpu
刚开始读linux源码,第一眼就看到了这个很有意思的函数族,周末好好研究一下 3.13 这个组都是宏定义for循环,分析的时候注意到cpumask_next(),它在一个文件中定义了两次,还不是重载, ...
- MSCOCO - pycocoDemo 学习版
Reference: https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoDemo.ipynb https://git ...
- Python数据挖掘——基础知识
Python数据挖掘——基础知识 数据挖掘又称从数据中 挖掘知识.知识提取.数据/模式分析 即为:从数据中发现知识的过程 1.数据清理 (消除噪声,删除不一致数据) 2.数据集成 (多种数据源 组合在 ...
- 数据库MySql在python中的使用
随着需要存储数据的结构不断复杂化,使用数据库来存储数据是一个必须面临的问题.那么应该如何在python中使用数据库?下面就在本篇博客中介绍一下在python中使用mysql. 首先,本博客已经假定阅读 ...
- 市场营销的4c原则
市场营销的4c原则随着市场竞争日趋激烈,媒介传播速度越来越快,4Ps理论越来越受到挑战.到80年代,美国劳特朋针对4P存在的问题提出了4Cs营销理论: 4C分别指代Customer(顾客).Cost( ...
- 字符串拆分和拼接(含list拼接)---基于python
最近得一超长字符串如下: l=“5245474953544552207369703a3137322e3136312e31302e323232205349502f322e300d0a5669613a20 ...
- 基于spec评论作品 - 探路者 贪吃蛇
基于spec评论作品,试用(并截图)所有其他小组的Alpha作品,与软件功能说明书对比,评论Alpha作品对软件功能说明书的实现. 首先通过命令行进入到游戏主页面中. 因为软件没有编译为exe程序,所 ...