本节内容

函数def:
1、位置参数,默认参数
2、位置参数,关键参数
3、如果参数中出现 *users,传递的参数就可以不再是固定的个数,
传过来的所有元素进行打包成元组 *args,**kwargs
4、非固定参数:
方式① send_alert('别他么狼了','alex','xxx','xxx','ooo')
方式② send_alert('别他么狼了',*['alex','xxx','iiii'])
5、返回值:return语句把结果返回;碰到return函数就会结束
返回只能返回一个值;当返回多个值的时候,是以元组的形式返回
6、局部变量:只定义在函数里的变量,只能在局部生效,不能在外部调用
在内部可以引用全局变量
在局部修改全局变量:global name (开发不建议用global) 7、全局变量:定义在函数外部一级代码的,全局能用
可以修改 全局变量 里的元素。---> 不可被修改的有 字符串,数字
8、在函数里修改列表内部元素:可以被修改的有:列表,字典,元组(里包含列表,字典等)集合,对象,类
不可被修改:字符串,数字 ---> 已是最小单元,内部元素不可被修改
9、嵌套函数: 多级函数
函数内部可以再定义函数,执行时需要被调用。 10、作用域:在python中,函数就一个作用域,局部变量放置在其作用域中。
代码定义完成之后,作用域已经生成,作用域链向上查找
11、匿名函数:lambda 作用:节省代码量、看着高级
例:func = lambda x,y:x*y # 声明一个匿名函数
func(3,5)
三元运算:lambda x,y:x*y if x < y else x/y
map(lambda x:x**x,data)
12、高阶函数:①函数接受一个函数或多个函数作为输入
②return 返回另一个函数
13、递归、递归的返回值:
递归的特点:
① 必须有一个明确的结束条件
② 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
③ 递归效率不高,递归层次更多会导致栈溢出
递归与栈的关系:
每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。
由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。
求阶乘(factorial): n! = n*(n-1)!
代码如下:
def factorial(n):
if n == 1:
return 1
return n * factorial(n-1)
print(factorial(4))
尾递归: 在调用下一次递归的时候,返回。 14、深度查询: 15、函数内置方法:abs():取绝对值、
dict():把一个数据转成字典、
help():帮助、min()取最小值、
max():
all():所有值bool都为True,只要有一个为0,就为False,空列表也为True
any():与all相反、
dir():打印当前程序所有的变量、
hex():转换为16进制
slice():先定义一个列表切片的规则(没卵用)、
divmod():divmod(10,3)--->(3,1)
sorted():排序,从小到大,可以自定义排序规则
ascii():(没卵用)
enumerate():
oct():8进制
bin():2进制
eval():把字符串转换为代码,去其外表,取本质,只能执行一行代码
exec():与eval()相同,但可以执行多行,区别:exec()--->没有返回值
ord():返回a在ASCII的位置
chr():与ord()相反
sum():求和
bytearray():原内存地址修改字符串,
map():
filter():过滤
reduce():在functools工具包里,functools.reduce
print():
tuple():
callable():判断对象是否可调用(判断变量是否是函数的时候可用)
len():
format():
frozenset():
vars():当前所有变量都会打印出来
locals():在函数里,打印函数当前作用域里所有的局部变量
globals():
repr():显示形式变成字符串
zip():整合两个列表的对应关系
compile():
reversed():默认翻转
complex():复数
round():保留几位小数
delattr,hasattr,getattr,setattr:
hash():哈希
set():把列表变成集合
16、函数练习题:修改个人信息程序 17、函数的进阶:(鸡汤:电影--->荒野生存 ;书:百年孤独;)
命名空间(name space):
分三种:①locals:包括局部变量和形参
②globals:全局变量
③builtins:内置函数模块的名字空间
不同变量的作用域不同就是由这个变量所在的命名空间决定的。
查看作用域方法:globals(),locals()
作用域的查找顺序:
L:locals
E:enclosing 相邻的 外部嵌套函数的名字空间
G:globals 全局变量
B:builtins
闭包:
关于闭包,即函数定义和函数表达式位于另一个函数的函数体内(嵌套函数)。
而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数。
当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。
也就是说,内部函数会在外部函数返回后被执行。而当这个内部函数执行时,
它仍然必需访问其外部函数的局部变量、参数以及其他内部函数。
这些局部变量、参数和函数声明(最初时)的值是外部函数返回时的值,
但也会受到内部函数的影响。 ①装饰器(语法糖):作用:在符合开放、封闭原则下,给原有程序加新功能 ②生成器(generator):
range 底层就是一个生成器
python2
range = list
xrange = 生成器
python3
range = 生成器
xrange 没有
创建方式:
1、列表 生成 式 ()
2、函数 yield 作用: 返回数据,冻结当前的执行过程,并且把值返回给外面的next()
函数里有yield之后, 就会把函数名加()变成一个生成器;return 在生成器里 代表生成器的终止,直接报错
next 唤醒冻结的函数执行过程,继续执行,直到遇到下一个yield 调用next内置函数时,相当于调用了send 也发送了一个信息到生成器内部,但只能发送None
而 send 可以发送任意的值。 send 作用: 唤醒并继续执行,发送一个信息到生成器内部
sign = yield count
if sign == 'stop':
break
# next_range.send("sop") ③迭代器: 生成器是迭代器(Iterator)对象
迭代就相当于 循环 可直接作用于for循环的数据类型,有:
①集合数据类型: 如 list tuple dict set str 等
②generator : 包括 生成器 和 带yield的generator function.
这些可以直接作用于for循环的对象统称为可迭代对象: Iterable.
可以使用 isinstance() 判断一个对象是否是可迭代Iterable对象。 可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator.
可以使用isinstance()判断一个对象是否是Iterator对象. 生成器都是Iterator对象,但列表list、字典dict、字符串str虽然是可迭代的Iterable,却不是迭代器Iterator。
把list、dict、str等Iterable变成Iterator可以使用iter()函数. >>>from collections import Iterator
>>>isinstance((x for i in range(10)),Iterator) ---> True
>>>isinstance([],Iterator) ---> False
>>>isinstance('abc',Iterator) ---> False list,dict,str是Iterable,却不是Iterator。
把list,dict,str的Iterable变成Iterator可以使用iter()函数
>>>isinstance(iter([]),Iterator) ---> True
>>>isinstance(iter('abc'),Iterator) ---> True isinstance()判断一个对象是否是可迭代(Iterable)对象.
>>>from collections import Iterable
>>>isinstance('abc',Iterable) ---> True 18、斐波那契数列(Figonacci): 除第一个和第二个数之外,任意一个数都可由前面两个数相加得到
a,b = 0,1 ; a,b = b,a+b
斐波那契数列用列表生成式写不出来,但是,用函数把它打印出来却很简单.

函数笔记

一、函数定义

什么是函数?

函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的,具体区别,我们后面会讲,编程中的函数在英文中也有很多不同的叫法。在BASIC中叫做subroutine(子过程或子程序),在Pascal中叫做procedure(过程)和function,在C中只有function,在Java里面叫做method。

定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可。

特点:① 减少重复代码;② 使程序变的可扩展;③ 是程序变得可维护。

语法定义:

def sayhi():#函数名
print("Hello!") sayhi() #调用函数

可以带参数

def calc(x,y):
res = x**y
return res #返回函数执行结果 c = calc(a,b) #结果赋值给c变量
print(c)

函数参数

形参变量:只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量。

实参:可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值。

默认参数

  形参在定义时就已经为其赋值,可以传值也可以不传值,经常需要变得参数定义成位置形参,变化较小的参数定义成默认参数(形参)

参考如下代码

def stu_register(name,age,country,course):
print("----注册学生信息------")
print("姓名:",name)
print("age:",age)
print("国籍:",country)
print("课程:",course) stu_register("王山炮",22,"CN","python_devops")
stu_register("张叫春",21,"CN","linux")
stu_register("刘老根",25,"CN","linux")

 发现 country 这个参数 基本都 是"CN", 就像我们在网站上注册用户,像国籍这种信息,你不填写,默认就会是 中国, 这就是通过默认参数实现的,把country变成默认参数非常简单。

def stu_register(name,age,course,country="CN"):

这样,这个参数在调用时不指定,那默认就是CN,指定了的话,就用你指定的值。

注意的问题:1. 只在定义时赋值一次;2. 默认参数的定义应该在位置形参右面;3. 默认参数通常应该定义成不可变类型

另外,你可能注意到了,在把country变成默认参数后,我同时把它的位置移到了最后面,为什么呢?

关键参数

  正常情况下,给函数传参数要按顺序,不想按顺序就可以用关键参数,只需指定参数名即可(指定了参数名的参数就叫关键参数),但记住一个要求就是,关键参数必须放在位置参数(以位置顺序确定对应关系的参数)之后。

def stu_register(name, age, course='PY' ,country='CN'):
print("----注册学生信息------")
print("姓名:", name)
print("age:", age)
print("国籍:", country)
print("课程:", course)

 可以这样调用

stu_register("王山炮",course='PY', age=22,country='JP' )

 但不可以这样调用

stu_register("王山炮",course='PY',22,country='JP' )

 # 这样相当于给age赋值2次,会报错!
stu_register("王山炮",22,age=25,country='JP' )

非固定参数

  若你的函数在定义时不确定用户想传入多少个参数,就可以使用非固定参数

def stu_register(name,age,*args): # *args 会把多传入的参数变成一个元组形式
print(name,age,args) stu_register("hyp",22)
#输出
#hyp 22 () #后面这个()就是args,只是因为没传值,所以为空 stu_register("Jack",32,"CN","Python")
#输出
# Jack 32 ('CN', 'Python')

 还可以有一个**kwargs

def stu_register(name,age,*args,**kwargs): # *kwargs 会把多传入的参数变成一个dict形式
print(name,age,args,kwargs) stu_register("hyp",22)
#输出
#hyp 22 () {}#后面这个{}就是kwargs,只是因为没传值,所以为空 stu_register("Jack",32,"CN","Python",sex="Male",province="ShanDong")
#输出
# Jack 32 ('CN', 'Python') {'province': 'ShanDong', 'sex': 'Male'}

返回值

  函数外部的代码要想获取函数的执行结果,就可以在函数里用return语句把结果返回

def stu_register(name, age, course='PY' ,country='CN'):
print("----注册学生信息------")
print("姓名:", name)
print("age:", age)
print("国籍:", country)
print("课程:", course)
if age > 22:
return False
else:
return True registriation_status = stu_register("王山炮",22,course="PY全栈开发",country='JP') if registriation_status:
print("注册成功")
else:
print("too old to be a student.")

 注意:

  • 函数在执行过程中只要遇到return语句,就会停止执行并返回结果,so 也可以理解为 return 语句代表着函数的结束。
  • 如果未在函数中指定return,那这个函数的返回值为None。

全局变量与局部变量

name = "hyp"

def change_name(name):
print("before change:",name)
name = "hyp是一个有女朋友的人"
print("after change:", name) change_name(name) print("在外面看看name改了么?",name) # 输出
before change: hyp
after change: hyp是一个有女朋友的人
在外面看看name改了么? hyp

 不用传name 值到函数里,也可以在函数里调用外面的变量

name = "hyp"

def change_name():
print("now name: ", name) change_name() print("外部的name: ", name) # 输出
now name: hyp
外部的name: hyp

 但就是不能改!

  • 在函数中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。
  • 全局变量作用域是整个程序,局部变量作用域是定义该变量的函数。
  • 当全局变量与局部变量同名时,在定义局部变量的函数内,局部变量起作用;在其它地方全局变量起作用。

作用域

  作用域(scope),程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。

如何在函数里修改全局变量?

name = "hyp"

def change_name():
global name
name = "hyp还是一名学生"
print("after change", name) change_name() print("在外面看看name改了么?", name)

 global name的作用就是要在函数里声明全局变量name ,意味着最上面的name = "hyp"即使不写,程序最后面的print也可以打印name

嵌套函数

name = "hyp"

def change_name():
name = "hyp2" def change_name2():
name = "hyp3"
print("第3层打印", name) change_name2() # 调用内层函数
print("第2层打印", name) change_name()
print("最外层打印", name) # 输出
第3层打印 hyp3
第2层打印 hyp2
最外层打印 hyp

匿名函数

  匿名函数就是不需要显式的指定函数名

#这段代码
def calc(x,y):
return x**y print(calc(2,5)) #换成匿名函数
calc = lambda x,y:x**y
print(calc(2,5))

 匿名函数主要是和其它函数搭配的使用,如下

res = map(lambda x:x**2,[1,5,7,4,8])
for i in res:
print(i)

高阶函数

  变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。

只需满足以下任意一个条件,即是高阶函数

  • 接受一个或多个函数作为输入
  • return 返回另外一个函数
def add(x,y,f):
return f(x) + f(y) res = add(3,-6,abs)
print(res)

递归

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

def calc(n):
print(n)
if int(n/2) ==0:
return n
return calc(int(n/2)) calc(10) # 输出
10
5
2
1

 来看实现过程,我改了下代码

def calc(n):
v = int(n/2)
print(v)
if v > 0:
calc(v)
print(n) calc(10) # 输出
5
2
1
0
1
2
5
10

为什么呢?来看执行过程是这样的

递归的特性:

  1. 必须有一个明确的结束条件
  2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
  3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

递归有什么用呢?递归函数实际应用案例,二分查找

data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]

def binary_search(dataset,find_num):
print(dataset) if len(dataset) >1:
mid = int(len(dataset)/2)
if dataset[mid] == find_num: #find it
print("找到数字",dataset[mid])
elif dataset[mid] > find_num :# 找的数在mid左面
print("\033[31;1m找的数在mid[%s]左面\033[0m" % dataset[mid])
return binary_search(dataset[0:mid], find_num)
else:# 找的数在mid右面
print("\033[32;1m找的数在mid[%s]右面\033[0m" % dataset[mid])
return binary_search(dataset[mid+1:],find_num)
else:
if dataset[0] == find_num: #find it
print("找到数字啦",dataset[0])
else:
print("没的分了,要找的数字[%s]不在列表里" % find_num) binary_search(data,66)

二分查找

内置函数

1.abs()【绝对值】

2.all()集合中的元素都为真的时候为真,若为空串返回为True

3.any()集合中的元素有一个为真的时候为真若为空串返回为False

4.chr()返回整数对应的ASCII字符

5.ord()返回字符对应的ASC码数字编号

6.bin(x)将整数x转换为二进制字符串

7.bool(x)返回x的布尔值

8.dir()不带参数时,返回当前范围内的变量、方法和定义的类型列表,带参数时,返回参数的属性、方法列表。

9.divmod()分别取商和余数.

10.enumerate()返回一个可枚举的对象,该对象的next()方法将返回一个tuple

11.eval()将字符串str当成有效的表达式来求值并返回计算结果。

12.filter(function, iterable)函数可以对序列做过滤处理

13.hex(x)将整数x转换为16进制字符串。

14.id()返回对象的内存地址

15.len()返回对象的长度

16.map遍历序列,对序列中每个元素进行操作,最终获取新的序列。

17.oct()八进制转换

18.range()产生一个序列,默认从0开始

19.reversed()反转

20.round()四舍五入

21.sorted()队集合排序

22.sum()对集合求和

23.type()返回该object的类型

24.vars()返回对象的变量,若无参数与dict()方法类似。

25.zip()zip函数接受任意多个(包括0个和1个)序列作为参数,返回一个tuple列表。

26.reduce()对于序列内所有元素进行累计操作.

内置参数详解: https://docs.python.org/3/library/functions.html?highlight=built#ascii

几个刁钻古怪的内置方法用法提醒

#compile
f = open("函数递归.py")
data =compile(f.read(),'','exec')
exec(data) #print
msg = "又回到最初的起点"
f = open("tofile","w")
print(msg,"记忆中你青涩的脸",sep="|",end="",file=f) # #slice
# a = range(20)
# pattern = slice(3,8,2)
# for i in a[pattern]: #等于a[3:8:2]
# print(i)
#
# #memoryview
#usage:
#>>> memoryview(b'abcd')
#<memory at 0x104069648>
#在进行切片并赋值数据时,不需要重新copy原列表数据,可以直接映射原数据内存,
import time
for n in (100000, 200000, 300000, 400000):
data = b'x'*n
start = time.time()
b = data
while b:
b = b[1:]
print('bytes', n, time.time()-start) for n in (100000, 200000, 300000, 400000):
data = b'x'*n
start = time.time()
b = memoryview(data)
while b:
b = b[1:]
print('memoryview', n, time.time()-start)

Python全栈开发之路 【第四篇】:Python基础之函数的更多相关文章

  1. Python全栈开发记录_第四篇(集合、函数等知识点)

    知识点1:深拷贝和浅拷贝 非拷贝(=赋值:数据完全共享,内存地址一样,修改一个另一个也变化) 浅拷贝:数据半共享(复制其数据独立内存存放,但是只拷贝成功第一层)像[[1,2],3,4]如果修改列表中列 ...

  2. Python全栈开发之路 【第一篇】:Python 介绍

    本节内容 一.Python介绍 python的创始人为荷兰人——吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本 ...

  3. Python全栈开发之路 【第二篇】:Python基础之数据类型

    本节内容 一.字符串 记住: 有序类型:列表,元组,字符串 ---> 都可迭代: 无序类型:字典,集合 ---> 不可迭代: 特性:不可修改 class str(object): &quo ...

  4. python 全栈开发之路 day1

    python 全栈开发之路 day1   本节内容 计算机发展介绍 计算机硬件组成 计算机基本原理 计算机 计算机(computer)俗称电脑,是一种用于高速计算的电子计算机器,可以进行数值计算,又可 ...

  5. Python全栈开发之路 【第七篇】:面向对象编程设计与开发(1)

    本节内容 一.编程范式 编程指的是写程序.敲代码,就是指程序员用特定的语法.数据结构和算法编写的代码,目的是来告诉计算机如何执行任务的. 在编程的世界里最常见的两大流派是:面向过程与面向对象.“功夫的 ...

  6. Python全栈开发之路 【第八篇】:面向对象编程设计与开发(2)

    一.继承与派生 什么是继承? 继承指的是类与类之间的关系,是一种什么是什么的关系,继承的功能之一就是用来解决代码重用问题. 继承是一种创建新的类的方式,在python中,新建的类可以继承一个或多个父类 ...

  7. Python全栈开发之路 【第六篇】:Python基础之常用模块

    本节内容 模块分类: 好处: 标准库: help("modules") 查看所有python自带模块列表 第三方开源模块: 自定义模块: 模块调用: import module f ...

  8. python 全栈开发,Day32(知识回顾,网络编程基础)

    一.知识回顾 正则模块 正则表达式 元字符 : . 匹配除了回车以外的所有字符 \w 数字字母下划线 \d 数字 \n \s \t 回车 空格 和 tab ^ 必须出现在一个正则表达式的最开始,匹配开 ...

  9. Python全栈开发记录_第十篇(反射及选课系统练习)

    反射机制:反射就是通过字符串的形式,导入模块:通过字符串的形式,去模块中寻找指定函数,对其进行操作.也就是利用字符串的形式去对象(模块)中操作(查找or获取or删除or添加)成员,一种基于字符串的事件 ...

随机推荐

  1. Visual Studio语言设置

    按照的是中文的visual studio,用起来很不方便,因为程序员的都是英文版,平时交流时也是英文的名字 转换语言时发现只有中文和跟随windows系统的设置 官方给的文档看的不是很清楚 查阅资料后 ...

  2. 数据库之mysql篇(3)—— mysql创建/修改数据表/操作表数据

    创建数据表:create table 数据表名 1.创建表规范 create table 表名( 列名   数据类型    是否为空   自动排序/默认值  主键/外键/唯一键, 列名   数据类型 ...

  3. Proxysql读写分离配置

    ProxySQL是Percona主推的读写分离中间件,下载地址为: https://www.percona.com/downloads/proxysql/ 一.安装 1:下载 wget https:/ ...

  4. 服务器体系(SMP, NUMA, MPP)与共享存储器架构(UMA和NUMA)

    1. 3种系统架构与2种存储器共享方式 1.1 架构概述 从系统架构来看,目前的商用服务器大体可以分为三类 对称多处理器结构(SMP:Symmetric Multi-Processor) 非一致存储访 ...

  5. c/c++ 标准库 bind 函数 详解

    标准库 bind 函数 详解 bind函数:接收一个函数名作为参数,生成一个新的函数. auto newCallable = bind(callbale, arg_list); arg_list中的参 ...

  6. python 中文报错

    解决的办法为:在程序的开头写入如下代码,这就是中文注释 #coding=utf-8

  7. May 28. 2018 Week 22nd Monday

    Do one thing at a time, and do well. 一次只做一件事,并且要做到最好. Why is it that about 25% to 50% of people have ...

  8. February 21st, 2018 Week 8th Wednesday

    Our life is what our thoughts make it. 我们的思想成就了我们的生活. The mind is everything. What you think, you be ...

  9. 【Teradata】配置PE和AMP(congfig和reconfig工具、vprocmanager)

    The Reconfiguration and Configuration utilities are used to define the AMPs and PEs that operate tog ...

  10. SQLite 线程安全和并发

    SQLite 与线程 SQLite 是线程安全的. 线程模型 SQLite 支持如下三种线程模型 单线程模型 这种模型下,所有互斥锁都被禁用,同一时间只能由一个线程访问. 多线程模型 这种模型下,一个 ...