函数调用
定义一个函数:给了函数一个名称,指定了函数里包含的参数,和代码块结构。
这个函数的基本结构完成以后,你可以通过另一个函数调用执行,也可以直接从 Python 命令提示符执行。
如下实例调用了 printme() 函数:
#!/usr/bin/python3
# 定义函数
defprintme(str):
# 打印任何传入的字符串
print(str)
return# 调用函数
printme("我要调用用户自定义函数!")
printme("再次调用同一函数")
以上实例输出结果:
我要调用用户自定义函数!再次调用同一函数函数特性:
减少重复代码
使程序变的可扩展
使程序变得易维护
参数 :
必须参数 ---》
--必需参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
def t1(x):
print(x)
t1(2) # 必须传入一个参数 否则不传入参数会运行报错
输出结果 2
关键字参数 ---》
关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。
使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
实例:
deft2(**kwargs):
print(kwargs)
t2(name='tom',age=28,sex='N')
t2(**{'name': 'jony','sex': 'F’})
输出结果为:
{'name': 'tom', 'sex': 'N', 'age': 28}
{'name': 'jony', 'sex': 'F'}
默认参数
调用函数时,如果没有传递参数,则会使用默认参数。
实例;
def t(x, y=2):
print(x)
print(y)
t(1)
t(1,3) #1,3 是位置参数也是实参 与形参一一对应
输出结果:
x 是形参 y为默认参数
1
2
1
3
不定长参数
你可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,和上述 2 种参数不同,声明时不会命名。如下:
deft3(*args):
print(args)
t3(10,20,30,50,80)
输出结果:(10, 20, 30, 50, 80) #元组
加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数
#*args接受N个位置参数,转化成元组;
#**kwargs接收N个关键字参数,转为字典
#位置参数必须放在关键字参数前面
#关键字与形参顺序无关
def test(x,y,z):
print(x)
print(y)
print(z)
# test(y=2,x=1) #与形参顺序无关
# test(1,2) #与形参一一对应
#test(x=2,3)
test(3,z=2,y=6)
全局与局部变量:全局变量和局部变量的区别在于作用域,全局变量在整个py文件中声明,全局范围内可以使用;局部变量是在某个函数内部声明的,只能在函数内部使用,如果超出使用范围(函数外部),则会报错。
当全局变量与局部变量同名时:(在函数内部,如果局部变量与全局变量变量名一样,则优先调用局部变量。)在定义局部变量的子程序内,局部变量起作用;在其它地方全局变量起作用。
实例
school = ‘old boy’ # 全局变量
def change_name(name):
print(“before change ”,name,school)
name=’kk’ #这个函数就是这个变量的作用域 也就是说在此函数内生效
print(“after change ”,name)
name=’gg’
chang_name(name)
print(name)
输出结果为:
before change gg mage
after change kk
gg old boy
或
school = 'old boy' # 全局变量
name='gg'
def change_name(name):
global school # 声明局部变量改为全局变量
school = 'mage'
print("before change ",name,school)
name='kk' #这个函数就是这个变量的作用域 也就是说在此函数内生效
print("after change ",name)
#name='gg'
change_name(name)
print(name,school)
输出结果;
before change gg mage
after change kk
gg mage
返回值
函数的最后都有一个返回值return,可以用来获取该函数执行结果返回给该函数,让外部调用该函数的根据返回的值不同做不同的事。
返回值可指定,如果不指定默认返回None
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def test1():
print('alex')
print(test1())
def test2():
a= 5
if a <5:
return True
else:
return False
print(test2())
#根据返回的值进行其他判断
if test2():
print('yes')
else:
print('no')
结果:
alex
None
False
no
函数遇到return后就结束,该函数return下还有多少代码都不执行
函数可以返回多个值
结果:
(1, 2)
返回多值其实就是返回一个tuple,在语法上返回一个tuple可以省略括号
也可以返回列表
结果:
[1, 2]
递归函数:
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
递归函数特性:
必须有一个明确的结束条件;
每次进入更深一层递归时,问题规模相比上次递归都应有所减少
相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入)。
递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
实例:
def calc ( n ):
print(n)
if int(n/2)==0:
return n
return calc(int (n /2)) # 函数递归
calc(10)
输出结果:
10
5
2
1
递归实现三级菜单练习
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
menu = {
'北京': {
'海淀': {
'五道口': {
'soho': {},
'网易': {},
'google': {}
},
'中关村': {
'爱奇艺': {},
'汽车之家': {},
'youku': {},
},
'上地': {
'百度': {},
},
},
'昌平': {
'沙河': {
'老男孩': {},
'北航': {},
},
'天通苑': {},
'回龙观': {},
},
'朝阳': {},
'东城': {},
},
'上海': {
'闵行': {
"人民广场": {
'炸鸡店': {}
}
},
'闸北': {
'火车战': {
'携程': {}
}
},
'浦东': {},
},
'山东': {},
}
exit_flag = False
l = [menu]
# k= input('input>>').strip()
# print (l[-1][k]) # {'浦东': {}, '闸北': {'火车战': {'携程': {}}}, '闵行': {'人民广场': {'炸鸡店': {}}}}
# print (l[-1].keys()) # (['山东', '北京', '上海']
while not exit_flag:
for key in l[-1]:
print(key)
k = input('input>>').strip() # 北京
if k in l[-1].keys() and l[-1][k]:
l.append(l[-1][k])
elif k == 'b':
l.pop()
elif k == 'q':
exit_flag =True
else:
print( "输入错误,请重新输入")
二分查找法
l = [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,56,66,67,69,72,76,82,83,88]
print(l.index(66))
输出结果: 17 #(index=17)
匿名函数
匿名函数就是不需要显式的指定函数名。
关键字lambda表示匿名函数,冒号前面的n表示函数参数,可以有多个参数。
匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。
用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数:
有些函数在代码中只用一次,而且函数体比较简单,使用匿名函数可以减少代码量,看起来比较"优雅“
实例
#这段代码
def calc(x,y):
return x**y
#换成匿名函数
calc = lambda x,y:x**y
print(calc(2,5))
输出结果 32
函数式编程:
函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元。
函数式编程中的函数这个术语不是指计算机中的函数(实际上是Subroutine),而是指数学中的函数,即自变量的映射。也就是说一个函数的值仅决定于函数参数的值,不依赖其他状态。比如sqrt(x)函数计算x的平方根,只要x不变,不论什么时候调用,调用几次,值都是不变的。
Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。
一、定义
简单说,"函数式编程"是一种"编程范式"(programming paradigm),也就是如何编写程序的方法论。
主要思想是把运算过程尽量写成一系列嵌套的函数调用。举例来说,现在有这样一个数学表达式:
(1 + 2) * 3 - 4
传统的过程式编程,可能这样写:
var a = 1 + 2;
var b = a * 3;
var c = b - 4;
函数式编程要求使用函数,我们可以把运算过程定义为不同的函数,然后写成下面这样:
var result = subtract(multiply(add(1,2), 3), 4);
这段代码再演进以下,可以变成这样
add(1,2).multiply(3).subtract(4)
这基本就是自然语言的表达了。再看下面的代码,大家应该一眼就能明白它的意思吧:
merge([1,2],[3,4]).sort().search("2")
因此,函数式编程的代码更容易理解。
要想学好函数式编程,不要玩py,玩Erlang,Haskell, 好了,我只会这么多了。。
面向对象和面向过程
面向对象---》类---》class
面向过程---》过程---》def
函数式编程---》函数---》def
高阶函数:
一个函数可以作为参数传给另外一个函数,或者一个函数的返回值为另外一个函数(若返回值为该函数本身,则为递归),满足其一则为高阶函数。
实例
#参数为函数
def bar():
print("in the bar..")
def foo(func):
func()
print("in the foo..")
foo(bar)
输出结果;
in the bar..
in the foo..
#返回值为函数
def bar():
print("in the bar..")
def foo(func):
print("in the foo..")
return bar
res=foo(bar)
print(res)
print(res())
输出结果 :
in the foo..
in the bar..
None
#返回值为函数
def bar():
print("in the bar..")
def foo(func):
print("in the foo..")
return bar
res=foo(bar)
res()
以上两个示例中,函数foo()为高阶函数,示例一中函数bar作为foo的参数传入,示例二中函数bar作为foo的返回值。
注:函数名(例如bar 、foo)-->其为该函数的内存地址;函数名+括号(例如 bar()、foo() )-->调用该函数。
高阶函数-map、filter、reduce
这三个函数均为高阶函数,其也为Python内置的函数
map函数
map函数接收的是两个参数,一个函数,一个序列,其功能是将序列中的值处理再依次返回至列表内
实例:
map()传入的第一个参数是f,即函数对象本身。由于结果r是一个Iterator,Iterator是惰性序列,因此通过list()函数让它把整个序列都计算出来并返回一个list。
filter函数
filter函数也是接收一个函数和一个序列的高阶函数,其主要功能是过滤。其返回值也是迭代器对象
reduce函数
reduce函数也是一个参数为函数,一个为可迭代对象的高阶函数,其返回值为一个值而不是迭代器对象,故其常用与叠加、叠乘等
实例:
或:
from functools import reduce # 高阶函数
def add(x,y):
return x + y
t=reduce(add,(1,4,5,7,9))
print(t)
输出结果:26
内置函数:
注:查看详细猛击这里
abs() 对传入参数取绝对值
bool() 对传入参数取布尔值, None, 0, "",[],{},() 这些参数传入bool后,返回False
all() 所有传入参数为真,才为真
any() 任何一个传入参数为真,才为真
ascii() 自动执行传入参数的_repr_方法(将对象转换为字符串)
bin() 接收一个十进制,转换成二进制
oct() 接收一个十进制,转换成八进制
hex() 接收一个十进制,转换成十六进制
bytes() 字符串转换成字节。第一个传入参数是要转换的字符串,第二个参数按什么编码转换为字节 eg. bytes(s,encoding = 'utf-8') , bytes(s,encoding = 'gbk') 1个字节占8位;utf-8编码格式下,一个汉字占3个字节;gbk编码格式下,一个汉字占2个字节
str() 字节转换成字符串。第一个传入参数是要转换的字节,第二个参数是按什么编码转换成字符串
chr(65) # 数字转字母,查看ASCII码表
ord('A') # 字母转数字,查看ASCII码表
compile() # 接收.py文件或字符串作为传入参数,将其编译成python字节码
eval() # 执行python代码,并返回其执行结果。 e.g. eval("1+2+3") eval("print(123)"). 在接收用户输入时应避免使用eval,因为别有用心的用户可能借此注入恶意代码
exec() #执行python代码(可以是编译过的,也可以是未编译的),没有返回结果(返回None) e.g. exec(compile("print(123)","","exec")) exec("print(123)")
dir() # 接收对象作为参数,返回该对象的所有属性和方法
help() # 接收对象作为参数,更详细地返回该对象的所有属性和方法
divmod(100,10) # 返回一个元组(10,0),第一个元素的100/10的商,第二个元素的100/10的余数
enumerate() # 接收序列化类型的数据,返回一个迭代器(对象). e.g. for i,item in enumerate(['one','two','three']): print(i,item) 打印1 'one' 换行2 'two'换行 3 'three'
isinstance(object, class) # 判断对象是否是某个类的实例. e.g. isinstance([1,2,3],list)
filter(函数或者lambda表达式,可迭代的对象) # 对可迭代对象中的每一个元素,将其作为实参传入函数(或lambda表达式),如果函数返回False,将该元素丢弃,如果函数返回True,将该元素添加到filter的返回值中。注意filter返回的是一个filter对象,实际应用中往往需要用list或tuple将其转换为列表或元组类型. e.g. list(filter(lambda a:a>1,[1,2,3])) 返回[2,3]
map(函数或lambda表达式,可迭代的对象) #对可迭代的每一个元素,将其作为实参传入函数,将每一次调用函数返回的结果都添加到map的返回值中。e.g. tuple(map(lambda a:a+1,(1,2,3))) 返回(2,3,4)
format() #字符串格式化
frozenset() #转换为不可变的集合
globals() # 返回一个字典,包括所有的全局变量与它的值所组成的键值对
locals() # 返回一个字典,包括所有的局部变量与它的值所组成的键值对
hash() # 对传入参数取哈希值并返回
id() # 返回内存地址,可用于查看两个变量是否指向相同一块内存地址
input('please input:') # 提示用户输入,返回用户输入的内容(不论输入什么,都转换成字符串类型)
issubclass(subclass,class) #查看这个类是否是另一个类的派生类,如果是返回True,否则返回False
len('string') # 返回字符串长度,在python3中以字符为单位,在python2中以字节为单位
max() #接收序列化类型数据,返回其中值最大的元素
min() # ..... 返回其中值最小的元素
memoryview() # 查看内存地址
next()
iter()
object()
pow(x,y) # 求次方,返回x**y的结果
pow(x,y,z) # 返回 x**y%z 的结果
property() # 获取对象的所有属性
range() # 获取随机数或随机字符 eg. range(10) 从0到10的随机数
repr() # 执行传入对象中的_repr_方法
reversed() #对序列化类型数据反向排序,返回一个新的对象。注意与对象的reverse方法区别,后者是就地改变对象
sorted() # 对序列化类型数据正向排序,返回一个新的对象。注意与对象的sort方法区别,后者是就地改变对象
slice() #对序列化类型数据切片,返回一个新的对象。eg. slice(起始下标,终止下标,步长),步长默认为1
round() # 返回四舍五入后的结果
int() #转换为整型
list() # 转换为列表类型
set() # 转换为集合类型
str() #转换为字符串类型
tuple() # 转换为元组类型
type() # 返回对象类型
staticmethod() # 返回静态方法
super() # 返回基类
vars() #返回当前模块中的所有变量
zip() # 接收多个序列化类型的数据,对各序列化数据中的元素,按索引位置分类成一个个元组。
eg. myList = list(zip([1,2,3],['a','b','c'])) 创建myList列表[(1,'a'),(2,'b'),(3,'c')]
mydic = dict(zip([1,2,3],['a','b','c'])) 创建mydic字典{1:'a',2:'b',3:'c'}
l1 = [1,2,3]
l2 = ['one','two','three']
list(zip(l1,l2)) 返回[(1,'one'),(2,'two'),'(3,'three')]