目录
暂缺javascript
函数
定义函数
你能够定义一个由本身想要功能的函数,如下是简单的规则:java
- 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
- 任何传入参数和自变量必须放在圆括号中间,圆括号之间能够用于定义参数。
- 函数的第一行语句能够选择性地使用文档字符串—用于存放函数说明。
- 函数内容以冒号起始,而且缩进。
- return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return至关于返回 None。
参数传递
在 python 中,类型属于对象,变量是没有类型的:python
a=[1,2,3]c++
a="Runoob"闭包
以上代码中,[1,2,3] 是 List 类型,"Runoob" 是 String 类型,而变量 a 是没有类型,她仅仅是一个对象的引用(一个指针),能够是指向 List 类型对象,也能够是指向 String 类型对象。app
可更改(mutable)与不可更改(immutable)对象ide
在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是能够修改的对象。函数
-
不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,至关于新生成了a。优化
-
可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,自己la没有动,只是其内部的一部分值被修改了。ui
python 函数的参数传递:
python 中一切都是对象,严格意义咱们不能说值传递仍是引用传递,咱们应该说传不可变对象和传可变对象。
def ChangeInt( a ):
a = 10
b = 2
ChangeInt(b)
print( b ) # 结果是 2
传不可变对象实例
实例中有 int 对象 2,指向它的变量是 b,在传递给 ChangeInt 函数时,按传值的方式复制了变量 b,a 和 b 都指向了同一个 Int 对象,在 a=10 时,则新生成一个 int 值对象 10,并让 a 指向它。
# 可写函数说明
def changeme( mylist ):
"修改传入的列表"
mylist.append([1,2,3,4])
print ("函数内取值: ", mylist)
return
# 调用changeme函数
mylist = [10,20,30]
changeme( mylist )
print ("函数外取值: ", mylist)
传可变对象实例
传入函数的和在末尾添加新内容的对象用的是同一个引用。故输出结果以下:
函数内取值: [10, 20, 30, [1, 2, 3, 4]]
函数外取值: [10, 20, 30, [1, 2, 3, 4]]
参数
如下是调用函数时可以使用的正式参数类型:
- 必需参数(位置参数positional参数)
- 关键字参数
- 默认参数
- 不定长参数
必需参数(位置参数positional参数)
必需参数须以正确的顺序传入函数。调用时的数量必须和声明时的同样。
关键字参数
关键字参数和函数调用关系紧密,函数调用使用关键字参数来肯定传入的参数值。
使用关键字参数容许函数调用时参数的顺序与声明时不一致,由于 Python 解释器可以用参数名匹配参数值。
关键字参数必须在位置参数后面,不能出如今它前面,不然报错
#可写函数说明
def printme( str ):
"打印任何传入的字符串"
print (str)
return
#调用printme函数
printme( str = "菜鸟教程")
默认参数
调用函数时,若是没有传递参数,则会使用默认参数。如下实例中若是没有传入 age 参数,则使用默认值:
def printinfo( name, age = 35 ):
"打印任何传入的字符串"
print ("名字: ", name)
print ("年龄: ", age)
return
#调用printinfo函数
printinfo( age=50, name="runoob" )
print ("------------------------")
printinfo( name="runoob" )
以上实例输出结果:
名字: runoob 年龄: 50 ------------------------ 名字: runoob 年龄: 35
不定长参数
可变长指的是实参值的个数不固定
而实参有按位置和按关键字两种形式定义,针对这两种形式的可变长,形参对应有两种解决方案来完整地存放它们,分别是*args,**kwargs
加了星号 * 的参数会以元组(tuple)的形式导入,存放全部未命名的变量参数。
若是在函数调用时没有指定参数,它就是一个空元组。咱们也能够不向函数传递未命名的变量。
加了两个星号 ** 的参数会以字典的形式导入。
特殊的:
def func(*args,**kwargs)定义了不定长参数,传参时,能够直接传元组和字典内的格式也可直接传列表和字典可是传列表和字典时,前面必定要加*号,以下 li = [11,2,2,3,3,4,54] func(*li) di = {'name':'wupeiqi', age:18, 'gender':'male'} func(*
不定长参数的嵌套和使用问题
def func(*a, **k):
def fun1(*a, **k): # 先看fun2
print(a)
print(k)
pass
print(a)
fun1(a, k)
fun1((465,), 789, {})
fun1(*a, **k)
def fun2(*a, **k):
print('fun2 a--', a) # a表明*a接收的元素的元组形式
print('fun2 k--', k) # k表明**k接收的元素的字典形式
print('fun2 *a--', *a) # *a表明*a接收的内容(原始内容,不是元组)
print('fun2 **k--', **k) # **k表明**k接收的内容(原始内容,不是字典)
pass
fun2(*a, **k) # *a也是传递*a包含的原始内容,([1,2,3,4])若如此传参,*a接收的就是([1,2,3,4]), # 在列表,元组前面加*至关于取列表或者元组或者字典的内容
# 能够(*[1,2,3,4]),则*a接收的就是(1,2,3,4)
# 在列表,元组前面加*至关于取列表或者元组或者字典的内容
func(123)
c = ((123,),)
print(c)
print(c.__len__() )
输出结果为
(123,)
((123,), {})
{}
((465,), 789, {})
{}
(123,)
{}
fun2 a-- (123,)
fun2 k-- {}
fun2 *a-- 123
fun2 **k--
((123,),)
1
===========*args===========
def foo(x,y,*args):
print(x,y)
print(args)
foo(1,2,3,4,5)
def foo(x,y,*args):
print(x,y)
print(args)
foo(1,2,*[3,4,5])
def foo(x,y,z):
print(x,y,z)
foo(*[1,2,3])
===========**kwargs===========
def foo(x,y,**kwargs):
print(x,y)
print(kwargs)
foo(1,y=2,a=1,b=2,c=3)
def foo(x,y,**kwargs):
print(x,y)
print(kwargs)
foo(1,y=2,**{'a':1,'b':2,'c':3})
def foo(x,y,z):
print(x,y,z)
foo(**{'z':1,'x':2,'y':3})
===========*args+**kwargs===========
def foo(x,y):
print(x,y)
def wrapper(*args,**kwargs):
print('====>')
foo(*args,**kwargs)
#五、命名关键字参数:*后定义的参数,必须被传值(有默认值的除外),且必须按照关键字实参的形式传递
能够保证,传入的参数中必定包含某些关键字
def foo(x,y,*args,a=1,b,**kwargs):
print(x,y)
print(args)
print(a)
print(b)
print(kwargs)
foo(1,2,3,4,5,b=3,c=4,d=5)
结果:
2
(3, 4, 5)
3
{'c': 4, 'd': 5}
此乃重点知识!!!
可变长参数
闭包函数
一 什么是闭包?
内部函数包含对外部做用域而非全局做用域的引用
提示:以前咱们都是经过参数将外部的值传给函数,闭包提供了另一种思路,包起来喽,包起呦,包起来哇
def counter():
n=0
def incr():
nonlocal n
x=n
n+=1
return x
return incr
c=counter()
print(c())
print(c())
print(c())
print(c.__closure__[0].cell_contents) #查看闭包的元素
闭包函数
二 闭包的意义与应用
闭包的意义:返回的函数对象,不只仅是一个函数对象,在该函数外还包裹了一层做用域,这使得,该函数不管在何处调用,优先使用本身外层包裹的做用域
应用领域:延迟计算(原来咱们是传参,如今咱们是包起来)
from urllib.request import urlopen
def index(url):
def get():
return urlopen(url).read()
return get
baidu=index('http://www.baidu.com')
print(baidu().decode('utf-8'))
用法
尾调用函数
普通的函数递归或者函数调用时,由于外层函数并未结束,因此有一个”调用栈“的概念去储存函数的调用状态,这无形会浪费大量空间时间,无形使代码效率变低。
可是利用尾调函数进行优化的话,即在函数的最后一步(不必定是最后一行)调用别的函数,不会生成“调用”栈,由于在函数的最后一步调用别的函数的话原函数的状态不会保留,至关于原函数已经结束。
这里要注意:return fun(x)是尾调,而 return fun(x)+1不是,由于后者至关于又把调用后的结果赋值给了return,因此调用不是最后一步。不写return在函数尾部直接调用函数也是尾调。
return语句
return [表达式] 语句用于退出函数,选择性地向调用方返回一个表达式。不带参数值的return语句(或不写return)返回None
def test1():
print('1')
def test2():
print('2')
return 0
def test3():
print('3')
return 0, 'qwe',[1,'qwee',[]],{'1':'dsf'}
def test4():
print('4')
return test2
def test5():
print('5')
return test2()
a = test1()
b = test2()
c = test3()
d = test4()
e = test5()
print(a)
print(b)
print(c)
print(d)
print(e)
1
2
3
None
<function test3 at 0x000001672A31A7B8>
(0, 'qwe', [1, 'qwee', []], {'1': 'dsf'})
return的各类返回值
变量做用域
Python 中,程序的变量并非在哪一个位置均可以访问的,访问权限决定于这个变量是在哪里赋值的。
变量的做用域决定了在哪一部分程序能够访问哪一个特定的变量名称。Python的做用域一共有4种,分别是:
- L (Local) 局部做用域
- E (Enclosing) 闭包函数外的函数中
- G (Global) 全局做用域
- B (Built-in) 内建做用域
以 L –> E –> G –>B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找。
x = int(2.9) # 内建做用域
g_count = 0 # 全局做用域
def outer():
o_count = 1 # 闭包函数外的函数中
def inner():
i_count = 2 # 局部做用域
Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的做用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的做用域的
也就是说这些语句内定义的变量,外部也能够访问,若是将变量定义在函数中,则它就是局部变量,外部不能访问
全局变量和局部变量
定义在函数内部的变量拥有一个局部做用域,定义在函数外的拥有全局做用域。
global 和 nonlocal关键字
当内部做用域想修改外部做用域的变量时,就要用到global和nonlocal关键字了。
num = 1
def fun1():
global num # 须要使用 global 关键字声明
print(num)
num = 123
print(num)
fun1()
print(num)
以上实例输出结果:
1
123
123
global用法
若是要修改嵌套做用域(enclosing 做用域,外层非全局做用域)中的变量则须要 nonlocal 关键字了:
def outer():
num = 10
def inner():
nonlocal num # nonlocal关键字声明
num = 100
print(num)
inner()
print(num)
outer()
以上实例输出结果:
100
100
nonlocal用法
注:另外有一种特殊状况,假设下面这段代码被运行:
a = 10
def test(): # 给函数设定一个参数a就行了
a = a + 1
print(a)
test()
以上程序执行,报错信息以下:UnboundLocalError: local variable 'a' referenced before assignment
错误信息为局部做用域引用错误,由于 test 函数中的 a 使用的是局部,未定义,没法修改。
内置函数

函数对象(函数也是对象)
秉承着一切皆对象的理念,咱们再次回头来看函数(function)。函数也是一个对象,具备属性(可使用dir()查询)。
做为对象,它还能够赋值给其它对象名,或者做为参数传递。
lambda函数(匿名函数)
关键字lambda
表示匿名函数,冒号前面的
表示函数参数。
匿名函数有个限制,就是只能有一个表达式,不用写return
,返回值就是该表达式的结果。
用匿名函数有个好处,由于函数没有名字,没必要担忧函数名冲突。此外,匿名函数也是一个函数对象,也能够把匿名函数赋值给一个变量,再利用变量来调用该函数:
>>> f = lambda x: x * x
>>> f
<function <lambda> at 0x101c6ef28> >>> f(5) 25
一样,也能够把匿名函数做为返回值返回,好比:
def build(x, y): return lambda: x * x + y * y
两个参数的匿名函数
func = lambda x,y: x + y
print func(3,4)
lambda生成一个函数对象。该函数参数为x,y,返回值为x+y。函数对象赋给func。func的调用与正常函数无异。
以上定义能够写成如下形式:
def func(x, y):
return x + y
函数做为参数传递
函数能够做为一个对象,进行参数传递。函数名(好比func)即该对象。好比说:
def test(f, a, b):
print 'test'
print f(a, b)
test(func, 3, 5)
test函数的第一个参数f就是一个函数对象。将func传递给f,test中的f()就拥有了func()的功能。
咱们所以能够提升程序的灵活性。可使用上面的test函数,带入不一样的函数参数。好比:
test((lambda x,y: x**2 + y), 6, 9)
map()函数
map()是Python的内置函数。它的第一个参数是一个函数对象。
re = map((lambda x: x+3),[1,3,5,6])
这里,map()有两个参数,一个是lambda所定义的函数对象,一个是包含有多个元素的表。map()的功能是将函数对象依次做用于表的每个元素,每次做用的结果储存于返回的表re中。map经过读入的函数(这里是lambda函数)来操做数据(这里“数据”是表中的每个元素,“操做”是对每一个数据加3)。
在Python 3.X中,map()的返回值是一个可迭代对象。能够利用list()函数,将该循环对象转换成表。
若是做为参数的函数对象有多个参数,可以使用下面的方式,向map()传递函数参数的多个参数:
re = map((lambda x,y: x+y),[1,2,3],[6,7,9])
map()将每次从两个表中分别取出一个元素,带入lambda所定义的函数。
filter()函数
filter函数的第一个参数也是一个函数对象。它也是将做为参数的函数对象做用于多个元素。若是函数对象返回的是True,则该次的元素被储存于返回的表中。filter经过读入的函数来筛选数据。一样,在Python 3.X中,filter返回的不是表,而是循环对象。
filter函数的使用以下例:
def func(a):
if a > 100:
return True
else:
return False
print filter(func,[10,56,101,500])
reduce()函数
reduce函数的第一个参数也是函数,但有一个要求,就是这个函数自身能接收两个参数。reduce能够累进地将函数做用于各个参数。以下例:
print reduce((lambda x,y: x+y),[1,2,5,7,9])
reduce的第一个参数是lambda函数,它接收两个参数x,y, 返回x+y。
reduce将表中的前两个元素(1和2)传递给lambda函数,获得3。该返回值(3)将做为lambda函数的第一个参数,而表中的下一个元素(5)做为lambda函数的第二个参数,进行下一次的对lambda函数的调用,获得8。依次调用lambda函数,每次lambda函数的第一个参数是上一次运算结果,而第二个参数为表中的下一个元素,直到表中没有剩余元素。
上面例子,至关于(((1+2)+5)+7)+9
根据mmufhy的提醒: reduce()函数在3.0里面不能直接用的,它被定义在了functools包里面,须要引入包,见评论区。
实现了 __call__ 的类也能够做为函数
对于一个自定义的类,若是实现了 __call__ 方法,那么该类的实例对象的行为就是一个函数,是一个能够被调用(callable)的对象。例如:
class Add:
def __init__(self, n):
self.n = n
def __call__(self, x):
return self.n + x
>>> add = Add(1)
>>> add(4)
>>> 5
执行 add(4) 至关于调用 Add.__call__(add, 4),self 就是实例对象 add,self.n 等于 1,因此返回值为 1+4
add(4)
||
Add(1)(4)
||
Add.__call__(add, 4)