python 基础(四) 函数
函数
一、什么是函数?
函数是可以实现一些特定功能的 小方法 或者是小程序
优点:
-
提高 了代码的后期维护
-
增加了代码的重复使用率
-
减少了代码量 提高了代码可读性
二、函数的定义
使用 def关键+函数名([参数]):
函数体
函数的命名规则:
遵循变量的命名规则
三、函数名
(1) 函数的调用
函数名([参数])
(2) 函数名区分大小写
(3) 只能在函数定义的下方来调用
(4) 函数不能重名 会被覆盖
四、函数的参数问题
(1) 形参(形式上的参数)
在函数定义处的括号里的变量 称之为 形参
注意:
-
函数在定义的时候 存在形参 且没有默认值 则在调用时 必须传实参
a(1,2) #此刻1和2称之为实参
-
函数在定义时 如果没有 形参 则不能传实参
-
传入的实参个数 不能大于形参个数
-
实参和形参对应
-
实参的参数 和 形参一一对应 从左倒右依次赋值
(2) 形参默认值
在函数定义处 给当前形参赋一个默认值 则在调用时 当前有默认值的形参 可传可不传
如果传实参 则当前形参的值为实参的值 否则值为默认值
实例:
def defaultArg(a,b=2):
print(a,b)
defaultArg(1) #1,2
defaultArg(1,3) #1 3
错误写法(没有遵循默认值的规则)
def defaultArg(a=1,b):
print(a,b)
defaultArg(1,2)
在给形参默认值的时候 有默认值放在最后面
(3) 关键字参数
可以做到给指定的形参赋值
def demo(a,b,c):
# def demo(a,b,c):
print(a,b,c)
# demo(1,2,3)
# demo(c=1,b=2,a=3) #关键字参数 关键字为 形参名
# demo(1,b=2,c=3) #关键字参数 第一个值默认传递给a 从左到右
# demo(a=1,2,c=3) #follows keyword argument
# demo(1,b=2,a=3) #关键字参数 当前参数a 赋值2次
五、函数的返回值
(1) 没有返回值的情况
实例:
a = 1
def func():
a = 1+2
print(func())#打印函数调用处 None
(2) 有返回值的情况
使用关键字 return
使用 return 可以方便我们对函数值的操作(你能够拿到这个值 并对他操作)
实例:
a = 1
def func():
a = 1+2
return a
print(func())#将值返回给函数调用处 3
注意事项:
在函数体内使用return时 return下面的代码将不会在执行
(3) 函数返回多个值得情况
实例:
def mySum(a=0,b=0):
Sum = a + b
return Sum,a,b #将a,b,Sum全部返回 以元组的方式
return (Sum,a,b) #将a,b,Sum全部返回 以元组的方式
return [Sum,a,b] #将a,b,Sum全部返回 以列表的方式
六、不定长参数
概念:也就是传入得参数得个数 不确定
(1) *args 以元组接收不确定实参得值
def demo(*args): #以元组得形式 接受不确定参数得个数
print(args)
demo(1,2,3) #(1,2,3)
demo() #空元组 ()
*args和普通形参的搭配使用
A: *args,a
def demo(a,b,*args):
print(args,a)
demo(1,2) #1 2 ()
demo(1,2,3,4,5) #1 2 (3, 4, 5)
demo('x') #('x',) 1
demo('x','y') #('x', 'y') 1
B: a,*args
def demo(*args,a=1):
print(args,a)
demo('x','y',a=2) #('x', 'y') 2
(2) **kwargs 以字典得形式接收不确定参数
其中关键字为 字典得键 值为字典得值
def func(**kwargs):
print(kwargs)
func(a=1,b=2,c=3)
func(a=1,a=2) #SyntaxError: keyword argument repeated
注意:
关键字 不能重复
SyntaxError: keyword argument repeated
(3) 在调用处的 **的使用
def func(**kwargs):
print(kwargs) #{'a':'a','b':'b'}
myDict = {'a':'a','b':'b'}
func(**myDict) #在调用处 将字典 转换为关键字参数
(4) 组合使用
普通参数,*args,**kwargs
def demo(x,*args,**kwargs):
print('x',x,'*args',args,'**kwargs',kwargs)
demo(1,2,3,4,a=1,y=2)
#demo(x=1,2,3,4,a=1,y=2) #x 1 *args (2, 3, 4) **kwargs {'a': 1, 'y': 2}
七、递归
概念:自己调用自己
实现累加得普通操作
def mySum(num):
Sum = 0
for i in range(1,num+1):
# print(i)
Sum += i
print(Sum)
mySum(5)
使用递归实现一个数得累加
def mySum(num):
if num == 0:
return False
# return #int' and 'NoneType'
return num + mySum(num-1)
运行过程
mySum(5)
5+mySum(4)
5+(4+mySum(3))
5+(4+(3+mySum(2)))
5+(4+(3+(2+mySum(1))))
5+(4+(3+(2+(1+mySum(0)))))
5+(4+(3+(2+(1+False))))
5+(4+(3+(2+1))))
5+(4+(3+3)))
5+(4+6)
5+10
15
证明递归原路返回
def demo(n):
print(n)
if n>=0:
demo(n-1)
print(n)
demo(3)
上面代码得分解
def a(n):
print(n) #4
b(n-1) #3
print(n) #4
def b(n): #3
print(n) #3
c(n-1) #2
print(n) #3
def c(n): #2
print(n) #2
d(n-1)
print(n) #2
def d(n): #1
print(n) #1
print(n) #1
a(4)
1.定义一个函数 模仿pop
传入一个列表 将最后得值弹出并返回
def myPop(List):
val = List[-1]
del List[-1]
return val
myList = [1,2,3,4]
print(myPop(myList))
2.自定义一个函数 实现 字典得键值交换
def dictChange(Dict):
newDict = {}
for i in Dict:
# print(i)
newDict[Dict[i]] = i
return newDict
myDict = {'name':'zs','age':'18'}
print(dictChange(myDict))
3.实现一个 类似 popitem()的操作
def myPopitem(Dict):
keys = list(Dict.keys())[-1]
val = Dict[keys]
del Dict[keys]
return keys,val
myDict = {'a':'1','b':'2'}
print(myPopitem(myDict))
print(myDict)
八、可变类型与不可变类型
不可变类型:如整数,字符串,元组...
可变类型: 字典,列表...
不可变类型实例:
def change(var):
# print(var)
# print(id(var))
var = 2
Int = 1
change(Int)
# print(id(Int))
print(Int)
有值2 Int变量执行了2 在传递给change函数得时候 按照传值得方式赋值了变量Int Int和var都执行了 2(int对象)
在 var = 2 得时候 创建了一个新的变量
可变类型实例:
def change(List):
List.append('a')
myList = [1,2,3]
change(myList)
print(myList)
理解的代码
a = [1,2,3]
b = a
b = 2
# print(a)
# print(b)
# b.append('a')
print(b)
print(a)s
九、变量得作用域
在python中 程序得变量 并不是在哪个位置都可以访问得倒 访问权限 取决于变量得定义位置
-
L 局部作用域
-
E 闭包函数外得函数中
-
G 全局作用域
-
B 内建作用域
(1) 在函数外部声明得变量 称之为 全局变量 函数内外都能够获取
num = 1
def func():
print(num)
func()
函数内可以获取到全局变量 但是不能进行修改
(2) 在函数内部声明得变量称之为局部变量 只能在函数内部使用 函数外部获取不到
def func():
num = 2
print(num)
func()
print(num)
在函数内部想用某个变量 那么会先在函数内部查找 如果内部不存在 则取外部查找
(3) global 声明函数内外使用同一个变量
num = 1
def func():
global num
num = 2
func()
print(num)
(4) 将局部变量 声明为全局变量(函数内外都可以获取到)
def func():
global x #将局部变量 声明为全局变量
x = 1
func()
print(x)
(5) nonlocal 当函数发生嵌套时(将上层的变量于当前声明内外使用同一个)
num = 1
Str = 'string'
#1 当函数放生嵌套的时候 在使用变量时 去上一层查找
def a():
# nonlocal num
# num = 2
Str = '新的字符串'
def b():
# nonlocal num #将外层和当的变量声明统一使用同一个
# num = 3
def c():
# global num
nonlocal num
num = 'num'
print(num)
# print(Str)
c()
print(num)
b()
print(num)
a()
如果函数上层没有要查找的变量 则去上上层... 直到查到为止
在函数嵌套时 里层函数使用global时 会将全局变量声明使用
是否会引入新的作用域
-
在python中 只有模块(module),类(class),函数 会引入新的作用域
-
if/else try/except for/while 是不会引入新的作用域 也就是说 这些语句内定义的变量 外部也能够访问
十、lambda表达式(匿名函数)
定义: lambda
变量名 = lambda [参数]:函数体
注意:
-
lambda 只是一个表达式 函数体比def简单很多
-
lambda 是表达式 不是代码块 只能在lambda中封装有限的逻辑
-
调用和函数一样 变量名([参数])
实例:
#第一种方式
func = lambda a,b:a+b #将值进行返回
func = lambda a,b:print(a+b) #将值进行输出
#第二种方式 定义并调用
print((lambda a,b:a+b)(1,2))
#第三种 给默认值
func = lambda a=1,b=1:a+b
print(func())
#第四种 没有形参的情况
a = 1
func = lambda :a
print(func())
#第五种 嵌套
func = lambda :(lambda :print('我是嵌套的表达式'))()
十一、装饰器
概念: 在代码运行期间 动态的添加功能 称之为装饰器
步骤1
def demo(arg):
print('我是demo函数')
# print(arg)
# func()
arg()
def func():
print('我是func函数')
# demo('abc')
demo(func)
步骤2
def demo(arg):
def inner():
print('当前时间为')
return arg()
return inner
def func():
print('2018/4/5')
def func2():
print('2018-4-5')
func2 = demo(func2)
func2()
func = demo(func)
func()
步骤3
#demo函数 是一个 实现主体功能的函数
def demo(arg):
def inner(age): #根据 age判断年龄段
Str = ''
if age<=10:
Str = '儿童'
elif age<=20:
Str = '少年'
elif age<=30:
Str = '青年'
elif age<=50:
Str = '中年'
else:
Str = '老年'
return arg(Str)
return inner
#自己有需求 要添加实现的函数
def func(person):
print('你已经步入了{}'.format(person))
func = demo(func)
func(60)
步骤4
import functools
#demo函数 是一个 实现主体功能的函数
def demo(arg):
def inner(age): #根据 age判断年龄段
pass
...
#自己有需求 要添加实现的函数
def func(person):
print('你已经步入了{}'.format(person))
给装饰器传参数
import functools
def demo(text):
def inner(arg):
def decorator(*args,**kwargs):
print(text)
return arg(*args,**kwargs)
return decorator
return inner
def time(*args,**kwargs):
print('2018/4/25',args)
十二、包和模块
模块(Module): 就是python中的一个 py文件 其中定义的所有 的变量和函数 都属于当前的py文件 Module对于所有函数而言 相当于一个 全局的命名空间(namespace) 而每一个函数又有自己的局部命名空间
包(Package): 所谓的包 就是 一堆module的集合 也就是一堆py文件 包文件总 必须有一个__init__.py
文件 作为当前包的初始化
__name__
判断当前文件 是在主文件执行 还是在其他文件导入执行的
在主文件name的值为 main 被其它文件导入 name的值为他自己模块的名称
Module:
里面就是一堆的类,函数,变量
a.py
age = 10
def demo():
return '你调用a.py中的demo函数了'
if __name__ == '__main__':
print(demo())
Package:
目录结构:
package
----> __init__.py
----> func.py 包含某些功能的py文件
-----> ...py
包或者模块的导入
from 包名.模块名 import 属性或者函数
from package.a import demo 导入一个
from package.a import demo,age 导入多个
from package.a import * 导入所有
使用
print(demo())
print(age)
from 包名 import 模块名
from package import a 从package包 导入a模块
import 包.模块名/模块名
import 包.模块名/模块名 as 别名
import package.a
print(package.a.age)
import package.a as t
print(t.age)
包中的初始化操作
__init__.py
通常做一个包被导入时 进行初始化的操作 可以将其他模块module 中的变量,函数 进行导入 在外部导入当前包的时候 不需要指定包下的模块名 而是直接 from 包名 import 函数/变量
实例
package->__init__.py
from package.a import demo
from package.a import *
from package.b import func
from .a import *
def abc():
print('走我了')
在外部的test.py中进行导入使用
from package import demo,func,abc
from package import * #导入所有
print(demo())
print(func())
abc()