1.1Python函数
面向对象
面向过程
1.可读性差
2.重用性差
函数式编程
1.1.1自定义函数
看一个函数的例子:db文件内容为xuliangwei|123
def login(username,password):
'''
用于用户登陆
:param username: 用户输入用户名
:param password: 用户输入密码
:return: true,登陆成功 false,登陆失败
'''
file_name = open("db",'r')
for line in file_name:
line_list = line.split("|")
if line_list[0] == username and line_list[1] == password:
return True
return False
解释:
1.def:表示函数的关键字
2.函数名:函数的名称,日后根据函数名调用函数
3.函数体:函数中进行一系列的逻辑计算,如:发送邮件
4.返回值:当函数执行完毕后,可以给调用者返回数据。
5.参数:为函数体提供数据(Python函数传递参数是传递一个引用。而不是重新赋值.)
1.普通参数(严格按照顺序,将实际参数赋值给形式参数)
2.默认参数(必须放置在参数列表的最后)
3.指定参数(将实际参数复制给指定的形式参数)
4.动态参数:
*args 默认将位置参数,全部放置在元组中
**kwargs 默认将关键字参数(字典),全部放置在字典中
5.万能参数
1.1.2 局部变量
1.在程序中定义的变量成为局部变量。
2.局部变量作用域是定义该变量的子程序。
3.当全局变量与局部变量冲突时,在定义局部变量的子程序内,局部变量起作用,在其他地方全局变量起作用。
#!/usr/bin/env python
# Author:xuliangwei
name = "XuLiangWei"
def change_name(name):
print("before change:", name)
name = "我是有Tesla的男人" #定义局部变量
print("after chage:", name)
change_name(name)
print("在外面看name改了么?",name)
执行结果:
before change: XuLiangWei
after chage: 我是有Tesla的男人
在外面看name改了么? XuLiangWei
1.1.3 全局变量
1.在程序一开始定义的变量称为全局变量。
1.全局变量定义变量,必须都是大写(潜规则)。比如:NAME="xuliangwei"
2.函数优先读当前环境变量,如果没有则会读全局变量,全局变量在所有的作用域都可读。
3.修改全局变量需要先global name,表示name是全局变量(重新赋值)。
4.特殊:列表,字典,元组嵌套列表,可修改,不可重新赋值。
1.1.4内置函数
# all #非0即真
# any #
# bool #0和,空字典空列表都是假
# callable #表示是否可执行,或是否可调用
# dir #快速查看对象提供了哪些功能
# divmod #文章分页使用
# isinstance #用于判断,对象是否是某个类的实例
# globals #列出全局变量
# locals #列出所有局部变量
# hash #
#enumerate
#float
#format
#frozenset
# max #最大
# min #最小
# sum #求和
# int #整数
# hex #十进制转换十六进制
# bin #十进制转二进制
# oct #十进制转十进制
# filter #内部循环,参数比较
# map #将函数返回值添加到结果中
# compile #将字符串,编译成Python代码
# eval #执行表达式,并且获取结果
# exec #执行Python代码,接收:代码或者字符串
#id #查看内存地址
#input #等待用户输入
# isinstance #查看某个对象是不是某个类的实例
# issubclass #
# len #查看长度
# list #
# memoryview #查看内存地址相关类
# next #
# iter #创建迭代器
# object #所有类的复类
# open #
# ord #
# pow #
# print #
# property #
# range #
# repr #
# reversed #反转
# round #
# set #集合
# slice #
# sorted #
# staticmethod #
# str #字符串
# super #面向对象
# tuple #元祖
# type #类型
# vars #当前模块有哪些变量
# zip #压缩
# __import__ #导入模块
# delattr()
# getattr()
# setattr()
1.1.5函数返回值
想要获取函数的执行结果,就可以用return语句把结果返回。
1.函数在执行过程中只要遇到return语句,就会停止执行并返回结果,也可以理解为return语句代表着函数的结果。
2.如果未在函数中指定return,那这个函数的返回值为None。
1.1.6递归函数
在函数内部,可以调用其他函数。如果一个函数在内部调用自身,这个函数就是递归函数。
#!/usr/bin/env python
# Author:xuliangwei
def calc(n):
print(n)
if int(n/2) ==0:
return n
return calc (int(n/2))
calc(10)
递归特征:
1.必须有一个明确的结束条件。
2.每次进入更深一层递归时,问题规模相比上次递归都应有所减少。
3.递归效率不高,递归层次过多会导致栈益处(在计算机中,函数调用是通过栈(stack)这种数据结果实现的,每当进入一个函数调用,栈就会加一层栈帧,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈益处。)
1.1.7匿名函数
匿名函数就是不需要显示的指定函数
#!/usr/bin/env python
# Author:xuliangwei
def calc(n):
return n**n
print(calc(10))
#换成匿名函数
calc = lambda n:n**n
print(calc(10))
#从上看来好像并无卵用,如果是这么用确实没毛改进,不过匿名函数主要是和其他函数搭配使用,如下:
res = map(lambda x:x**2,[1,5,7])
for i in res:
print(i)
#结果:
1
25
49
1.1.8高阶函数
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
#!/usr/bin/env python
# Author:xuliangwei
def add (x,y,f):
return f(x) + f(y)
res = add(3,-6,abs)
print(res)
1.1.9函数式编程
函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元。
而函数式编程,虽然也可以归结到面向过程的程序设计,但其思想更接近数学计算。
我们首先要搞明白计算机(Computer)和计算(Compute)的概念。
在计算机的层次上,CPU执行的是加减乘除的指令代码,以及各种条件判断和跳转指令,所以,汇编语言是最贴近计算机的语言。
而计算则指数学意义上的计算,越是抽象的计算,离计算机硬件越远。
函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。
函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!
Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。
(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);
#这就是函数式编程(就会这么多)
1.2装饰器
1.自动执行xx函数并且将其下面的函数名f1当作参数传递
2.将xx函数的返回值,重新赋值
定义:本质是函数,(装饰其他函数)就是为其他函数添加附件功能。
1.不能修改被装饰的函数的源代码
2.不能修改被装饰的函数的调用方式
实现装饰器知识储备:
1.函数即"变量"
2.高阶函数
3.嵌套函数
高级函数+嵌套函数=>装饰器
无参数和无嵌套函数装饰器
def foo(func):
print
'decorator foo'
return func
@foo
def bar():
print
'bar'
bar()
# 没有嵌套函数,增加了打印"decorator foo"功能,并且没有改变函数的调用方式。
无参数装饰器(没有参数)
#!/usr/bin/env python
# Author:xuliangwei
import time
def decorator(func):
def wrapper(*args, **kwargs):
start = time.time()
func(*args, **kwargs)
stop = time.time()
print ('run time is %s ' % (stop - start))
print ("timeout")
return wrapper
@decorator # 装饰器
def test(list_test):
for i in list_test:
time.sleep(0.1)
print ('-' * 20, i)
# decorator(test)(range(10))
test(range(10))
# 可以看出装饰器decorator并没有参数
有参数装饰器(没有参数)
import time
def timer(timeout=0):
def decorator(func):
def wrapper(*args, **kwargs): # 会给装饰器传递参数,因为无法确定装饰器有多少参数,所以使用这个。
start = time.time()
func(*args, **kwargs)
stop = time.time()
print ('run time is %s ' % (stop - start))
print (timeout)
return wrapper
return decorator
@timer(2) # 装饰器的参数为2
def test(list_test):
for i in list_test:
time.sleep(0.1)
print ('-' * 20, i)
# timer(timeout=10)(test)(range(10))
test(range(10))
# 装饰器timer的参数为2,@timer(2)相当于test=timer(2)(test)
1.3迭代器
我们已经知道,可以直接作用于for循环的数据类型有以下几种:
一类是集合数据类型,如list、tuple、dict、set、str等;
一类是generator,包括生成器和带yield的generator function。
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。
可以使用isinstance()判断一个对象是否是Iterable对象:
xuliangwei:~ xuliangwei$ Python3
>>>
>>> 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
而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
*可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
可以使用isinstance()判断一个对象是否是Iterator对象:
xuliangwei:~ xuliangwei$ Python3
>>>
>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False
你可能会问,为什么list、dict、str等数据类型不是Iterator?
这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
小结
凡是可作用于for循环的对象都是Iterable类型;
凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
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
1.4生成器
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:
l = [x * x for x in range(10)]
print(l)
g = (x * x for x in range(10))
print(g)
#执行结果:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
<generator object <genexpr> at 0x101380938>
1.只有在调用时才会生成相应的数据。
只记录当前位置。
只有一个next()方法。next()