Python基础学习(二)
一、函数的基本用法
1、概念:
函数是对程序逻辑进行结构化或是过程化的一种编程方法,其是组织好的,可重复使用的,用来实现单一,或者相同功能的代码段。
函数提高了应用点的模块性和代码的重复利用率
本质:函数是对功能的封装
形式参数:简称形参,本质是一个没有值的变量 实际参数:简称实参,本质是常量,变量或者表达式 传参:实参给形参赋值的过程
而实参的类型取决于形参的需要
2、函数定义:
def 函数名(参数1,参数2,参数3.。。。):
函数体
return 返回值
b、参数1,参数2,参数3.....形式参数,不同的参数之间使用逗号隔开,参数的数量没有限制,依据具体的需求决定参数的数量
c、函数体:被封装的功能
d、return:结束函数,将返回值返回给调用者,也可单独使用
e、返回值可为常量、变量、表达式
3、返回值
返回值:表示一个函数执行完毕之后得到的结果
注:对于return语句不带参数,则返回一个none
4、调用
函数的调用:实质就是函数入栈出栈的过程
即:函数的入栈:函数被调用;函数的出栈:函数被调用完毕
注:在函数调用的过程要注意避免出现死循环
5、变量的作用域
变量的作用域:指变量可以被访问的范围
作用域的划分:
l:(local)局部作用域
e:(enclosing)函数作用域(闭包)
g:(global)全局作用域
b:(built-in)内置作用域
变量的查找规则(变量重名):
python中变量的作用域由大到小,依次为内建(built_in b) >全局(glbal g)> 函数的闭包外(enclosing e)> 局部(local l)
注:在变量重名情况下在函数内部访问变量时使用就近原则。
如果将全局变量的名字声明在一个函数体内的时候,全局变量的名字能被局部变量给覆盖掉,此时我们就需要使用global或者nonlocal来声明变量了。
#1.变量不重名
num1 = 10 #全局作用域
def outer():
num2 = 20 #函数作用域
def inner():
num3 = 30 #局部作用域
print(num1,num2,num3)
return inner
f = outer()
f()
# global:全局的
# 全局变量
num1 = 4
def func1():
# 声明num1是全局变量的num1
global num1
print(num1) #4
num1 = 20
func1()
a = 10
def test():
global a
a = a + 1
print(a) #unboundlocalerror: local variable 'a' referenced before assignment
test()
# nonlocal:不是局部的
# nonlocal;前提条件:必须使用在闭包中
x = 0 # 全局作用域
def outer():
x = 1 # 函数作用域
def inner():
# 将一个局部作用域的变量声明为不是局部的,局部----》函数
nonlocal x
x = 2 #局部作用域
print("inner:",x)
#在外部函数中调用内部函数
nner()
print("outer:",x)
outer()
print("global:",x)
6、参数
1、参数的传递:
参数的传递有值传递和引用传递
值传递:传递不可变类型的数据,例:num、string、tuple等;在值传递时,形参的改变并不会影响实参
引用传递:传递可变类型的数据,例:list、dict、set等;形参的改变会影响实参的使用
在函数中参数传递的是对象的引用
#引用传递:传递列表或者字典时,如果改变引用的值,就修改了原始的对象
def check(l):
print(l)
print(id(l))
l.append([1, 23, 2, 3, 4])
return l
l = [1, 2, 3, 4]
print(check(l))
print(id(l))
'''
[1, 2, 3, 4]
2902500909320
[1, 2, 3, 4, [1, 23, 2, 3, 4]]
2902500909320
'''
#值传递:当传递不可变对象时,如果改变引用变量的值,只是创建了不同的对象,原始对象并没有改变。
def check(s):
print(s)
print(id(s))
s = "i am test"
print(id(s))
return s
s = "this is a test"
print(check(s))
print(s)
'''
this is a test
2418424029424
2418424029488
i am test
this is a test
2、参数的类型:
a、必须参数:必备参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
def printme( str ):
"打印任何传入的字符串"
print str
return
#调用printme函数
printme()
b、关键字参数:允许实参的顺序和形参的顺序不一致,因为python解释器会根据关键字参数的名称自动的匹配
def show2(name,age):
print("name:%s age:%d" % (name,age))
show2(name="jack",age=47)
# 注:关键字参数使用在实参列表中,不要求顺序保持一致
show2(age=36,name="fadj")
# 注:在实参列表中,可以不全部设置为关键字参数
show2("zhangsan",age=15)
# 注:关键字参数只能出现在实参列表的后面
def show3(a,b,c):
print(a,b,c)
show3(1,4,4)
show3(a=3,c=5,b=5)
show3(45,b=9,c=18)
#show3(a=45,9,18) #syntaxerror: positional argument follows keyword argument
c、默认参数:调用函数的时候,如果没有传递参数,则使用默认值【default】
#注意1:默认参数体现在形参列表中
def func3(name="abc",age=18):
print("name:%s age:%d" % (name, age))
#注意2:使用了默认参数,则可以选择不传参,使用的默认值,如果传参,则相当于给形参重新赋值
func3()
func3("jack",19)
#注意3:关键字参数和默认参数可以结合使用
func3(name="jack",age=19)
func3("jack",age=19)
#注意4:形参列表可以不全部设置为默认参数,只要吃部分设置,则默认参数出现在形参列表的后面
#报错:syntaxerror: non-default argument follows default argument
# def show4(name="abc",age):
# print("name:%s age:%d" % (name, age))
# show4("bob",18)
print("hello")
d、不定长参数:可以处理比声明时更多的参数
#a.*,一般写法为*args
def text1(*num):
print(num)
for n in num:
print(n)
# *不定长参数被当做元组处理,num形参名其实就是元组名
text1(10)
text1(10,4,54,65,65,7)
# 可以传一个元组,但是,元组被当做一个整体全部传参
text1((54,4,64))
# 一般情况下,将不定长参数设置在形参列表的最后
def text2(*num3,num1,num2):
print(num1,num2,num3)
# 如果不定长参数出现在形参列表的前面或者中间,则可以借助于关键字参数传参
#text2(12,43,43)
text2(12,34,num1=35,num2=59)
# 在形参列表,不定长参数最好只出现一个
#错误演示
# def text3(*num3,num2,*num1):
# print(num1,num2,num3)
# text3(43,53,num2=10,5,5,4)
#b.**,一般写法为**kwargs
def text4(**num3):
print(num3)
#注意1:**,被当做字典处理,传参的时候,需要以key=value的方式进行传参
text4(x=26,y=17)
#注意2:在形参列表中使用**,保证出现在后面
"""
使用场景:单例设计模式
def text(*args,**kwargs):
总结:
a.必需参数使用最多,其次是不定长参数
b.关键字参数和默认参数最多使用在系统函数中
"""
7、匿名函数
lambda表达式:python中的匿名函数主要用来处理一些简单逻辑表达式的封装,使用lambda关键字
优点:不占用内存,提高代码的运行速度
一般格式为:
var = lambda args:表达式
例如:
f = lambda x,y:x+y #该函数的调用结果为 冒号后的表达式所表达的结果 print(f(1,2))
二、函数进阶
1、概念【特殊用法】:
1、变量可以指向函数
x = abs(-35) print(x) # 35 # 一个普通的变量可以指向一个函数,该变量就可以被当做函数调用 f = abs print(f) print(f(-100)) def check(): print("check") check() f1 = check f1()
2、函数也可以作为变量名
# 本质:函数名就是一个指向函数的变量 print(abs(-28)) # abs = "hello" # print(abs(-7))
3、函数作为参数使用
# 调用形参中的函数,必须和原函数保持一致【注意是否需要传递参数】 def test(a,b,fun): return fun(a) + fun(b) #abs(43) + abs(-27) print(test(43,-27,abs)) #fun = abs def test1(s1,s2,func): return func(s1) + func(s2) print(test1("hello","gajghj",len))
2、闭包:
在函数内部定义了另一个函数,即存在外部函数和内部函数
闭包【closure】:在外部函数中定义一个内部函数,并且外部函数的返回值是内部函数的引用。
# 普通函数 def show(): print("1111") return num1 # 闭包 def outter(): def inner(): print("inner") return inner f = outter() #f = inner f() # 在闭包设置参数,a和b两个变量被称为*变量【临时变量】 # 闭包的优点:在外部函数中定义的变量,在内部函数可以直接访问 def outer1(a): b = 10 def inner1(): print(a + b) return inner1 f1 = outer1(23) #f1 = inner1 f1() # 内部函数设置参数 def outer2(a): b = 10 def inner2(c): print(a + b + c) return inner2 f2 = outer2(23) f2(12)
3、装饰器:
装饰器【decorator】:使其他函数在不需要做任何代码的变动下,为函数添加功能,装饰器的返回值也是一个函数。
本质:装饰器的本质就是一个闭包,其作用是将一个函数作为参数,返回另一个函数
装饰器函数运行在函数定义的时候
装饰器需要返回一个可执行的对象
装饰器返回的可执行对象要兼容函数f的参数
import time #1.简单的装饰器 def test(): print("hello") # func就是需要被装饰的函数 def outer(func): def inner(): # 增加新功能 print("new~~~~") # 调用原函数 func() return inner f1 = outer(test) f1() # 练习:书写装饰器,计算test函数执行的时间 def outer(func): def inner(): t1 = time.time() func() t2 = time.time() print(t2 - t1) return inner f1 = outer(test) f1() #2.带有参数的装饰器 def getage(age): print(age) # getage(10) # getage(-36) # 注意:被装饰的函数有参数,inner不一定需要设置参数,只有当需要在inner内部对参数进行操作的时候,则需要同步 def wrapper1(func): def inner(a): #数据的校验 if a < 0: a = -a func(a) return inner f = wrapper1(getage) f(10) f(-36) # 使用装饰器语法糖 # 注意:使用@,必须保证装饰器存在的情况下,才能给函数增加功能 def wrapper2(func): def inner(a): # 数据的校验 if a < 0: a = -a func(a) return inner @wrapper2 def getage1(age): print(age) getage1(-19) # 参数为不定长参数的装饰器 # 使用场景:一个装饰器可以同时作用于多个不同函数的情况 def wrapper3(func): def inner(*args,**kwargs): # 新增的功能 print("abc") #调用原函数 func(*args,**kwargs) return inner @wrapper3 def test(a,b): print(a,b) test(10,20) @wrapper3 def test1(): print("gsjrg") test1() # 多个装饰器作用于同一个函数 def wrapper11(func): def inner(*args,**kwargs): # 新增的功能 print("装饰器~~~~11") # 调用原函数 func(*args,**kwargs) return inner def wrapper22(func): def inner(*args,**kwargs): # 新增的功能 print("装饰器~~~~22") # 调用原函数 func(*args,**kwargs) return inner @wrapper11 # func:check @wrapper22 # func:被wrapper11装饰之后的函数 def check(): print("check") check() #总结:多个装饰器作用于同一个函数的时候,从上往下依次执行,但是,原函数只被调用一次
4、偏函数
通过设定默认参数,可以降低调用的难度,偏函数也可以起到这样的作用
概念:对函数的参数做一些控制的函数
注意:偏函数一般不需要自己定义,直接使用【functools模块其中提供了偏函数的使用】
import functools print(int("23534")) # print(int("abc345")) #valueerror: invalid literal for int() with base 10: 'abc345' # 在int中有一个默认参数base,用来指明当前数据的进制 print(int("110")) print(int("110",base=10)) print(int("1010",base=2)) print(int("1010",2)) # 自定义一个函数,设置一个默认参数base,默认值设置为2 def int2(x,base=2): return int(x,base) print(int2("1010")) print(int2("1010",10)) # 系统的functools模块中提供了偏函数的实现 # 参数:已经存在的函数名 默认参数 int3 = functools.partial(int,base=2) print(int3("1110")) print(int3("1110",base=10)) # 思想:根据一个已经存在的函数,通过修改该函数参数的默认值,生成一个新的函数,被称为偏函数
三、高阶函数
1、filter():过滤
""" filter(function,iterable) 通过一定的条件过滤可迭代对象中的元素 工作原理:把传入的函数依次作用于可迭代对象的每一个元素,根据返回的布尔值【true或者false】决定是否保留元素 如果返回true,则表示需要保留该元素;如果返回false,则表示需要过滤掉该元素 """ # 将列表中的偶数筛选出来 list1 = [1,2,3,4,5,6,7,8] # 自定义【追加】 newlist1 = [] for num in list1: if num % 2 == 0: newlist1.append(num) print(newlist1) # 自定义【删除】 newlist2 = list1.copy() for num in newlist2: if num % 2 == 1: newlist2.remove(num) print(newlist2) #方式三:列表生成式 newlist3 = [num for num in list1 if num % 2 == 0] print(newlist3) # filter def func(num): # 保留偶数元素 if num % 2 == 0: return true # 过滤奇数元素 return false newlist4 = list(filter(func,list1)) print(newlist4) # 将爱好为"无"的数据剔除掉 data = [['姓名', '爱好', '年龄'],['tom', '无', 10],['jack', '唱歌', 28]] def func2(s): if s == "无": return false return true for line in data: result = list(filter(func2,line)) print(result)
2、map():映射
""" map(function,iterable) 会根据的函数对指定的序列做出映射 function:函数 iterable:可迭代对象,序列 工作原理:函数会以序列中的每一个元素作为参数,返回包含函数的功能的新列表 功能:将传入的函数依次作用于序列中的每一个元素,并把结果作为新的iterable返回 """ # 计算列表中各个元素的平方 list1 = [1,2,3,4,5] # 自定义 newlist1 = [] for num in list1: newlist1.append(num ** 2) print(newlist1) # 列表生成式 newlist2 = [num ** 2 for num in list1] print(newlist2) # 生成器 newlist3 = list((num ** 2 for num in list1)) print(newlist3) # map[def定义的函数] def func(x): return x ** 2 result = map(func,list1) print(result) print(type(result)) newlist4 = list(result) print(newlist4) """ 传给map的函数的要求: a.参数只能有一个【默认将可迭代对象的一个元素传递给该函数】 b.该函数必须有返回值,否则得到的可迭代对象中的元素为none """ #方式五:map[匿名函数] newlist5 = list(map(lambda x:x ** 2,list1)) print(newlist5) # 已知有一个整数列表,将转换为字符串列表 #例如:[2,3,4,5]------>['2','3','4','5'] str() list2 = [2,3,4,5] newl1 = [] for num in list2: newl1.append(str(num)) print(newl1) newl2 = [str(num) for num in list2] newl3 = list((str(num) for num in list2)) newl4 = list(map(str,list2)) print(newl4)
reduce():迭代【累积】
from functools import reduce """ 导入模块:functools reduce(function,iterable):函数会对序列中的元素进行累积 功能:用传给reduce的函数先序列中的第1,2个元素进行操作, 用得到的结果和第3个元素进行操作,用得到的结果和第4个元素进行操作。。。。 举例: f,[a,b,c,d] reduce(f,[a,b,c,d]) 工作原理:f(f(f(a,b),c),d),类似于递归 """ # 计算一个整数列表中元素的和 # 一:自定义 list1 = [1,2,3,4,5] total = 0 for num in list1: total += num print(total) # 二:reduce【def定义函数】 def mysum(x,y): return x + y result0 = reduce(mysum,list1) print(result0) """ mysum(1,2)---->3 mysum(3,3)---->6 mysum(6,4)---->10 mysum(10,5)---->15 """ # 三:reduce[匿名函数] result1 = reduce(lambda x,y:x + y,list1) print(result1) """ 函数的注意事项: a.必须有两个参数 b.必须设置返回值【报错:typeerror: unsupported operand type(s) for +: 'nonetype' and 'int'】 """ # 将[1,3,5,7,9]转换为整数13579 list2 = [1,3,5,7,9] def func(x,y): return x * 10 + y result3 = reduce(func,list2) print(result3) # 自定义一个函数,实现str转换为int的函数 int(xx) def chartonum(s): # 自定义字符串和整型之间的映射关系 digits = {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6} return digits[s] # 需求:“24356”------》24356 # a.产生映射关系 r0 = list(map(chartonum,"24356")) print(r0) #b.使用reduce累积 r1 = reduce(func,r0) print(r1) print(type(r1)) r2 = reduce(func,map(chartonum,"23456")) print(r2)
上一篇: scrapy爬取美女图片