Python-lesson 3-函数

1、函数知识体系

  1. 什么是函数?
    在程序中具备某一功能的工具就是函数
    函数的使用原则:先定义、后调用

  2. 为什么要用函数?
    (1)代码冗余
    (2)程序组织结构不清晰、可读性差
    (3)扩展性差

  3. 函数的分类:
    (1)内置函数
    python自带的
    (2)自定义函数
    自己定义的

  4. 自定义函数和使用
    函数的定义分为两个阶段:定义和调用
    函数定义: 定义只检测语法不执行代码

def 函数名(参数1,参数2...):          //必须
"""
文档注释
"""
    函数代码块1                  //必须
    函数代码块2
    ...
    return 值

函数调用:开始执行函数代码
函数名()

  1. 定义函数的三种方式
    (1)无参函数
    def func():
    print('......')
    func()

(2)有参函数
def func(x,y):
if x > y:
return(x)
else:
return(y)

res=func(1,2)

(3)空函数
def register():
pass

  1. 调用函数的三种形式
    (1)语句模式
    def func():
    print('......')
    func()

(2)表达式形式
def func(x,y):
if x > y:
return(x)
else:
return(y)

res=func(1,2) * 12
print(res)

(3)函数的调用可以当作另外一个函数的参数传入
def func(x,y):
if x > y:
return(x)
else:
return(y)

res=func(func(1,2),3)
print(res)

  1. 返回值的特点
    (1)返回值没有类型限制,也没有个数限制
    (2)return是函数结束运行的标志,函数内可以有多个return,但只要执行一次return函数就立即结束,并且将return后的值当作本次调用的结果返回。

  2. 函数的参数
    形参即变量名,实参即变量值,函数调用时,将值绑定到变量名上,函数调用结束,解除绑定

  3. 函数参数详解
    (1)形参

  • 位置形参:按照从左至右的顺序依次定义的形参
    特点:必须被传值

  • 默认参数:在定义阶段,就已经为某个形参赋值,该形参称之为默认形参
    特点:在定义阶段就已经有值,意味着调用阶段不用为其传值
    def func(x,y=2):
    print(x,y)

func(1)

注意:位置形参与默认形参可以混用,位置形参必须放在默认形参的前面

(2)实参

  • 位置实参:在调用阶段,按照从左到右的顺序依次传入的值
    特点:这种传值方式会与形参一一对应

  • 关键字实参:在调用阶段,按照key=value的格式传值
    特点:可以完全打乱位置,但仍然能为指定的形参传值

注意:
1、可以混用位置实参与关键字实参,但是同一个形参只能被赋值一次
2、位置实参必须在关键字实参的前面

(3)形参中*与**的用法

  • 形参中带*,*会将溢出的位置实参存成元组的形式然后赋值其后变量名
def func(x,y,*args):
    print(x,y,args)
print(1,2,3,4,5,6)
  • 形参中带**;**会将溢出的关键字实参存成字典的格式然后赋值其后变量名
def func(x,y,**kwargs):
    print(x,y,kwargs)
print(1,y=2,z=3,m=4,n=5)

(4)实参中* 与**的用法

  • 实参中带*;先将实参打散成位置实参,然后再与形参做对应
def func(x,y,z):
    print(x,y,z)

func(*[1,2,3])
func(*'llo')
  • 实参中带**;先将实参打散成关键字实参,然后再与形参做对应
def func(x,y,z):
    print(x,y,z)

func(**{'x':1,'z':3,'y':2})    //func(z=3,y=2,x=1)

将一个函数的参数完全转给另一个函数

def index(x,y,z)
    print(x,y,z)

def wrapper(*args,**kwargs):           
    index(*args,**kwargs)
#以上两行意思是将一个函数的参数完全传给另一个函数

wrapper(1,2,3)

2、函数对象

函数对象:把函数的内存地址当作一种变量值去使用,函数对象不加();如果内存地址加()就是在调用函数

与变量相同的用法:可以被引用、可以当作参数传递、返回值可以是函数、可以被储存到容器类型(列表、字典、元组)

独有的用法:加()可以运行其内部代码

  1. 可以被引用
def func1()
    print('from func')

func2=func1
func2()
  1. 可以当作参数传递
def func1()
    print('from func')

def bar(xxx)
    xxx()

bar(func1)
  1. 返回值可以是函数
def func1()
    print('from func')

def bar()
    return func1

f=bar()
f()
  1. 可以被储存到容器类型(列表、字典、元组)
def func1()
    print('from func')

l=[func1,]
l[0]()

3、函数嵌套

嵌套调用:在一个函数中调用了另一个函数
嵌套定义:在一个函数中定义的一个函数,只能在函数里面使用,外界不能用

def func1()
    print('hello')

def func2()
    print('world')
    func1()

func2()
----------------------------------------
world
hello

4、名称空间

名称空间:就是存储名字与内存地址绑定关系的空间

4.1 名称空间的分类:

(1)内置名称空间:存储解释器自带的变量名称与值的对应关系(print、len、max、min);python解释器启动时创建内置名称空间,关闭解释器销毁
(2)全局名称空间:文件级别的名称,只要你的名字定义是顶着最左边(空格也算)写的就在全局空间,除了内置的和函数内的,都是全局名称空间;执行py文件创建全局名称空间,关闭解释器销毁
(3)局部名称空间:只要在函数里面就是局部的;调用函数时创建,函数执行完毕销毁

  • 名称空间的加载顺序
    内置的名称空间--->全局的名称空间---->局部的

  • 查找顺序
    局部的名称空间---->全局的名称空间----->内置的名称空间

  • 总结:
    1、名字的查找顺序是从当前位置往外查找
    2、名称空间的嵌套关系是在函数定义阶段就固定死的,与调用位置无关。

5、作用域(作用范围)

域:指的是区域,范围的意思
全局的名称空间和内置的名称空间,在使用上没有什么区别
局部的和全局的内置的就区别了,局部定义的只能在局部使用
函数的作用域在定义时就固定了,与调用的位置没有关系

  • 给三个空间划分范围
    全局的和内置的可以划分为同一个范围
    global 表示的全局范围 ,就是所谓的全局作用域

局部的单独划分为一个范围
local 局部作用域

# 查看全局作用域中的内容
print(globals())
# 查看全局作用域中的值
print(dir(globals()["_builtins_"]))

#明确使用函数外的变量
global age(函数名)

# nonlocal 明确声明使用上一层的函数变量,如果上一层没有,则找上上层的,但是不能找到全局的变量
 nonlocal a(函数名)

# 查看局部作用域中的内容
print(locals())
  • 总结:
    1、如果是不可变类型,函数内变量值改变不会改变全局变量,若要改变需要声明;如果是可变类型,函数内变量值改变会改变全局变量
    2、函数内变量尽量独立,不改变全局变量。

6、闭包函数

闭包函数与普通函数的区别
(1)定义在另一个函数中
(2)在内部的函数中使用了外部的变量(不包含全局的变量)

# 为函数体传值的方案一:直接以参数的形式传入
def f(x):
      print(x)

f(10)

# 为函数体传值的方案二:函数之上传入,并返回函数本身,打包成闭包函数,并且闭包函数的调用赋值给全局变量
def inner():
      x=10
      def f():
            print(x)
      return f       //在返回这个内部的函数时,不是单纯的返回函数,还把内部函数中访问到的局部名称一起打包返回,所以叫做闭包函数
y=inner()
y()
---------------------------------------------
10

# 第二种传参方式可以演变成:
def inner(x):
      def f():
            print(x)
      return f 

y=inner(11)
y()
----------------------------------------------
11

# _closure_用于访问,闭包时打包的数据
print(f._closure_[0].cell_contents)
print(f._closure_[1].cell_contents)

7、装饰器

7.1 什么是装饰器

装饰器:装饰器就是一个用于给其它函数增加功能的函数
装饰器本身可以是任意可调用对象
被装饰对象本身也可以是任意可调用对象

7.2 为什么要用装饰器

开闭原则:对扩展开放,对修改封闭(可以添加新功能,但是不能修改源代码和调用方式)

所以添加新功能,但是源代码不能动,调用方式也不能动;装饰器的目的就是在遵循开闭原则的基础上添加新功能

装饰器 和 闭包函数的关系:装饰器是一种设计代码的套路(在不修改源代码和调用方式的情况下增加功能),要完成装饰器,就需要使用闭包函数

# 装饰器
import time

def index():
    print("开始下载xxx.mp4")
    time.sleep(2)
    print("xxx.mp4 下载完成!")

def outter(func):
    def wrapper():
        start_time = time.time()           //此处可修改,添加新功能
        func()
        end_time = time.time()           //此处可修改,添加新功能
        print("下载耗时:",(end_time - start_time))
    return wrapper

index=outter(index)    //返回给wrapper内存地址;wrapper内存地址中又包括最原始的index内存地址
index()

# 装饰器改进
import time

def outter(func):
    @wraps(func)              //将被装饰对象的属性信息传给新的装饰器函数
    def wrapper(*args,**kwargs):     //将参数完全传给func()
        start_time = time.time()          
        res=func(*args,**kwargs)      //完全接受wrapper的参数;并且以变量的形式接收func()的返回值,也就是被装饰对象的返回值
        end_time = time.time()         
        print("下载耗时:",(end_time - start_time))
        return res
    return wrapper

@outter                //语法糖;index=outter(index) ,根据被装饰函数的名字,自动调用装饰器
def index():
    print("开始下载xxx.mp4")
    time.sleep(2)
    print("xxx.mp4 下载完成!")
    return 1234           //被装饰对象有返回值

@outter              //语法糖;home=outter(home)
def home(name):      //被装饰对象有参数
    time.sleep(1)
    print('welcome %s to home page' %name)

装饰器模板

from functools import wraps          //导入functools模块,装饰器wraps

def outter(func):
      @wraps(func)              //将被装饰对象的所有属性赋值给wrapper
      def wrapper(*args,**kwargs):
            res=func(*args,**kwargs)
            return res
      return wrapper

@outter
def index():
      time.sleep(1)
      print('welcome to index page')
      return 1234

index()

7.3 多个装饰器

多个装饰器加载顺序:(由被装饰函数)由下至上
多个装饰器执行顺序:由上至下
加载顺序:


image.png

执行顺序:


image.png

8、三元表达式

x if x > y else y //条件成立返回左边,条件不成立返回右边
res='ok' if True else 'False' //条件成立执行左边,条件不成立执行右边

9、容器表达式

9.1 列表生成式

l=[i**2 for i in range(10)]    //将for循环的值按照左边表达式直接插入列表

l=[i**2 for i in range(10) if i > 4]   //将for循环的值判断条件,符合条件的值按照左边表达式直接插入列表

sbs=[name.upper() for name in names if name.endswith('sb')]              //在列表names里,如果有sb结尾的将其大写,插入sbs列表

9.2 字典生成式

res=[i:i**2 for i in range(10) if i > 4]
---------------------------------------------------
{5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

9.3 集合生成式

print({i for i in 'hello'})
----------------------------------------------------
{'l', 'o', 'e', 'h'}

10、匿名函数

匿名函数就是指定义了一个函数的内存地址,主要用于临时使用一次的场景

(lambda x,y:x+y)(1,2)            //x,y为参数,没有函数名;冒号后为代码块,自带return     
print(res)
-------------------------------------------------
3 

# 匿名函数通常和其它函数配合使用
print(max(salaries,key=lambda k:salaries[k]))    //以匿名函数作为参数比较大小;key的意思是以什么作为比较的参数,取最大

# 排序
print(sorted(salaries,key=lambda k:salaries[k],reverse=True))             //以value从大到小排序
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容