Python基础笔记3如何深入理解?

2026-06-10 21:347阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计2648个文字,预计阅读时间需要11分钟。

Python基础笔记3如何深入理解?

高级特性+代码不是越多越好,而是越少越好。代码不是越复杂越好,而是越简单越好。代码越少,开发效率越高。

1.切片(Slice)操作符,从一个list或tuple中提取部分元素非常常见。

高级特性

代码不是越多越好,而是越少越好。代码不是越复杂越好,而是越简单越好。代码越少,开发效率越高。

1.切片

切片(Slice)操作符,取一个list或tuple的部分元素非常常见。
列表

L=['Michael','Sarah','Tracy','Bob','Jack']
L[0:3]
L[1:3]
L[-1]
L[-2:]

L=list(range(100)#0-99
L[:10]#前10
L[-10:]#后10
L[10:20]
L[:10:2]#前10,每两个取一个
L[::5]#所有数中每5个取一个

tuple

(0,1,2,3,4,5)[:3]#得到的也是一个tuple(0,1,2)

字符串

'ABCDEFG'[:3]#ABC
'ABCDEFG'[::2]#ACEG

不像R和Perl等专门提供字符串截取函数,Python中用一个切片操作就可完成,灵活使用能减少不少循环。

2.迭代iteration

通过for循环来遍历

d={'a':1,'b':2,'c':3}
forkeyind:#字典默认迭代key
print(key)#无序

#迭代值
forvalueind.values():#括号不可少
print(value)
#迭代键和值
fork,vind.items():

判断一个对象是否可迭代

fromcollectionsimportIterable
isinstance('abc',Iterable)#字符串可迭代
isinstance([1,2,3],Iterable)#list可迭代
isinstance(123,Iterable)#整数不可迭代

实现下标(元素索引)迭代循环

fori,valueinenumerate(['a','b','c']):
print(i,value)

同时对多个变量循环

forx,y,zin[(1,2,3),(2,3,1),(2,1,3)]:
print(x,y,z)

任何可迭代对象都可以作用于for循环,包括我们自定义的数据类型,只要符合迭代条件,就可以使用for循环。

3.列表生成式

list(range(1,11))#1..10

[x*xforxinrange(1,11)]

[x*xforxinrange(1,11)ifx%2==0]

[m+nformin'abc'fornin'xyz']

应用

#列出当前目录所有文件和目录名
importos
[dfordinos.listdir('.')]

#两个变量生成list
d={'x':1,'y':2,'z':3}
[k+'='+vfork,vind.items()]

#所有list字符串小写
L=["aBC","Word"]
[s.lower()forsinLifisinstance(s,str)==True]#列表中只能都为str

4.生成器generator

一边循环一边计算。
创建生成器:

g=(x*xforxinrange(10))#()而非[]
g
next(g)
next(g)
......#一个个打印出来,直到最后一个元素

forning:#可迭代
print(n)

用一个函数来实现generator。普通函数调用直接返回结果,生成器函数调用返回的是一个生成器对象。

#斐波那契数列
deffib(max):
n,a,b=0,0,1
whilen<max:
yieldb#yield关键字
a,b=b,a+b
n=n+1
return'done'

forninfib(6):
print(n)#不会返回return的值

#return的值包含在StopIteration错误的value中:
g=fib(6)
whileTrue:
try:
x=next(g)
print('g:',x)
exceptStopIterationase:
print('Generatorreturnvalue:',e.value)
break

练习:写一个generator,不断输出杨辉三角的下一行

#_*_coding:utf-8_*_
deftriangles():
L=[1]
yieldL
whileTrue:
#两端都是1,中间是上两个相邻数之和
L=[1]+[L[x]+L[x+1]forxinrange(len(L)-1)]+[1]
yieldL

5.迭代器

可迭代对象(Iterable):可直接作用于for循环的对象,一类是集合数据类型(list/tuple/dict/set/str),一类是generator(生成器和带yield的生成器函数)

#判断对象是否为Iterable对象,以下都为True
fromcollectionsimportIterable
isinstance([],Iterable)
isinstance({},Iterable)
isinstance('abc',Iterable)
isinstance((xforxinrange(10)),Iterable)

可以被next()函数调用并不断返回下一个值的对象称为迭代器Iterator。

fromcollectionsimportIterator
isinstance([],Iterator)#False
isinstance({},Iterator)#False
isinstance('abc',Iterator)#False
isinstance((xforxinrange(10)),Iterator)#True

生成器都是迭代器对象,list/dict/str虽然是可迭代对象,但不是迭代器。但它们可用iter()函数变成迭代器。

isinstance(iter([]),Iterator)#True
isinstance(iter('abc'),Iterator)#True

迭代器对象是一个数据流,它是惰性的,只能通过next函数按需计算下一步。

函数式编程

函数式编程是一种抽象程度很高的编程范式,纯函数式编程甚至没有变量(python不是)。其特点是允许把函数本身作为参数传入另一个函数,还允许返回一个函数。

1.高阶函数

变量可以指向函数

x=abs(-10)#赋值
x

f=abs#赋函数
f
f(-10)

传入函数参数

Python基础笔记3如何深入理解?

defadd(x,y,f):
returnf(x)+f(y)

add(-5,6,abs)

map/reduce
map(function,Iterable)

deff(x):
returnx*x

r=map(f,[1,2,3,4])
list(r)

#简写
list([map(str,[1,2,3,4]))

reduce(f,[x1,x2,x3]) = f(f(x1,x2),x3)

fromfunctoolsimportreduce
defadd(x,y):
returnx+y

reduce(add,[1,3,5,7,9])

map和reduce结合使用:

#字符串转化为整数函数
fromfunctoolsimportreduce
digits={'0':0,'1':1,'2':2,'3':3}
defstr2int(s):
deffn(x,y):
returnx*10+y
defchar2num(s):
returndigits[s]
returnreduce(fn,map(char2num,s))

str2int('123')

以上函数还可进一步用lambda函数简化:

fromfunctoolsimportreduce
digits={'0':0,'1':1,'2':2,'3':3}
defchar2num(s):
returndigits[s]
defstr2int(s):
returnreduce(lambdax,y:x*10+y,map(char2num,s))

filter
过滤序列,从一个序列中筛出符合条件的元素

defis_odd(n):
returnn%2==1

list(filter(is_odd,[1,2,3,4,5]))#1,3,5

用filter筛选全体质数(素数):

#先构造一个从3开始的奇数序列
def_odd_iter():
n=1
whileTrue:
n=n+2
yieldn

#然后定义一个筛选函数
def_not_divisible(n):
returnlambdax:x%n>0

#最后定义一个生成器,不断返回下个素数
defprimes():
yield2
it=_odd_iter()#初始序列
whileTrue:
n=next(it)#返回第一个数
yieldn
it=filter(_not_divisible(n),it)#构造新序列

#打印1000内的素数
forninprimes():
ifn<1000:
print(n)
else:
break

筛选回数:

defis_palindrome(n):
returnstr(n)==str(n)[::-1]

output=filter(is_palindrome,range(1,1000))
print('1~1000:',list(output))

sorted
排序算法

sorted([3,5,-23,4,-8])
sorted([3,5,-23,4,-8],key=abs)#按绝对值排序

sorted(['bob','about','Zoo','Credit'])#默认ASCII码['Credit','Zoo','about','bob']
sorted(['bob','about','Zoo','Credit'],key=str.lower)#['about','bob','Credit','Zoo']

sorted(['bob','about','Zoo','Credit'],key=str.lower,reverse=True)#反向['Zoo','Credit','bob','about']

用sorted()排序的关键在于实现一个映射函数。

2.返回函数

把函数作为结果值返回

deflazy_sum(*args):
defsum():
ax=0
forninargs:
ax=ax+n
returnax
returnsum

f=lazy_sum(1,2,5,7)
f#返回的是函数
f()#返回结果

#每次调用都会返回一个新的函数,即使参数相同也不一样
f1=lazy_sum(1,2,5,7)
f2=lazy_sum(1,2,5,7)
f1==f2#False,f1()和f2()的调用结果互不影响。

闭包
上例中,在函数lazy_sum中又定义了函数sum,并且内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种程序结构称为“闭包(Closure)”。

返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。

defcount():
fs=[]
foriinrange(1,4):
deff():
returni*i
fs.append(f)
returnfs

f1,f2,f3=count()
#f1()f2()f3()都是9,因为返回的函数引用了变量i,但它并非立刻执行,等到3个函数都返回时,它们所引用的变量i已经变成了3。

如果一定要引用循环变量,就再创建一个函数,用该函数的参数绑定循环变量当前的值:

defcount():
deff(j):
defg():
returnj*j
returng
fs=[]
foriinrange(1,4):
fs.append(f(i))#f(i)立刻被执行,因此i的当前值被传入f()
returnfs

3.匿名函数

关键字lambda表示匿名函数

list(map(lambdax:x*x,[1,2,3,4,5,6,7,8,9]))

#赋值变量
f=lambdax:x*x
f
f(5)

#作为返回值
defbuild(x,y):
returnlambda:x*x+y*y

4.装饰器

函数也是对象,可赋值给变量,并调用。

defnow():
print('2019-1-1')
f=now
f()

函数对象的__name__属性可得到函数的名字:

now.__name__#now
f.__name__#now

想增加函数的功能,又不想修改函数的定义,这种在代码运行期间动态增加功能的方式称为“装饰器(Decorator)”。

本质上装饰器就是一个返回函数的高阶函数。

#定义一个能打印日志的装饰器:函数作为参数并返回函数
deflog(func):
defwrapper(*args,**kw):
print('call%s():'%func.__name__)
returnfunc(*args,**kw)
returnwrapper

@log#把装饰器置于函数的定义处,相当于now=log(now)
defnow():
print('2019-1-1')

now()#调用函数,会打印日志

如果要自定义log文本,需要编写一个返回装饰器的高阶函数:

deflog(text):
defdecorator(func):
defwrapper(*args,**kw):
print('%s%s():'%(text,func.__name__))
returnfunc(*args,**kw)
returnwrapper
returndecorator

#三层嵌套的装饰器调用:
@log('execute')#相当于now=log('execute')(now)
defnow():
print('2015-3-25')

完整的装饰器写法:

importfunctools

deflog(func):
@functools.wraps(func)
defwrapper(*args,**kw):
print('call%s():'%func.__name__)
returnfunc(*args,**kw)
returnwrapper

#带参数的装饰器:
importfunctools

deflog(text):
defdecorator(func):
@functools.wraps(func)
defwrapper(*args,**kw):
print('%s%s():'%(text,func.__name__))
returnfunc(*args,**kw)
returnwrapper
returndecorator

面向对象的装饰模式需要通过继承和组合来实现,Python的decorator可以用函数实现,也可以用类实现。

5.偏函数

functools模块提供的偏函数:当函数的参数个数太多化时,可创建一个新的函数,将某些参数给固定住(即设置默认值),从而在调用时更简单。

#自定义函数
defint2(x,base=2):#默认转化二进制
returnint(x,base)

#使用偏函数
importfunctools
int2=functools.partial(int,base=2)#实际上固定了int()函数的关键字参数base
int2('10010')
int2('10010',base=10)

max2=functools.partial(max,10)#10会作为*args的一部分自动加到左边
max2(5,6,7)#相当于max2(10,5,6,7)


作者:Bioinfarmer

若要及时了解动态信息,请关注同名微信公众号:Bioinfarmer。

本文共计2648个文字,预计阅读时间需要11分钟。

Python基础笔记3如何深入理解?

高级特性+代码不是越多越好,而是越少越好。代码不是越复杂越好,而是越简单越好。代码越少,开发效率越高。

1.切片(Slice)操作符,从一个list或tuple中提取部分元素非常常见。

高级特性

代码不是越多越好,而是越少越好。代码不是越复杂越好,而是越简单越好。代码越少,开发效率越高。

1.切片

切片(Slice)操作符,取一个list或tuple的部分元素非常常见。
列表

L=['Michael','Sarah','Tracy','Bob','Jack']
L[0:3]
L[1:3]
L[-1]
L[-2:]

L=list(range(100)#0-99
L[:10]#前10
L[-10:]#后10
L[10:20]
L[:10:2]#前10,每两个取一个
L[::5]#所有数中每5个取一个

tuple

(0,1,2,3,4,5)[:3]#得到的也是一个tuple(0,1,2)

字符串

'ABCDEFG'[:3]#ABC
'ABCDEFG'[::2]#ACEG

不像R和Perl等专门提供字符串截取函数,Python中用一个切片操作就可完成,灵活使用能减少不少循环。

2.迭代iteration

通过for循环来遍历

d={'a':1,'b':2,'c':3}
forkeyind:#字典默认迭代key
print(key)#无序

#迭代值
forvalueind.values():#括号不可少
print(value)
#迭代键和值
fork,vind.items():

判断一个对象是否可迭代

fromcollectionsimportIterable
isinstance('abc',Iterable)#字符串可迭代
isinstance([1,2,3],Iterable)#list可迭代
isinstance(123,Iterable)#整数不可迭代

实现下标(元素索引)迭代循环

fori,valueinenumerate(['a','b','c']):
print(i,value)

同时对多个变量循环

forx,y,zin[(1,2,3),(2,3,1),(2,1,3)]:
print(x,y,z)

任何可迭代对象都可以作用于for循环,包括我们自定义的数据类型,只要符合迭代条件,就可以使用for循环。

3.列表生成式

list(range(1,11))#1..10

[x*xforxinrange(1,11)]

[x*xforxinrange(1,11)ifx%2==0]

[m+nformin'abc'fornin'xyz']

应用

#列出当前目录所有文件和目录名
importos
[dfordinos.listdir('.')]

#两个变量生成list
d={'x':1,'y':2,'z':3}
[k+'='+vfork,vind.items()]

#所有list字符串小写
L=["aBC","Word"]
[s.lower()forsinLifisinstance(s,str)==True]#列表中只能都为str

4.生成器generator

一边循环一边计算。
创建生成器:

g=(x*xforxinrange(10))#()而非[]
g
next(g)
next(g)
......#一个个打印出来,直到最后一个元素

forning:#可迭代
print(n)

用一个函数来实现generator。普通函数调用直接返回结果,生成器函数调用返回的是一个生成器对象。

#斐波那契数列
deffib(max):
n,a,b=0,0,1
whilen<max:
yieldb#yield关键字
a,b=b,a+b
n=n+1
return'done'

forninfib(6):
print(n)#不会返回return的值

#return的值包含在StopIteration错误的value中:
g=fib(6)
whileTrue:
try:
x=next(g)
print('g:',x)
exceptStopIterationase:
print('Generatorreturnvalue:',e.value)
break

练习:写一个generator,不断输出杨辉三角的下一行

#_*_coding:utf-8_*_
deftriangles():
L=[1]
yieldL
whileTrue:
#两端都是1,中间是上两个相邻数之和
L=[1]+[L[x]+L[x+1]forxinrange(len(L)-1)]+[1]
yieldL

5.迭代器

可迭代对象(Iterable):可直接作用于for循环的对象,一类是集合数据类型(list/tuple/dict/set/str),一类是generator(生成器和带yield的生成器函数)

#判断对象是否为Iterable对象,以下都为True
fromcollectionsimportIterable
isinstance([],Iterable)
isinstance({},Iterable)
isinstance('abc',Iterable)
isinstance((xforxinrange(10)),Iterable)

可以被next()函数调用并不断返回下一个值的对象称为迭代器Iterator。

fromcollectionsimportIterator
isinstance([],Iterator)#False
isinstance({},Iterator)#False
isinstance('abc',Iterator)#False
isinstance((xforxinrange(10)),Iterator)#True

生成器都是迭代器对象,list/dict/str虽然是可迭代对象,但不是迭代器。但它们可用iter()函数变成迭代器。

isinstance(iter([]),Iterator)#True
isinstance(iter('abc'),Iterator)#True

迭代器对象是一个数据流,它是惰性的,只能通过next函数按需计算下一步。

函数式编程

函数式编程是一种抽象程度很高的编程范式,纯函数式编程甚至没有变量(python不是)。其特点是允许把函数本身作为参数传入另一个函数,还允许返回一个函数。

1.高阶函数

变量可以指向函数

x=abs(-10)#赋值
x

f=abs#赋函数
f
f(-10)

传入函数参数

Python基础笔记3如何深入理解?

defadd(x,y,f):
returnf(x)+f(y)

add(-5,6,abs)

map/reduce
map(function,Iterable)

deff(x):
returnx*x

r=map(f,[1,2,3,4])
list(r)

#简写
list([map(str,[1,2,3,4]))

reduce(f,[x1,x2,x3]) = f(f(x1,x2),x3)

fromfunctoolsimportreduce
defadd(x,y):
returnx+y

reduce(add,[1,3,5,7,9])

map和reduce结合使用:

#字符串转化为整数函数
fromfunctoolsimportreduce
digits={'0':0,'1':1,'2':2,'3':3}
defstr2int(s):
deffn(x,y):
returnx*10+y
defchar2num(s):
returndigits[s]
returnreduce(fn,map(char2num,s))

str2int('123')

以上函数还可进一步用lambda函数简化:

fromfunctoolsimportreduce
digits={'0':0,'1':1,'2':2,'3':3}
defchar2num(s):
returndigits[s]
defstr2int(s):
returnreduce(lambdax,y:x*10+y,map(char2num,s))

filter
过滤序列,从一个序列中筛出符合条件的元素

defis_odd(n):
returnn%2==1

list(filter(is_odd,[1,2,3,4,5]))#1,3,5

用filter筛选全体质数(素数):

#先构造一个从3开始的奇数序列
def_odd_iter():
n=1
whileTrue:
n=n+2
yieldn

#然后定义一个筛选函数
def_not_divisible(n):
returnlambdax:x%n>0

#最后定义一个生成器,不断返回下个素数
defprimes():
yield2
it=_odd_iter()#初始序列
whileTrue:
n=next(it)#返回第一个数
yieldn
it=filter(_not_divisible(n),it)#构造新序列

#打印1000内的素数
forninprimes():
ifn<1000:
print(n)
else:
break

筛选回数:

defis_palindrome(n):
returnstr(n)==str(n)[::-1]

output=filter(is_palindrome,range(1,1000))
print('1~1000:',list(output))

sorted
排序算法

sorted([3,5,-23,4,-8])
sorted([3,5,-23,4,-8],key=abs)#按绝对值排序

sorted(['bob','about','Zoo','Credit'])#默认ASCII码['Credit','Zoo','about','bob']
sorted(['bob','about','Zoo','Credit'],key=str.lower)#['about','bob','Credit','Zoo']

sorted(['bob','about','Zoo','Credit'],key=str.lower,reverse=True)#反向['Zoo','Credit','bob','about']

用sorted()排序的关键在于实现一个映射函数。

2.返回函数

把函数作为结果值返回

deflazy_sum(*args):
defsum():
ax=0
forninargs:
ax=ax+n
returnax
returnsum

f=lazy_sum(1,2,5,7)
f#返回的是函数
f()#返回结果

#每次调用都会返回一个新的函数,即使参数相同也不一样
f1=lazy_sum(1,2,5,7)
f2=lazy_sum(1,2,5,7)
f1==f2#False,f1()和f2()的调用结果互不影响。

闭包
上例中,在函数lazy_sum中又定义了函数sum,并且内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种程序结构称为“闭包(Closure)”。

返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。

defcount():
fs=[]
foriinrange(1,4):
deff():
returni*i
fs.append(f)
returnfs

f1,f2,f3=count()
#f1()f2()f3()都是9,因为返回的函数引用了变量i,但它并非立刻执行,等到3个函数都返回时,它们所引用的变量i已经变成了3。

如果一定要引用循环变量,就再创建一个函数,用该函数的参数绑定循环变量当前的值:

defcount():
deff(j):
defg():
returnj*j
returng
fs=[]
foriinrange(1,4):
fs.append(f(i))#f(i)立刻被执行,因此i的当前值被传入f()
returnfs

3.匿名函数

关键字lambda表示匿名函数

list(map(lambdax:x*x,[1,2,3,4,5,6,7,8,9]))

#赋值变量
f=lambdax:x*x
f
f(5)

#作为返回值
defbuild(x,y):
returnlambda:x*x+y*y

4.装饰器

函数也是对象,可赋值给变量,并调用。

defnow():
print('2019-1-1')
f=now
f()

函数对象的__name__属性可得到函数的名字:

now.__name__#now
f.__name__#now

想增加函数的功能,又不想修改函数的定义,这种在代码运行期间动态增加功能的方式称为“装饰器(Decorator)”。

本质上装饰器就是一个返回函数的高阶函数。

#定义一个能打印日志的装饰器:函数作为参数并返回函数
deflog(func):
defwrapper(*args,**kw):
print('call%s():'%func.__name__)
returnfunc(*args,**kw)
returnwrapper

@log#把装饰器置于函数的定义处,相当于now=log(now)
defnow():
print('2019-1-1')

now()#调用函数,会打印日志

如果要自定义log文本,需要编写一个返回装饰器的高阶函数:

deflog(text):
defdecorator(func):
defwrapper(*args,**kw):
print('%s%s():'%(text,func.__name__))
returnfunc(*args,**kw)
returnwrapper
returndecorator

#三层嵌套的装饰器调用:
@log('execute')#相当于now=log('execute')(now)
defnow():
print('2015-3-25')

完整的装饰器写法:

importfunctools

deflog(func):
@functools.wraps(func)
defwrapper(*args,**kw):
print('call%s():'%func.__name__)
returnfunc(*args,**kw)
returnwrapper

#带参数的装饰器:
importfunctools

deflog(text):
defdecorator(func):
@functools.wraps(func)
defwrapper(*args,**kw):
print('%s%s():'%(text,func.__name__))
returnfunc(*args,**kw)
returnwrapper
returndecorator

面向对象的装饰模式需要通过继承和组合来实现,Python的decorator可以用函数实现,也可以用类实现。

5.偏函数

functools模块提供的偏函数:当函数的参数个数太多化时,可创建一个新的函数,将某些参数给固定住(即设置默认值),从而在调用时更简单。

#自定义函数
defint2(x,base=2):#默认转化二进制
returnint(x,base)

#使用偏函数
importfunctools
int2=functools.partial(int,base=2)#实际上固定了int()函数的关键字参数base
int2('10010')
int2('10010',base=10)

max2=functools.partial(max,10)#10会作为*args的一部分自动加到左边
max2(5,6,7)#相当于max2(10,5,6,7)


作者:Bioinfarmer

若要及时了解动态信息,请关注同名微信公众号:Bioinfarmer。