第1章 Day3函数
1.1 函数与过程的区别
为什么要有返回值
是因为下面的程序有可能要以这个函数的返回结果做不同的操作
#函数
def func1():
'''testing1'''
print('in the func1')
return 0
#过程
def func2():
'''testing2'''
print('in the func2')
x=func1()
y=func2()
print('from func1 is %s' %x)
print('from func1 is %s' %y)
过程没定义返回值默认返回None
1.2 函数的作用
为了把相同逻辑的代码模块化 可以是程序变得简洁
提高代码利用率 避免相同代码多次出现
提高程序的可扩展性
import time
def logger():
time_format = '%Y-%m-%d %X'
time_current = time.strftime(time_format)
with open('a.txt','a+')as f:
f.write('%s end action ' %time_current)
def test1():
print('in the test1')
logger()
def test2():
print('in the test2')
logger()
def test3():
print('in the test3')
logger()
test1()
test2()
test3()
1.3 返回值可以传多个参数
Python会把他当成一个元组返回
import time
def logger():
time_format = '%Y-%m-%d %X'
time_current = time.strftime(time_format)
with open('a.txt','a+')as f:
f.write('%s end action ' %time_current)
def test1():
print('in the test1')
logger()
def test2():
print('in the test2')
logger()
def test3():
print('in the test3')
logger()
test1()
test2()
test3()
def test1():
pass
def test2():
return 0
def test3():
return 0,'hello',['a','b','c'],{'name':'lieying'}
x=test1()
y=test2()
z=test3()
print(x)
print(y)
print(z)
执行结果
None
0
(0, 'hello', ['a', 'b', 'c'], {'name': 'lieying'})
1.4 返回值可以是函数名
def test1():
print('in the test1')
pass
def test2():
print('in the test2')
return 0
def test3():
print('in the test3')
#return 0,'hello',['a','b','c'],{'name':'lieying'}
return test2 #这里返回的将是test2函数的id
x=test1()
y=test2()
z=test3()
print(x)
print(y)
print(z)
返回结果
in the test1
in the test2
in the test3
None
0
<function test2 at 0x00000000031220D0>
1.5 形参
1.5.1 位置形参:按照从左到右顺序依次定义的参数 必须被传参多一个不行,少一个也不行
默认参数 也称关键字形参例如
def foo(x,y,z=1):
print(x,y,z)
foo(2,y=3,z=4)
x 为位置形参 y=1为默认参数
2 为位置实参
1.5.2 默认参数
def test(x,y=2):
print(x)
print(y)
test(1)
test(1,3)
def conn(host,port=3306)
pass
#默认参数特点:调用函数的时候,默认参数非必须传递
#用途: 1.默认安装
默认参数必须在位置参数的后面
def haha(x=1,y):
print(x,y)
haha(2)
File "C:/Users/Administrator/PycharmProjects/python18期/day3/函数.py", line 1
def haha(x=1,y):
^
SyntaxError: non-default argument follows default argument
默认参数只在定义阶段赋值一次
x=100
def foo(a,b=x):
print(a,b)
x=200000000000
foo('egon')
默认参数的值应该定义成不可变类型
1.5.3 命名关键字参数: 在*后面定义的形参成为命名关键字参数,必须是被以关键字实参的形式传值
def foo(name,age,*,sex,hobby):
print(name,age,sex,hobby)
# foo('alex',73,'male','girl')
foo('alex',73,hobby='boy',sex='female')
foo(name='alex',sex='male',hobby='girl',age=74)
1.6 实参
1.6.1 位置实参:与形参按照位置一一对应
def test(x,y,z):
print(x)
print(y)
print(z)
#位置调用
#1,2,3 为实参
#test(1,2,3)
1.6.2 关键字实参:按照key:value的形式指名道姓的给name传参的形式
def foo(name,age,sex,hobby):
print(name,age,sex,hobby)
foo('alex',73,'male','girl')
foo(name='alex',sex='male',hobby='girl',age=74)
1.6.3 传参注意事项
位置实参必须在关键字实参的前面
def foo(x,y,z=1):
print(x,y,z)
foo(2,y=3,4)#这样调用会报错
不要对同一个形参传多次值
1.7 各种传参的结果
#*args:接受N个位置参数,转换成元组形式
# def test(*args):
# print(args)
# test(1,2,3,4,5,5)
# test(*[1,2,3,4,5,5])# args = tuple
# def test1(x,*args):
# print(x)
# print(args)
# test1(1,2,3,4,5,6,7)
#**kwargs: 接受N个关键字参数,转换成字典的方式
# def test2(**kwargs):
# print(kwargs)
# print(kwargs['name'])
# print(kwargs['age'])
# # print(kwargs['sex'])
# # print(kwargs['hobby'])
#
# test2(name='lieying',age=22,sex='man',hobby='gril')
# test2(**{'name':'alex','age':8})
#
# def test3(name,**kwargs):
# print(name)
# print(kwargs)
# test3('alex',age=18,sex='m')
# def test4(name,age=18,**kwargs):
# print(name)
# print(age)
# print(kwargs)
#
# test4('alex',age=34,sex='m',hobby='tesla')
def logger(source):
print("from %s" % source)
def test4(name,age=18,*args,**kwargs):
print(name)
print(age)
print(args)
print(kwargs)
logger("TEST4")
test4('alex',age=34,sex='m',hobby='tesla')
1.8 高阶函数 意思是函数里套函数
def add(a,b,f):
return f(a)+f(b)
res = add(3,-6,abs)
print(res)
1.8.1 高阶函数
def add(a,b,f):
return f(a)+f(b)
res = add(3,-6,abs)
print(res)
D:python3.6python.exe C:/Users/Administrator/PycharmProjects/python18期/day2/高阶函数.py
9
1.8.2 递归
有明确的结束条件 python默认可以999层
问题规模每递归一次都应该比上一次的问题规模有所减少
效率低
def calc(n):
print(n)
if int(n/2)>0:
return calc( int(n/2) )
print('->',n)
calc(10)
1.9 函数式编程
是没有变量的
1.10 匿名函数
calc =lambda x:x*3
calc()
第2章 Day4
装饰器:
定义 本质是函数,(装饰其他函数)就是为其他函数添加附加功能
原则:
1,不能修改被装饰的函数的源代码
2,不能修改被装饰的函数的调用方式
门牌号都没有的时候(没有引用的时候) 内存存的值就会被释放回收 这就是垃圾回收
del x 删除的是变量名 不是变量值
函数先定义 再调用
没定义 调用就会报错
2.1 高阶函数
2.1.1 a:把一个函数名当做实参传给另外一个函数(在不修改被装饰函数源代码的情况下为其添加功能)
实例2-1
import time
def bar():
time.sleep(3)
print('in the bar')
def test(func):
start_time=time.time()
func()
stop_time=time.time()
print('the func run time is %s' %(stop_time - start_time))
test(bar)
2.1.2 b:返回值中包含函数名(不修改函数的调用方式)
import time
def bar():
time.sleep(3)
print('in the bar')
def test2(func):
print(func)
return func
# print(test2(bar))
bar=test2(bar)#把bar的内存地址传给bar
bar() #run bar
2.2 嵌套函数
def foo():
print('in the foo')
def bar():
print('in the bar')
bar()
foo()
2.3 高阶函数+嵌套函数=》》装饰器
'''import time
def deco(func):
start_time=time.time()
func()
stop_time=time.time()
print(stop_time-start_time)
def test1():
time.sleep(3)
print('in the test1')
def test2():
time.sleep(3)
print('in the test2')
deco(test1)
deco(test2)
''' #利用高阶函数实现了功能但是 改变了原函数的调用方式
#接下来我们加一层嵌套函数 看能否不改变调用方式能否实现新加功能
import time
def timer(func): # timer(test1) func=test1
def deco():
start_time=time.time()
func() # run test1()
stop_time=time.time()
print('run time is %s'%(stop_time-start_time))
return deco
@timer # test1=timer(test1)
def test1():
time.sleep(3)
print('in the test1')
@timer # test2=timer(test2)
def test2():
time.sleep(3)
print('in the test2')
#print(timer(test1))
# test1=timer(test1)
# test2=timer(test2)
test1()
test2()
# deco(test1)
# deco(test2)
2.4 装饰器高潮版
2.5 列表生成式
>>>L = [x * 2 for x in range(10)]
>>> L
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>> g=(x * 2 for x in range(10))
>>> g
<generator object <genexpr> at 0x02CC5F80>
>>> for i in g:
print(i)
0
2
4
6
8
10
12
14
16
18
>>> a= [ i for i in range(10)]
>>> a = map(lambda x:x+1, a)
>>> a
<map object at 0x02F66AD0>
>>> for i in a:print(i)
1
2
3
4
5
6
7
8
9
10
生成器只会在调用的时候才会生成相应的数据
只记录当前的位置只有一个__next__()方法。next()
[1,2,3,4,5,6,7,8,9]
2.6 斐波那契数列
def fib(max):
n,a,b =0,0,1
while n< max:
yield b
a,b =b,a+b
n=n+1
return '---done--' #异常的时候打印的消息
# fib(10)
# for n in fib(10):
# print(n)
g=fib(10)
while True:
try:
x = next(g)
print('g:',x)
except StopIteration as e:
print('Generator return value:',e)
break
# print(g.__next__())
# print(g.__next__())
# print(g.__next__())
# print(g.__next__())
# print(g.__next__())
# print(g.__next__())
# print(g.__next__())
next 方法到没数据时会报错
如果一个函数定义中包含yield
关键字,那么这个函数就不再是一个普通函数,而是一个generator:
2.7 迭代对象
可以直接用于for循环的对象统称为可迭代对象 Iterable
一类是集合数据类型,如list、tuple、dict、set、str等
一类是generator,包括生成器和带yield的generator function
可以使用isinstance()
判断一个对象是否是Iterable
对象:
>>> from collections import Iterable
>>> isinstance([],Iterable)
True
>>> isinstance({},Iterable)
True
>>> isinstance('abc',Iterable)
True
>>> isinstance((x for x in range(10)),Iterable)
True
>>> isinstance(100,Iterable)
False
2.8 迭代器
而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
*可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
可以使用isinstance()
判断一个对象是否是Iterator
对象:
>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False
>>>
生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
把list、dict、str等Iterable变成Iterator可以使用iter()函数:
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter({}), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True
你可能会问,为什么list、dict、str等数据类型不是Iterator?
这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
小结
凡是可作用于for循环的对象都是Iterable类型;
凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
or甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
Python的for循环本质上就是通过不断调用next()函数实现的,例如:
for x in [1, 2, 3, 4, 5]:
pass
# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
try:
# 获得下一个值:
x = next(it)
except StopIteration:
# 遇到StopIteration就退出循环
break