Python 您所在的位置:网站首页 python中两个集合的关系 Python

Python

2023-03-09 23:32| 来源: 网络整理| 查看: 265

第一篇:函数的基本使用 一、定义

具备某一功能的可执行程序,函数必须遵循先定义后调用的原则。

二、定义函数 def 函数名(参数1,参数2,...): """文档描述""" 函数体 return 值

def: 定义函数的关键字;

函数名:函数名指向函数内存地址,是对函数体代码的引用。函数的命名应该反映出函数的功能;

括号:括号内定义参数,参数是可有可无的,且无需指定参数的类型;

冒号:括号后要加冒号,然后在下一行开始缩进编写函数体的代码;

"""文档描述""": 描述函数功能,参数介绍等信息的文档,非必要,但是建议加上,从而增强函数的可读性;

函数体:由语句和表达式组成;

return 值:定义函数的返回值,return是可有可无的。

参数是函数调用者向函数传值的媒介,若函数体代码逻辑依赖外部传来的参数时,则需要定义为有参函数。

def my_min(x,y): res=x if x < y else y return res

否则定义为无参函数

def interactive(): user=input('user>>: ').strip() pwd=input('password>>: ').strip() return (user,pwd) 三、pass

函数体为pass代表什么都不做,称之为空函数。定义空函数通常是有用的,用pass充当占位符,在哦我们构思程序框架体系的时候,通常先定义为空函数。

def auth_user(): """user authentication function""" pass def download_file(): """download file function""" pass def upload_file(): """upload file function""" pass def ls(): """list contents function""" pass def cd(): """change directory""" pass 四、调用函数与函数返回值

函数的使用分为定义阶段和调用阶段,定义函数的时候只检测语法,不执行函数体代码,函数名+()才表示函数的调用,只有调用函数时才会执行函数体代码。

return后面是函数体代码执行完的返回值,return可以将多个值返回并放到一个元组内,return 是函数执行结束的标志,一个函数可以有多个return 但是只会执行一个return,执行一次函数就会结束并把return 后面定义的值作为本次函数调用的结果返回。

>>> def test(x,y,z): ... return x,y,z #等同于return (x,y,z) ... >>> res=test(1,2,3) >>> print(res) (1, 2, 3) 第二篇:函数的参数 一、形参与实参的介绍

1.形参是在定义函数时,函数名后面的括号里声明的参数。形参的本质就是一个变量名,需要被赋值。

2.实参是在调用函数时,函数名后面的括号里传入的值:常量变量表达式或者三者的组合形式。

在调用有参函数时,实参会赋值给形参。因为在python中变量名和变量值只是单纯的绑定关系,在函数中这种绑定关系会在函数时生效,在函数调用结束后解除绑定。

二、位置参数

位置形参:在定义函数时,按照从左到右的方式依次定义的形参,这样定义的定义的形参都需要被赋值。

位置实参:在调用函数时,按照从左到右的方式依次放入括号内的实参,位置实参必须与位置形参一一对应,为位置形参赋值。

三、关键字实参

在函数调用阶段,以key=value键对形式出现的实参称为关键字实参,这种实参可以不按照位置与形参一一对应传值,也可以与位置实参混合用,但关键字实参必须在位置参数后面而且不可以对一个形参重复赋值。

四、默认形参

在定义函数阶段就已经为形参赋值。默认形参必须在位置形参之后,默认形参的值只能在函数定义阶段被赋值一次,最好是不可变类型。

五、可变长参数(*args和**kwargs 的用法) 可变长度的位置参数

如果在最后一个形参名为*args,在调用函数时,溢出的位置参数都会被*args接收,以元组的形式保存下来赋给该形参。

>>> def foo(x,y,z=1,*args): #在最后一个形参名args前加*号 ... print(x) ... print(y) ... print(z) ... print(args) ... >>> foo(1,2,3,4,5,6,7) #实参1、2、3按位置为形参x、y、z赋值,多余的位置实参4、5、6、7都被*接收,以元组的形式保存下来,赋值给args,即args=(4, 5, 6,7) 1 2 3 (4, 5, 6, 7)

如果事先生成一个列表也是可以传递给*args的,需要这样传:

这里其实经历了这样一个过程,*L是将列表里的元素打散,*就相当于起了一个打散的作用,传递给*args,然后*args再将这些参数返回成一个元组。如果L前不加*就是一个普通列表型参数。

>>> def foo(x,y,*args): ... print(x) ... print(y) ... print(args) ... >>> L=[3,4,5] >>> foo(1,2,*L) # *L就相当于位置参数3,4,5, foo(1,2,*L)就等同于foo(1,2,3,4,5) 1 2 (3, 4, 5) 可变长度的关键字参数

如果在最后一个形参名前加号,那么在调用函数时,溢出的关键字参数,都会被接收,以字典的形式保存下来赋值给该形参

>>> def foo(x,**kwargs): #在最后一个参数kwargs前加** ... print(x) ... print(kwargs) ... >>> foo(y=2,x=1,z=3) #溢出的关键字实参y=2,z=3都被**接收,以字典的形式保存下来,赋值给kwargs 1 {'z': 3, 'y': 2}

如果我们事先生成了一个字典,仍然是可以传值给**kwargs的

>>> def foo(x,y,**kwargs): ... print(x) ... print(y) ... print(kwargs) ... >>> dic={'a':1,'b':2} >>> foo(1,2,**dic) #**dic就相当于关键字参数a=1,b=2,foo(1,2,**dic)等同foo(1,2,a=1,b=2) 1 2 {'a': 1, 'b': 2}

注意:如果在传入dic时没有加**,那dic就只是一个普通的位置参数了。如果形参为常规参数(位置或默认),实参仍可以是**的形式

>>> def foo(x,y,z=3): ... print(x) ... print(y) ... print(z) ... >>> foo(**{'x':1,'y':2}) #等同于foo(y=2,x=1) 1 2 3 命名关键字参数

需要在定义形参时,用作为一个分隔符号,*号之后的形参称为命名关键字参数。对于这类参数,在函数调用时,必须按照key=value的形式为其传值,且必须被传值

>>> def register(name,age,*,sex,height): #sex,height为命名关键字参数 ... pass ... >>> register('lili',18,sex='male',height='1.8m') #正确使用 >>> register('lili',18,'male','1.8m') # TypeError:未使用关键字的形式为sex和height传值 >>> register('lili',18,height='1.8m') # TypeError没有为命名关键字参数height传值。

命名关键字参数也可以有默认值,从而简化调用

>>> def register(name,age,*,sex='male',height): ... print('Name:%s,Age:%s,Sex:%s,Height:%s' %(name,age,sex,height)) ... >>> register('lili',18,height='1.8m') Name:lili,Age:18,Sex:male,Height:1.8m

需要强调的是:sex不是默认参数,height也不是位置参数,因为二者均在*后,所以都是命名关键字参数,形参sex=’male’属于命名关键字参数的默认值,因而即便是放到形参height之前也不会有问题。另外,如果形参中已经有一个args了,命名关键字参数就不再需要一个单独的*作为分隔符号了

>>> def register(name,age,*args,sex='male',height): ... print('Name:%s,Age:%s,Args:%s,Sex:%s,Height:%s' %(name,age,args,sex,height)) ... >>> register('lili',18,1,2,3,height='1.8m') #sex与height仍为命名关键字参数 Name:lili,Age:18,Args:(1, 2, 3),Sex:male,Height:1.8m 组合使用

所有参数可任意组合使用,但定义顺序必须是:位置参数、默认参数、*args、命名关键字参数、**kwargs。

可变参数args与关键字参数kwargs通常是组合在一起使用的,如果一个函数的形参为args与kwargs,那么代表该函数可以接收任何形式、任意长度的参数

在该函数内部还可以把接收到的参数传给另外一个函数

>>> def func(x,y,z): ... print(x,y,z) ... >>> def wrapper(*args,**kwargs): ... func(*args,**kwargs) ... >>> wrapper(1,z=3,y=2) 1 2 3

按照上述写法,在为函数wrapper传参时,其实遵循的是函数func的参数规则,调用函数wrapper的过程分析如下:

位置实参1被*接收,以元组的形式保存下来,赋值给args,即args=(1,),关键字实参z=3,y=2被**接收,以字典的形式保存下来,赋值给kwargs,即kwargs={'y': 2, 'z': 3}

执行func(args,kwargs),即func(*(1,),** {'y': 2, 'z': 3}),等同于func(1,z=3,y=2)

第三篇:名称空间与作用域 一、名称空间

名称空间即存放名字与对象印射/绑定关系的地方。可以理解为存放变量值与变量名绑定关系。

内置名称空间

伴随python解释器的启动/关闭而产生/回收,因而是第一个被加载的名称空间,用来存放一些内置的名字,比如内置函数名。

全局名称空间

伴随python文件的执行/关闭而产生/回收,是第二个被加载的名称空间,文件执行过程中产生的名字都会存放于全局名称空间。

局部名称空间

伴随函数调用结束而产生回收大的名字都放于局部名称空间,函数的形参,函数内定义的名字都会存放于该名称空间中。

名称空间的加载顺序 内置名称空间->全局名称空间->局部名称空间 二、作用域 全据作用域和局部作用域

将三个名称空间划分为两个区域:全局作用域包括内置名称空间,全局名称空间;局部作用域包括局部名称空间

作用域与名字查找的优先级

1.在局部作用域查找名字时:局部名称空间==》全局名称空间==》》内置名称空间==》抛出异常

2.在全局作用域查找名字时:全局名称空间==》》内置名称空间==》抛出异常

3.在内嵌函数内查找名字时:自己局部作用域==》》一层层找外部嵌套函数定义的作用域==》》全局作用域

x=1 def outer(): x=2 def inner(): # 函数名inner属于outer这一层作用域的名字 x=3 print('inner x:%s' %x) inner() print('outer x:%s' %x) outer() #结果为 inner x:3 outer x:2

4,一个函数无论内部嵌套多少层函数,都可以查看到全局作用域的名字,若要在函数内修改全局名称空间中名字的值,当值为不可变类型时,则要用global关键字

x=1 def foo(): global x #声明x为全局名称空间的名字 x=2 foo() print(x) #结果为2

当实参的值为可变类型时,函数体内对该值的修改将直接反应到原值,

num_list=[1,2,3] def foo(nums): nums.append(5) foo(num_list) print(num_list) #结果为 [1, 2, 3, 5]

5.对于嵌套多层的函数,使用nonlocal关键字可以将名字声明为来自外部嵌套函数定义的作用域(注意:非全局作用域中的名字),nonlocal x会从当前函数的外层函数开始一层层去查找名字x,若是一直到最外层函数都找不到,则会抛出异常。

def f1(): x=2 def f2(): nonlocal x x=3 f2() #调用f2(),修改f1作用域中名字x的值 print(x) #在f1作用域查看x f1() #结果 3 第四篇:函数对象与闭包 一、函数对象

函数名可以被引用:可以将函数名赋值给一个变量

函数名可以作为容器的元素

函数名可以作为参数传入另一个函数

函数名可以作为另一个函数的返回值

二、闭包函数

基于函数对象的概念,可以将函数调到任意位置去调用,但作用域的关系是在定义函数时就已经被确定了的,与函数的调用位置无关。函数被当作数据处理时,始终以自带的作用域为准。

若内嵌函数包含对外部函数作用域(非全局作用域)中变量的引用,那么该内嵌函数就称为闭包函数。

x=1 def f1(): def f2(): print(x) return f2 def f3(): x=3 f2=f1() #调用f1()返回函数f2 f2() #需要按照函数定义时的作用关系去执行,与调用位置无关 f3() #结果为1 x=1 def outer(): x=2 def inner(): print(x) return inner func=outer() func() # 结果为2

可以通过函数的closure属性,查看闭包函数所有包裹的外部变量

>>> func.__closure__ (,) >>> func.__closure__[0].cell_contents 2

“闭”代表函数是内部的,“包”代表函数外’包裹’着对外层作用域的引用。因而无论在何处调用闭包函数,使用的仍然是包裹在其外层的变量。

第五篇:装饰器 定义

在不改变被装饰对象的源代码和调用方式的基础之上,为被装饰对象添加新的功能。

装饰器的实现 无参装饰器的实现

如果想为下述函数添加统计其执行时间的功能

import time def index(): time.sleep(3) print('Welcome to the index page’) return 200 index() #函数执行

遵循不修改被装饰对象源代码的原则,我们想到的解决方法可能是这样

start_time=time.time() index() #函数执行 stop_time=time.time() print('run time is %s' %(stop_time-start_time))

考虑到还有可能要统计其他函数的执行时间,于是我们将其做成一个单独的工具,函数体需要外部传入被装饰的函数从而进行调用,我们可以使用参数的形式传入

def wrapper(func): # 通过参数接收外部的值 start_time=time.time() res=func() stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return res

但之后函数的调用方式都需要统一改成

wrapper(index) wrapper(其他函数)

这便违反了不能修改被装饰对象调用方式的原则,于是我们换一种为函数体传值的方式,即将值包给函数,如下

def timer(func): def wrapper(): # 引用外部作用域的变量func start_time=time.time() res=func() stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return res return wrapper

这样我们便可以在不修改被装饰函数源代码和调用方式的前提下为其加上统计时间的功能,只不过需要事先执行一次timer将被装饰的函数传入,返回一个闭包函数wrapper重新赋值给变量名 /函数名index,如下

index=timer(index) #得到index=wrapper,wrapper携带对外作用域的引用:func=原始的index index() # 执行的是wrapper(),在wrapper的函数体内再执行最原始的index

至此我们便实现了一个无参装饰器timer,可以在不修改被装饰对象index源代码和调用方式的前提下为其加上新功能。但我们忽略了若被装饰的函数是一个有参函数,便会抛出异常

def home(name): time.sleep(5) print('Welcome to the home page',name) home=timer(home) home('egon') #抛出异常 TypeError: wrapper() takes 0 positional arguments but 1 was given

之所以会抛出异常,是因为home(‘egon’)调用的其实是wrapper(‘egon’),而函数wrapper没有参数。wrapper函数接收的参数其实是给最原始的func用的,为了能满足被装饰函数参数的所有情况,便用上*args+**kwargs组合(见4.3小节),于是修正装饰器timer如下

def timer(func): def wrapper(*args,**kwargs): start_time=time.time() res=func(*args,**kwargs) stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return res return wrapper

此时我们就可以用timer来装饰带参数或不带参数的函数了,但是为了简洁而优雅地使用装饰器,Python提供了专门的装饰器语法来取代index=timer(index)的形式,需要在被装饰对象的正上方单独一行添加@timer,当解释器解释到@timer时就会调用timer函数,且把它正下方的函数名当做实参传入,然后将返回的结果重新赋值给原函数名

@timer # index=timer(index) def index(): time.sleep(3) print('Welcome to the index page') return 200 @timer # index=timer(home) def home(name): time.sleep(5) print('Welcome to the home page’,name)

如果我们有多个装饰器,可以叠加多个

@deco3 @deco2 @deco1 def index(): pass

叠加多个装饰器也无特殊之处,上述代码语义如下:

index=deco3(deco2(deco1(index))) 有参装饰器的实现

了解无参装饰器的实现原理后,我们可以再实现一个用来为被装饰对象添加认证功能的装饰器,实现的基本形式如下

def deco(func): def wrapper(*args,**kwargs): 编写基于文件的认证,认证通过则执行res=func(*args,**kwargs),并返回res return wrapper

如果我们想提供多种不同的认证方式以供选择,单从wrapper函数的实现角度改写如下

def deco(func): def wrapper(*args,**kwargs): if driver == 'file': 编写基于文件的认证,认证通过则执行res=func(*args,**kwargs),并返回res elif driver == 'mysql': 编写基于mysql认证,认证通过则执行res=func(*args,**kwargs),并返回res return wrapper

函数wrapper需要一个driver参数,而函数deco与wrapper的参数都有其特定的功能,不能用来接受其他类别的参数,可以在deco的外部再包一层函数auth,用来专门接受额外的参数,这样便保证了在auth函数内无论多少层都可以引用到

def auth(driver): def deco(func): …… return deco

此时我们就实现了一个有参装饰器,使用方式如下

# 先调用auth_type(driver='file'),得到@deco,deco是一个闭包函数,包含了对外部作用域名字driver的引用,@deco的语法意义与无参装饰器一样 @auth(driver='file') def index(): pass @auth(driver='mysql') def home(): pass

可以使用help(函数名)来查看函数的文档注释,本质就是查看函数的doc属性,但对于被装饰之后的函数,查看文档注释

@timer def home(name): ''' home page function :param name: str :return: None ''' time.sleep(5) print('Welcome to the home page',name) print(help(home)) ''' 打印结果: Help on function wrapper in module __main__: wrapper(*args, **kwargs) None '''

在被装饰之后home=wrapper,查看home.name也可以发现home的函数名确实是wrapper,想要保留原函数的文档和函数名属性,需要修正装饰器

def timer(func): def wrapper(*args,**kwargs): start_time=time.time() res=func(*args,**kwargs) stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return res wrapper.__doc__=func.__doc__ wrapper.__name__=func.__name__ return wrapper

按照上述方式来实现保留原函数属性过于麻烦,functools模块下提供一个装饰器wraps专门用来帮我们实现这件事,用法如下

from functools import wraps def timer(func): @wraps(func) def wrapper(*args,**kwargs): start_time=time.time() res=func(*args,**kwargs) stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return res return wrapper 第六篇:迭代器 迭代是什么

迭代是一个重复反馈的过程,每一次开始都依赖于上一次的结果。

可迭代对象

字符串、列表、元组、字典、集合、打开的文件

迭代器对象

可迭代对象调用iter方法,使其具有iter方法和next方法,执行next方法会计算出迭代器中的下一个值

s={1,2,3} # 可迭代对象s i=iter(s) # 本质就是在调用s.__iter__(),返回s的迭代器对象i, print(next(i))# 本质就是在调用i.__next__() print(next(i)) print(next(i)) for循环的内部原理 goods=['mac','lenovo','acer','dell','sony'] i=iter(goods) #每次都需要重新获取一个迭代器对象 while True: try: print(next(i)) except StopIteration: #捕捉异常终止循环 break 第七篇:生成器 yield

当函数中存在yield关键字,在函数还没有执行的运行的时候只是一个普通的函数,当函数运行的时候就是一个生成器。

def a(): print('a') yield 1 print('b') yield 2 print('c') yield 3 print('d') yield 4 b = a()

此时b就是一个生成器,调用它的next方法,会运行函数体代码到 yield 1 位置挂起,再调用一次next方法会运行函数体代码到yield 2位置挂起。

print(b.__next__()) print(b.__next__()) print(b.__next__()) print(b.__next__()) ===》 a 1 b 2 c 3 d 4

生成器具有iter和next方法其本质就是一个迭代器。

生成器案例:实现range range(1, 10) for i in range(1, 10): print(i) for i in my_range(1, 10): print(i) def my_range(start, stop=None, step=1): if start < stop: if not stop: stop = start start=0 while start < stop: # 0


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有