一、函数的基础概念:
-
函数是python为了代码最大程度地重用和最小化代码冗余而提供的基本结构
-
函数是一种设计工具,它能让程序员将复杂的系统分解为可管理的部件
-
函数用于将相关功能打包并参数化
-
在python中可以创建4种函数
-
(1)
全局函数
:定义在模块 -
(2)
局部函数
:嵌套于其它函数中 -
(3)
lambda函数
:表达式,如需多次调用 -
(4)
方法
:与特定数据类型关联的函数,并且只能与数据类型关联一起使用
-
-
python提供了很多内置函数
二、创建函数:
def functionName(arg1,arg2,...): suite return def 函数名(参数): ... 函数体 ... 返回值
函数的定义主要有如下要点:
-
def:表示函数的关键字
-
函数名:函数的名称,日后根据函数名调用函数
-
函数体:函数中进行一系列的逻辑计算,如:发送邮件、计算出 [11,22,38,888,2]中的最大数等...
-
参数:为函数体提供数据
-
返回值:当函数执行完毕后,可以给调用者返回数据。
一些相关的概念:
-
def是一个可执行语句
-
因此可以出现在任何能够使用语句的地方,甚至可以嵌套于其他语句,例如if或while中
-
-
def创建了一个对象并将其赋值给一个变量名(即函数名),函数体则存在内存
-
return用于返回结果对象,其为可选;无return语句的函数自动返回None对象
-
返回多个值时,彼此间使用逗号分隔,且组合为元组形式返回一个对象
-
函数一旦执行到return,函数就终止了,如果return下面还有执行语句则终止
-
-
def语句运行之后,可以在程序中通过函数后附加()进行调用
三、函数作用域:
python创建、改变或查找变量名都是在名称空间中进行,在代码中变量名被赋值的位置决定了其能被访问到的范围,函数定义了本地作用域,而模块定义了全局作用域
-
1.全局变量全部用大写表示
-
2.全局变量都可以被访问,函数内部的变量则为本地作用域
-
3.在函数内如果要修改全局变量,需要global
-
4.特殊:字典,列表可以在函数内修改,但是不能重新赋值
NAME = 'tomcat' def f1(): age = 18 global NAME NAME = 'xiao' print(age,NAME) def f2(): age = 27 print(age,NAME) f1() f2()
四、函数的参数:
默认情况下,参数通过其位置进行传递,从左至右,这意味着,必须精确地传递和函数头部参数一样多的参数,但也可以通过关键字参数、默认参数或参数容器等改变这种机制
(1)普通参数:定义函数时从左至右
(2)默认参数:定义函数时是使用"name=value"的语法直接给变量一个值,从而传入的值可以少于参数个数
(3)指定参数:调用函数时指定"name形式参数=value实际参数"的语法通过参数名进行匹配
(4)动态参数:定义函数时形式参数中收集任意多基于普通参数
定义函数时使用* :收集普通参数,返回元组,*args
定义函数时使用:收集指定参数,返回列表,kwargs
(5)动态参数解包:调用函数时,使用**开头的参数,从而传递任意多基于普通或指定参数
注意:定义函数时
1.混用普通参数和默认参数,应当把默认参数写到右侧
2.混用有默认和无默认值的参数时,无默认值放左侧
4.1、返回值
函数是一个功能块,该功能到底执行成功与否,需要通过返回值来告知调用者。
以上要点中,比较重要有参数和返回值:
def 发送短信(): 发送短信的代码... if 发送成功: return True else: return False while True: # 每次执行发送短信函数,都会将返回值自动赋值给result # 之后,可以根据result来写日志,或重发等操作 result = 发送短信() if result == False: 记录日志,短信发送失败...
4.2、参数
没有参数的情况
#!/usr/bin/env python # -*- coding:utf-8 -*- ''' 1.需要开启邮箱服务sendmail 2.邮箱服务器需要开启SMTP服务 ''' def sendmail(): try: import smtplib from email.mime.text import MIMEText from email.utils import formataddr msg = MIMEText('邮件内容', 'plain', 'utf-8') msg['From'] = formataddr(["发件人", 'pythonxiao@126.com']) msg['To'] = formataddr(["收件人", '329275108@qq.com']) msg['Subject'] = "邮件主题" server = smtplib.SMTP("smtp.126.com", 25) server.login("pythonxiao@126.com", "xiaozhiqi2016") server.sendmail('pythonxiao@126.com', ['329275108@qq.com', ], msg.as_string()) server.quit() except: return False else: return True ret = sendmail() if ret == True: print("发送成功") else: print("发送失败")
有参数的情况:
def email(mail): import smtplib from email.mime.text import MIMEText from email.utils import formataddr msg = MIMEText('邮件内容', 'plain', 'utf-8') msg['From'] = formataddr(["测试",'asdasd@126.com']) msg['To'] = formataddr(["走人",'asdasdasd@163.com']) msg['Subject'] = "主题" server = smtplib.SMTP("smtp.126.com", 25) server.login("wdfgfghfgh@126.com", "123456") server.sendmail('asdasdas@126.com', [mail,], msg.as_string()) server.quit() email("6087414@qq.com")
当执行这个脚本的时候会给邮箱6087414@qq.com
发送邮件。
注:上面的邮箱地址等都是随便写的,请自行更改
从上面例子可以看出有参数的函数表现的非常灵活可扩展!
函数的有三中不同的参数(定义函数时):
-
普通参数
-
默认参数
-
动态参数
指定参数和动态参数解包是发生在调用函数
1、普通参数
(1)# xxoo为普通参数也叫形式参数,简称:形参 def f1(name): print(name) # 'test' 叫做函数的实际参数,简称:实参 f1('tomcat')
2、默认参数
(2)# name 是普通参数,ab=5是默认参数 def f1(name,ab=5): print(name,ab) # 指定参数 f1('tomcat',12) # 使用默认参数 f1('tomcat') 注意:默认参数需要放在参数列表最后
3、动态参数
动态参数把接收过来的实际参数当作一个元组,每一个参数都是元组中的一个元素。
第一种动态参数
定义第一种动态参数需要在参数前面加上一个*
号
>>> def ret(*args): ... print(args,type(args)) ... >>> ret(11,22,33) (11, 22, 33) <class 'tuple'>
第二种动态参数
定义第二种动态参数需要在参数前面加上两个*
号,给参数传参的时候是一个key对应一个value的,相当于一个字典的键值对,而且返回的类型就是字典类型。
使用两个星号可以将参数收集到一个字典中,参数的名字是字典的键,对应参数的值是字典的值。
>>> def ret(**kwargs): ... print(kwargs,type(kwargs)) ... >>> ret(k1=123,k2=456) {'k1': 123, 'k2': 456} <class 'dict'>
第三种动态参数
第三种又称为万能的动态参数,如下实例:
>>> def ret(*args,**kwargs): ... print(args,type(args)) ... print(kwargs,type(kwargs)) ... >>> ret(11,222,333,k1=111,k2=222) (11, 222, 333) <class 'tuple'> {'k1': 111, 'k2': 222} <class 'dict'>
1.5、函数式编程:
以后写函数按照下面这个例子来编写,规范,这是一个登录注册的函数编程
-
1.函数与函数间隔2行
-
2.函数需要注释,便于记忆
-
3.函数名需要见名知意
db文件格式
admin|123
xiao|12345
代码
#!/usr/bin/env python # coding: utf8 def datainput(): username = input("input your username:") password = input("input your password:") return username,password def login(username,password): f = open('db','r') for line in f: data = line.strip().split('|') if data[0] == username and data[1] == password: return True return False def register(username,password): f = open('db','r') for line in f: user = line.strip().split('|') #print(user) if username in user: return False else: f = open('db','a') userdata = "\n" + username + "|" + password f.write(userdata) f.close() return True def main(): num = input("1.登录,2.注册:") if int(num) == 1: data = datainput() result = login(data[0],data[1]) if result: print('登录成功') else: print('登录失败') elif int(num) == 2: data = datainput() ret = register(data[0],data[1]) if ret: print("注册成功") else: print("注册失败,用户已存在") main()
五、lambda表达式
对于简单的函数,也存在一种简便的表示方式,即:lambda表达式
# ###################### 普通函数 ###################### # 定义函数(普通方式) def func(arg): return arg + 1 # 执行函数 result = func(123) # ###################### lambda ###################### # 定义函数(lambda表达式) my_lambda = lambda arg : arg + 1 # 执行函数 result = my_lambda(123)
lambda表达式会自动return返回值,条件为真返回True,条件为假返回False.
六、函数递归
所谓递归其实就是函数本身调用函数,直到满足指定条件之后一层层退出函数, 例如
从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?“从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?‘从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?……’”
-
利用函数编写一个斐波那契数列
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368
斐波那契数列就是前面给两个数相加得到后面一个数,依次往后
代码如下
#!/usr/bin/env python # _*_ coding: utf-8 _*_ def Counter(n1, n2): if n1 > 10000: # 当要计算的值大于10000就退出 return print("Counter:", n1) # 输出当前计算到那个值了 n3 = n1 + n2 # 第一个值加上第一个值等于第三个值 Counter(n2, n3) # 调用计数器函数,此时第一个值是调用函数传过来的最后一个值,而第二个值是计算出来的第三个值 Counter(0, 1) # 调用计数器函数
输出结果
/usr/bin/python3.5 /home/Python/Documents/PycharmProjects/blogcodes/斐波那契.py Counter: 0 Counter: 1 Counter: 1 Counter: 2 Counter: 3 Counter: 5 Counter: 8 Counter: 13 Counter: 21 Counter: 34 Counter: 55 Counter: 89 Counter: 144 Counter: 233 Counter: 377 Counter: 610 Counter: 987 Counter: 1597 Counter: 2584 Counter: 4181 Counter: 6765 Process finished with exit code 0
-
利用递归获取斐波那契数列中的第10个数,并将该值返回给调用者
代码:
#!/usr/bin/env python # _*_ coding: utf-8 _*_ def Counter(Index, Start, End): print("第%d次计算,第一个数字是%d,第二个数字是%d" % (Index, Start, End)) if Index == 10: # 如果要计算的值是10就退出 return Start N = Start + End # N等于第一个数加上第二个数 Number = Counter(Index + 1, End, N) # 继续调用计数器函数,End相当与传给函数的第一个数,N是传给函数的第二个数 return Number result = Counter(1, 0, 1) print("得出的数字是:", result)
输出结果
/usr/bin/python3.5 /home/Python/Documents/PycharmProjects/blogcodes/递归.py 第1次计算,第一个数字是0,第二个数字是1 第2次计算,第一个数字是1,第二个数字是1 第3次计算,第一个数字是1,第二个数字是2 第4次计算,第一个数字是2,第二个数字是3 第5次计算,第一个数字是3,第二个数字是5 第6次计算,第一个数字是5,第二个数字是8 第7次计算,第一个数字是8,第二个数字是13 第8次计算,第一个数字是13,第二个数字是21 第9次计算,第一个数字是21,第二个数字是34 第10次计算,第一个数字是34,第二个数字是55 得出的数字是: 34 Process finished with exit code 0