1. https://www.jianshu.com/p/168e341fb81c

一、函数定义

函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段;比如常用的print(),就是内建函数;通俗来讲,函数就是把代码打包成不通形状的乐高积木,以便可以根据需求调用拼装;当然这种函数叫做自定义函数。
定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可.
特性: 减少重复代码;使程序变的可扩展;使程序变得易维护.

  • 语法
  1. def 函数名(参数列表):
  2. 函数体
  • 事例
  1. def hello():
  2. print('Hello World')
  3. #上面是函数主体,下面是调用hello这个函数;
  4. hello()
  • 返回值
    要想获取函数的执行结果,就可以用return语句把结果返回
  1. 注意:
  2. 一旦函数经过调用并开始执行,那函数外部的程序,就无法再控制函数的执行过程,只能等待函数执行结果;所以return语句代表着函数的结束;
  3. 如果未在函数中指定return,那这个函数的返回值为None
  4. def count(numb1, numb2):
  5. numb3 = numb1 * numb2
  6. return numb3
  7. print(count(3, 4))
二、函数参数

参数从调用的意义上来讲,分为形式参数和实际参数,简称"形参"和"实参";形参指的是函数创建和定义过程中小括号内的参数;实参是指函数被调用的过程中传递进来的参数;

  • 形参:变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量;
  • 实参:可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值;

     
    形参和实参
  • 普通参数
    普通参数又位置参数,需要按照形参的顺序,进行实参的赋值
  1. def data(name, age):
  2. '''
  3. :param name:
  4. :param age:
  5. :return:
  6. '''
  7. print('姓名:{0}\n年龄:{1}'.format(name, age))
  8. data('lain', 23)
  • 关键字参数
    关键字参数在传入实际参数时指定形参的变量名,不用考虑具体位置
  1. def data(name, age, pro):
  2. '''
  3. :param name:
  4. :param age:
  5. :param pro:
  6. :return:
  7. '''
  8. print('姓名:' + name + '\n年龄:' + age + '\n职业:' + pro)
  9. data(pro='CA', name='LAIN', age='28') #不用考虑先后顺序
  • 默认参数
    使用默认参数时,可以不带实参去调用函数;默认参数是在参数定义的过程中,为形参赋值,当函数调用的时候不传递实参,则默认使用形参的赋值参数代替
  1. def data(pro='CA', name='LAIN', age='28'):
  2. '''
  3. :param name:
  4. :param age:
  5. :param pro:
  6. :return:
  7. '''
  8. print('姓名:' + name + '\n年龄:' + age + '\n职业:' + pro)
  9. data() #实参不传参则按照形参赋值的参数进行打印;
  10. data(name='LIMING', age='30', pro='DBA') #实参传参则按照实参传递的参数进行打印;
  • 收集参数
    一个函数能处理比当初声明时更多的参数是收集参数又叫可变参数或者不定长参数;声明时不会命名;
    命名规范:*args **kwargs
  1. 元组形式:加一个星号(*)的变量名会存放所有未命名的变量参数。如果在函数调用时没有指定参数,它就是一个空元组;
  1. def data(name, age, pro, *hobby):
  2. '''
  3. :param name:
  4. :param age:
  5. :param pro:
  6. :return:
  7. '''
  8. print('姓名:' + name + '\n年龄:' + age + '\n职业:' + pro)
  9. print('兴趣爱好:', *hobby)
  10. data('LIMING', '30', 'DBA', '足球', '跑步', '爬山')
  1. #上面的事例可以理解为打包,既然可以打包那么肯定可以解包
  2. def data(name, age, pro, *hobby):
  3. '''
  4. :param name:
  5. :param age:
  6. :param pro:
  7. :return:
  8. '''
  9. print('姓名:' + name + '\n年龄:' + age + '\n职业:' + pro)
  10. print('兴趣爱好:', *hobby)
  11. a = ['足球', '跑步', '爬山']
  12. data('LIMING', '30', 'DBA', *a)
  1. 字典形式:加两个星号(**)的变量名会存放所有未命名的变量参数。
  1. def data(name, age, pro, *hobby, **mes):
  2. '''
  3. :param name:
  4. :param age:
  5. :param pro:
  6. :return:
  7. '''
  8. print('姓名:' + name + '\n年龄:' + age + '\n职业:' + pro)
  9. print('兴趣爱好:', *hobby)
  10. print('其他信息:', mes)
  11. data('LIMING', '30', 'DBA', '足球', '跑步', '爬山', phone='13452123453', studID='20183511')

如果在函数调用时没有指定参数,它就是一个空字典;

  1. def data(name, age, pro, *hobby, **mes):
  2. '''
  3. :param name:
  4. :param age:
  5. :param pro:
  6. :return:
  7. '''
  8. print('姓名:' + name + '\n年龄:' + age + '\n职业:' + pro)
  9. print('兴趣爱好:', *hobby)
  10. print('其他信息:', mes)
  11. data('LIMING', '30', 'DBA', '足球', '跑步', '爬山')
三、函数的变量作用域

python中的作用域:局部作用域(L-Local)、闭包函数外的函数作用域(E-Enclosing)、全局作用域(G-Global)、内建函数作用域(B-Built-in);

  • 变量作用域由内到外查找:L —>E—>G—>B
  1. 函数外声明的是全局变量,函数内声明的是局部变量;
  2. 全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序;
  3. 当全局变量与局部变量同名时:在定义局部变量的子程序内,局部变量起作用;在其它地方全局变量起作用。
  4. 正常情况下,局部环境变量无法修改全局变量;
  1. a = 0
  2. def number(arg1, arg2):
  3. '''
  4. :param arg1:
  5. :param arg2:
  6. :return:
  7. '''
  8. a = arg1 + arg2
  9. print('函数内a的值: ',a)
  10. print('函数内a的内存地址: ',id(a))
  11. number(1, 2)
  12. print('函数外a的值: ', a)
  13. print('函数外a的内存地址: ', id(a))
  14. 执行结果:
  15. 函数内a的值: 3
  16. 函数内a的内存地址: 492495664
  17. 函数外a的值: 0
  18. 函数外a的内存地址: 492495616
  • 通过global修改全局变量
  1. a = 0
  2. def number(arg1, arg2):
  3. '''
  4. :param arg1:
  5. :param arg2:
  6. :return:
  7. '''
  8. global a
  9. a = arg1 + arg2
  10. print('函数内a的值: ',a)
  11. print('函数内a的内存地址: ',id(a))
  12. number(1, 2)
  13. print('函数外a的值: ', a)
  14. print('函数外a的内存地址: ', id(a))
  15. 执行结果:
  16. 函数内a的值: 3
  17. 函数内a的内存地址: 492495664
  18. 函数外a的值: 3
  19. 函数外a的内存地址: 492495664
  • 通过nonlocal修改闭包函数外的函数变量
  1. a = 0
  2. def number():
  3. '''
  4. :param arg1:
  5. :param arg2:
  6. :return:
  7. '''
  8. a = 1
  9. print('number()函数内a的内存地址: ', id(a))
  10. def soure():
  11. nonlocal a #修改的是外层函数a=1的值
  12. a = 2
  13. print('soure()函数内a的内存地址: ', id(a))
  14. soure()
  15. print('soure()函数外a的内存地址: ', id(a))
  16. number()
  17. print('函数外a的内存地址: ', id(a))
  • lambda表达式
    lambda表达式语法:冒号左边放原函数的参数,可以有多个参数,用逗号隔开即可,冒号右边是返回值。
  1. def calc(x,y):
  2. runturn x*y
  3. print(calc(3,4))
  4. lambda表达式如下
  5. calc = lambda x,y:x*y
  6. print(calc(3,4))
四、递归函数

在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
递归特性:

  1. 自己调用自己;
  2. 必须有一个明确的结束条件;
  3. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少;
  4. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出);
  1. data = range(0,1000000)
  2. def digui(data,find):
  3. if len(data) > 0:
  4. middle_pos = int(len(data)/2)
  5. if data[middle_pos] == find:
  6. print('find_name:',find)
  7. elif data[middle_pos] < find:
  8. print('\033[31;1m 右边的值:%s\033[0m',data[middle_pos+1:])
  9. digui(data[middle_pos+1:],find)
  10. else:
  11. print('\033[32;1m 左边的值:%s\033[0m',data[0:middle_pos])
  12. digui(data[0:middle_pos],find)
  13. else:
  14. print('没有找到!')
  15. digui(data,451232)
  1. def sum_number(n):
  2. if n <= 0:
  3. return 0
  4. return n+sum_number(n-1)
  5. print(sum_number(100))
五、推导式
  • 列表推导式
  1. list = [i*i for i in range(10)] #列表推导式,用中括号表示
  2. print(list)
  3. list1 = []
  4. for i in range(10):
  5. list1.append(i*i)
  6. print(list1)
  7. 其他事例:
  8. list = [i*i for i in range(10) if i%2 == 0]
  9. print(list)
  10. list = [x*y for x in range(1, 10) for y in range(1, 10) if x >= y]
  11. print(list)
  • 字典推导式
  1. dic = {i:i*i for i in range(5)} #大括号内冒号左右分别是key、value组合
  2. print(dic)
  • 集合推导式
  1. s = {i for i in 'hello world' if i not in 'w'} #集合与字典推导式的区别是key、value组合
  2. print(s)
  • 元组推导式
  1. tup = tuple(i for i in range(5)) #tuple
  2. print(tup)
****
  1. result = [lambda x:x + i for i in range(5)]
  2. print(result[0](10)) #调用函数时循环结束i的值为4,所以结果为10+4=14
  3. 14
  4. result = [lambda x,y=i:x + y for i in range(5)]
  5. print(result[0](10)) #每次循环将i赋值给y,结果为0+10=10
  6. print(result[1](10)) #每次循环将i赋值给y,结果为1+10=11
六、迭代器

迭代:通过for循环遍历对象每个元素的过程
我们已经知道,可以直接作用于for循环的数据类型有以下几种:

  • 一类是集合数据类型,如list、tuple、dict、set、str等;
  • 一类是generator,包括生成器和带yield的generator function;
    以上这些统称为可迭代对象(Iterable)
  1. 可以通过python内置的方法Iterable来测试数据类型是否为可迭代对象
  2. from collections import Iterable
  3. print(isinstance('Hello', Iterable)) #字符串是可迭代对象
  4. print(isinstance([1, 2, 3], Iterable)) #列表是可迭代对象
  5. print(isinstance({'a':2, 'b':3}, Iterable)) #字典是可迭代对象
  6. print(isinstance((1, 2, 3), Iterable)) #元组是可迭代对象
  7. print(isinstance({1, 2, 3}, Iterable)) #集合是可迭代对象
  8. print(isinstance(1, Iterable)) #整数是不可迭代对象
  9. 运行结果:
  10. True
  11. True
  12. True
  13. True
  14. True
  15. False

可以迭代并且可以被next()函数和iter()调用,并不断返回下一个值的对象就称为迭代器(Iterator);迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往后遍历不能回溯,不像列表,你随时可以取后面的数据,也可以返回头取前面的数据。

  1. 通过Iterator可以测试上面的可迭代对象是否为迭代器
  2. from collections import Iterator
  3. print(isinstance('Hello', Iterator)) #字符串不是迭代器
  4. print(isinstance([1, 2, 3], Iterator)) #列表不是迭代器
  5. print(isinstance({'a':2, 'b':3}, Iterator)) #字典不是迭代器
  6. print(isinstance((1, 2, 3), Iterator)) #元组不是迭代器
  7. print(isinstance({1, 2, 3}, Iterator)) #集合不是迭代器
  8. print(isinstance(1, Iterator)) #整数是不是迭代器
  9. 运行结果:
  10. False
  11. False
  12. False
  13. False
  14. False
  15. False
  1. 通过iter()函数创建迭代器
  2. numb = [1, 2, 3, 4, 5] #创建的是列表,通过iter函数创建就是列表迭代器,如果是集合、字典、字符串那就是集合迭代器、字典迭代器、字符串迭代器;
  3. it = iter(numb)
  4. print(type(it))
  5. 运行结果:
  6. <class 'list_iterator'> #列表迭代器
  1. 通过next()函数取值
  2. numb = 'hello'
  3. it = iter(numb)
  4. print(next(it))
  5. print(next(it))
  6. print(next(it))
  7. print(next(it))
  8. print(next(it))
  9. 运行结果: #从第一个元素开始,到遍历完成结束;
  10. h
  11. e
  12. l
  13. l
  14. o
  • 为什么list、dict、str等数据类型不是Iterator?
  1. 这是因为PythonIterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
  2. Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
七、生成器

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。生成器的作用是一边获取一边生成,用多少生成多少;

  1. #推导式生成器
  2. g = (i* i for i in range(4))
  3. print(type(g))
  4. 运行结果:
  5. <class 'generator'> #类型为生成器
  1. #通过yield,函数返回值会变成生成器
  2. - 斐波那契数列
  3. def fibonacci(n):
  4. a, b, counter = 0, 1, 0
  5. while True:
  6. if counter > n:
  7. return
  8. yield a
  9. a, b = b, a+b
  10. counter = counter + 1
  11. fib = fibonacci(10)
  12. # print(type(fib))
  13. for i in fib:
  14. print(i, end=',')
  15. 运行结果:
  16. <class 'generator'> #print数据类型为生成器
  17. 0,1,1,2,3,5,8,13,21,34,55, #直接遍历取出
八、装饰器

装饰器定义:装饰器是函数,只不过该函数可以具有特殊的含义,装饰器用来装饰函数或类,使用装饰器可以在函数执行前和执行后添加相应操作完全符合程序开发中,开放-封闭原则;不改变原有代码功能,不改变原有调用方式实现新功能的扩张。

  1. # -*- coding: UTF-8 -*-
  2. # Author: LAIN
  3. # Time: 2018-08-15
  4. #装饰器
  5. user_status = False
  6. def login(fund):
  7. def inner():
  8. user = 'LAIN'
  9. pwd = '12345'
  10. global user_status
  11. if user_status == False:
  12. username = input('USER:')
  13. passwd = input('PASSWORD:')
  14. if username == user and passwd == pwd:
  15. print('登录成功')
  16. user_status = True
  17. else:
  18. print('账号密码错误!')
  19. if user_status == True:
  20. fund()
  21. return inner
  22. def home():
  23. print('-----商城首页-----')
  24. @login #语法糖,表明这是个装饰器
  25. def numerical():
  26. print('-----电子数码-----')
  27. @login
  28. def food():
  29. print('-----食品生鲜-----')
  30. @login
  31. def department():
  32. print('-----百货商品-----')
  33. home()
  34. numerical() #运行login函数后调用
  35. food() #运行login函数后调用
  36. department() #运行login函数后调用

[转帖]Python基础之函数(四)的更多相关文章

  1. python基础篇(四)

    PYTHON基础篇(四) 内置函数 A:基础数据相关(38) B:作用域相关(2) C:迭代器,生成器相关(3) D:反射相关(4) E:面向对象相关(9) F:其他(12) 匿名函数 A:匿名函数基 ...

  2. python基础之函数详解

    Python基础之函数详解 目录 Python基础之函数详解 一.函数的定义 二.函数的调用 三.函数返回值 四.函数的参数 4.1 位置参数 4.2 关键字参数 实参:位置实参和关键字参数的混合使用 ...

  3. python基础——匿名函数

    python基础——匿名函数 当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便.  在Python中,对匿名函数提供了有限支持.还是以map()函数为例,计算f(x)=x2时 ...

  4. python基础——返回函数

    python基础——返回函数 函数作为返回值 高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回.  我们来实现一个可变参数的求和.通常情况下,求和的函数是这样定义的: def calc_ ...

  5. python基础——sorted()函数

    python基础——sorted()函数 排序算法 排序也是在程序中经常用到的算法.无论使用冒泡排序还是快速排序,排序的核心是比较两个元素的大小.如果是数字,我们可以直接比较,但如果是字符串或者两个d ...

  6. python基础——filter函数

    python基础——filter函数 Python内建的filter()函数用于过滤序列. 和map()类似,filter()也接收一个函数和一个序列.和map()不同的是,filter()把传入的函 ...

  7. python基础——匿名函数及递归函数

    python基础--匿名函数及递归函数 1 匿名函数语法 匿名函数lambda x: x * x实际上就是: def f(x): return x * x 关键字lambda表示匿名函数,冒号前面的x ...

  8. 八. Python基础(8)--函数

    八. Python基础(8)--函数 1 ● 函数返回布尔值 注意, 自定义的函数也可以是用来作逻辑判断的, 例如内置的startswith()等函数. def check_len(x):     ' ...

  9. Python全栈开发之路 【第四篇】:Python基础之函数

    本节内容 函数def: 1.位置参数,默认参数 2.位置参数,关键参数 3.如果参数中出现 *users,传递的参数就可以不再是固定的个数, 传过来的所有元素进行打包成元组 *args,**kwarg ...

  10. Python基础__函数

    本节将进入函数的介绍,函数是Python基础中最精彩的部分之一,接下来将对函数做详细介绍.函数 函数就是对代码进行一个封装.把实现某一功能的代码进行封装到一起.下次需要使用时不需要进行编写代码直接调用 ...

随机推荐

  1. Spring Cloud 学习推荐

    学习 Spring Boot Spring tutorials | Java Web Development, Spring Cloud Programming tutorials Spring Bo ...

  2. 数据库面试要点:关于MySQL数据库千万级数据查询和存储

    摘要:百万级.千万级数据处理,核心关键在于数据存储方案设计,存储方案设计的是否合理,直接影响到数据CRUD操作.总体设计可以考虑一下几个方面进行设计考虑: 数据存储结构设计:索引设计:数据主键设计:查 ...

  3. 探究Python源码,终于弄懂了字符串驻留技术

    摘要:在本文中,我们将深入研究 Python 的内部实现,并了解 Python 如何使用一种名为字符串驻留(String Interning)的技术,实现解释器的高性能. 每种编程语言为了表现出色,并 ...

  4. 云小课|ModelArts Pro 视觉套件:零代码构建视觉AI应用

    阅识风云是华为云信息大咖,擅长将复杂信息多元化呈现,其出品的一张图(云图说).深入浅出的博文(云小课)或短视频(云视厅)总有一款能让您快速上手华为云.更多精彩内容请单击此处. 摘要:ModelArts ...

  5. 应用数仓ODBC前,这些问题你需要先了解一下

    摘要:ODBC为解决异构数据库间的数据共享而产生的,现已成为WOSA的主要部分和一种数据库访问接口标准. 本文分享自华为云社区<GaussDB(DWS) ODBC 问题定位指南>,作者: ...

  6. 面试官问:mysql中时间日期类型和字符串类型的选择

    摘要:MySQL中有多种表示时间日期的数据类型,主要有YEAR.TIME.DATE.DATETIME.TIMESTAMP等 本文分享自华为云社区<一针见血,mysql中时间日期类型和字符串类型的 ...

  7. html5鼠标拖动排序及resize实现方案分析及实践

    对列表进行拖动排序,尺寸改变.之前一般会使用jQuery-UI.其通过mousedown.mousemove.mouseup这三个事件来实现页面元素被鼠标拖拽的效果.vue-drag-resize v ...

  8. ​Black Hat 2022 聚焦软件供应链安全

    Black Hat 大会被公认为世界信息安全行业最权威大会,也是在全球范围内最具有技术性的信息安全大会.Black Hat USA 聚焦网络安全事件,并且持续向外界输出前沿安全技术研究成果以及行业发展 ...

  9. 渗透测试 vs 漏洞扫描:差异与不同

    渗透测试和漏洞扫描常常被混淆,这两者都通过探索系统来寻找 IT 基础架构中的弱点及易受攻击的地方.阅读本文,带你了解两者之间的差异与不同. 手动 vs 自动 渗透测试是一种手动安全评估方式,网络安全人 ...

  10. Java 事件链

    Java中的事件机制的参与者有3种角色: 1. event object:就是事件产生时具体的"事件",用于listener的相应的方法之中,作为参数,一般存在于listerner ...