python getsize函数_python之函数

我们可以用一段代码来实现我们需要的功能,但是当我们需要重复使用这段代码时,复制粘贴并不是一个酷的方法,我们可以用到函数来实现这一需求

一、函数定义

函数是逻辑结构化和过程化的一种编程方法,通过一个函数名封装好一串用来完成某一特定功能的代码

函数的定义:

def 函数名(参数1,参数2....):

''注释''

函数体

def func1():  #定义函数

print('this is a function')  #函数体

func1()  #调用函数

#通常无参函数不需要返回值,有参函数需要有返回值

def func1(name):  #带参数的形式

print('%s is a good man'%name)

func1('egon')

#关于函数的返回值,如果没有指定,默认是None

#函数与过程的定义就是过程没有返回值,用完之后就没有了,而函数有返回值

def func1(name):

print('%s is a good man'%name)

print(func1('egon'))

-->  egon is a good man

None

函数的优点:1.代码重用

2.保持一致性,易于维护

3.可扩展性好

注意:1.函数必须先定义,在使用,和变量类似,在定义前使用会报错

2.函数在定义阶段只检测语法错误,不会执行代码,所以即使在函数体内有未定义的变量名,在函数未调用前也不会报错

3.函数的返回值可以是任意类型,如果是返回多个值,一定是元组形式

4.return 的作用是终止函数的执行,return只执行一次,后面的内容不执行

二、函数参数

函数的参数分为形式参数和实际参数,在函数定义的时候,函数名后面括号里的就是形式参数,在函数调用的时候,传递的参数是实际参数。形式参数只在函数内部有效,外部无法引用。

1.形参

1)位置参数:按照从左到右的顺序依次定义的参数 def foo(x,y,z)

位置形参必须被传值,且多一个少一个都不行

2)默认参数:在函数定义阶段就已经为形参赋值,调用阶段不赋值也会有默认值 def foo(x,y=10)

值经常变化的情况,通常定义成位置参数,但是值在多数情况下不变的情况下,可以定义成默认参数

注意:

a.默认参数必须放在位置参数后面

b.默认参数通常定义成不可变类型

c.默认参数只在定义时被赋值一次

3)命名关键字参数:def register(*,name,age) *后面定义的形参,必须被传值,且必须以关键字的形式传值

2.实参

1)位置实参:与位置形参一一对应

2)关键字参数:实参在定义时,按照key-values的形式定义

def foo(x,y)

foo(x=1,y=2)

关键字参数可以不用向位置参数一样与形参一一对应,可以打破顺序限制

注意:a.位置参数和关键字参数混合使用的时候,位置参数必须在关键字参数前面

b.既可以是位置实参形式,也可以是关键字实参形式,但是一个形参只能传值一次

3)可变长参数:

按位置定义的可变长参数用*表示

按关键字定义的可变类型的参数用**表示

def func(x,y,*args):

print(x,y,args)

func(1,2,3,4,5)  --->1 2 (3 4 5)

#遇到*就是位置参数,把*后面的全部拆开,再一一匹配,多余的就以元组的形式存放到一起

def func(x,y,**kwargs):

print(x,y,kwargs)

func(1,y=2,z=3,a=1,b=2)---->1 2 {'z': 3, 'a': 1, 'b': 2}

#遇到**就是关键字参数,把**后面的全部拆成关键字,再一一匹配,多余的以字典形式存放到一起

def wrapper(*args,**kwargs):可以接受任意形式,任意长度的参数

参数的定义顺序:x,y=1,*args,z,**kwargs,分别是位置参数,默认参数,可变长位置参数,命名关键字参数,可变类型参数

但需要注意的是,这些参数并不会同时全部出现

三、名称空间和作用域

名称空间存放名字和值的绑定关系,以key-value 的形式

在Windows命令提示行中输入命令:import this ,在最后一行会看到这样一句话:

Namespaces are one honking great idea -- let's do more of those!

名称空间分为三种:

1)内置名称空间:Python自带的,如print,int,len....当Python解释器启动的时候,就会生成内置名称空间

2)全局名称空间:文件级别定义的名字会存放到全局名称空间,执行Python程序的时候产生,简单点说就是没有缩进的变量名

3)局部名称空间:定义在函数(或模块、类)内部的名字,只有在函数(模块、类)调用的时候才生效,调用结束后就会释放

加载顺序是:内置名称空间-->全局名称空间-->局部名称空间

取值顺序是:局部名称空间-->全局名称空间-->内置名称空间

四、函数嵌套和作用域

1.函数嵌套包括函数的嵌套调用和函数的嵌套定义

函数嵌套调用可以用求最大值的例子来说明:

def max2(x,y):

if x > y:

return x

else:

return y

def max4(a,b,c,d):

res1=max2(a,b) #23

res2=max2(res1,c) #23

res3=max2(res2,d) #31

return res3

print(max4(11,23,-7,31))

函数嵌套定义:

def f1():

def f2():

def f3():

print('from f3')

print('from f2')

f3()

print('from f1')

f2()

# print(f1)

f1()

2.作用域

1)全局作用域:内置名称空间与全局名称空间的名字属于全局范围,在整个文件的任意位置都能引用

2)局部作用域:属于局部范围,只在函数内部可以被引用,局部有效

一定要注意局部变量和全局变量的作用范围,在局部修改全局变量会出错,在全局范围引用局部变量也会出错

作用域在函数定义时就已经固定了,不会因调用位置而改变

但是如果一定要在局部修改全局变量,也是用办法的,就是在要修改的变量前加一个global

x=1

def foo():

x=10

print(x)

foo() #10

print(x) #1

x=1

def foo():

global x

x=10

print(x)

foo() #10

print(x) #10

def foo():

x=1

def f2():

x+=x

return x

return f2()

print(foo()) #会报错UnboundLocalError: local variable 'x' referenced before assignment

def foo():

x=1

def f2():

nonlocal x  #告诉Python解释器,这里的x不是局部变量,只会找函数内部的,不会修改全局变量

x+=x

return x

return f2()

print(foo()) #会打印出修改后的x的值,2

五、闭包函数

定义在函数内部的函数,该内部函数包含对外部作用域,而非全局作用域的名字的引用,那么该内部函数称为闭包函数

name='egon'

def func():

name='alex'

def bar():

print(name)

return bar

f=func() #f就是闭包函数

print(f.__closure__[0].cell_contents) #该命令可以查看闭包函数外面包了什么东西------>alex

闭包函数的特点:a.自带作用域,b.延迟计算(f只是拿到了函数的内存地址,什么时候用,加括号就可以运行)

闭包函数最基本的形式:

def 外部函数名():

内部函数需要的变量

def 内部函数名():

引用外部变量

return 内部函数名

六、装饰器

1.开放封闭原则:对扩展是开放的,对修改是封闭的

2.装饰器本质是任意可调用的对象,被装饰对象也是任意可调用的对象

3.装饰器的功能是:在不修改被装饰对象源代码及调用方式的前提下,为其添加新的功能

4.装饰器语法:在被装饰对象的正上方的单独一行,写上@装饰器名字

5.有多个装饰器的时候,每行一个,执行时从上往下运行

6.被装饰函数有参数的情况:写成(*args,**kwargs)的形式

装饰器示例一:

#实现缓存网页内容的功能,下载的页面存放于文件中,如果文件内有值(文件大小不为0),

# 就优先从文件中读取网页内容,否则,就去下载,然后存到文件中

from urllib.request import urlopen

import os

cache_path=r'C:\untitled\0615Python第8天\cache_file.txt'

def make_cache(func):

def wrapper (*args,**kwargs):

if os.path.getsize(cache_path):

#有缓存

print('\033[45m========>有缓存\033[0m')

with open(cache_path,'rb') as f:

res=f.read()

else:

res=func(*args,**kwargs)#下载

with open(cache_path,'wb') as f:#制作缓存

f.write(res)

return res

return wrapper

@make_cache

def get(url):

return urlopen(url).read()

print(get('https://www.python.org'))

装饰器示例二:

#为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码

db_dic={

'egon':'123',

'alex':'alex3714',

'yuanhao':'smallb'

}

db_path=r'C:\untitled\0615Python第8天\db_dic.txt'

with open(db_path,'w',encoding='utf-8') as f:

f.write(str(db_dic))

login_dic={

'user':None,

'status':False,

}

def auth(func):

def wrapper(*args,**kwargs):

#加一个验证状态的字典,如果已经登录成功,下次使用就不用重新验证

if login_dic['user'] and login_dic['status']:

res=func(*args,**kwargs)

return res

else:

name=input('name:')

password=input('password:')

with open(db_path, 'r', encoding='utf-8') as f:

auth_dic = eval(f.read())

if name in auth_dic and password==auth_dic[name]:

print('login ok')

login_dic['user']=name

login_dic['status']=True

res=func(*args,**kwargs)

return res

else:

print('error')

return wrapper

@auth

def index():

print('welcom to the page')

@auth

def home(name):

print('welcom to %s\'s home page'%name)

index()

home('egon')

七、迭代器

1.对于字符串、列表、元组的数据类型,我们可以依据索引来实现迭代的效果,但是字典、集合这种没有索引的数据类型,就需要其他方式

2.Python为了提供一种不依赖索引的迭代方式,为一些对象内置了__iter__方法,obj.__iter__()得到的结果就是迭代器

得到的迭代器既有.__iter__方法,又有.__next__方法

3.迭代器的优点:

a.提供了一种不依赖索引的取值方式

b.惰性计算,节省内存

4.迭代器的缺点:

a.取值不如按照索引取值方便

b.一次 性的,取值只能往后走,不能往前退

c.无法获取迭代器的长度

5.for循环实际上会默认调用.__iter__方法

6.判断是否是可迭代对象和迭代器,可以用命令

print(isinstance(str1,Iterable)) --->判断是否为可迭代对象

print(isinstance(str1,Iterator)) --->判断是否为迭代器

八、生成器函数(语句形式和表达式形式)

1.生成器函数:函数体内包含有yield关键字,该函数的执行结果就是生成器

2.生成器实际就是迭代器的一种

3.yield的功能:

a.与return类似,都可以返回值,但不一样的地方在于yield返回多次值,而return只能返回一次值

b.为函数封装好了__iter__和__next__方法,把函数的执行结果做成了迭代器

c.遵循迭代器的取值方式obj.__next__(),触发的函数的执行,函数暂停与再继续的状态都是由yield保存的

4.生成器语句形式应用实例

1 #模拟linux中tail -f a.txt|grep 'error' |grep '404'的功能

2 import time

3 def tail(filepath,encoding='utf-8'):

4 with open(filepath,encoding='utf-8') as f:

5 f.seek(0,2) #以末尾为开始位,第0个

6 while True:

7 line=f.readline()

8 if line:

9 yield line

10 else:

11 time.sleep(0.5)

12

13 def grep(lines,pattern):

14 for line in lines:

15 if pattern in line:

16 # print(line)

17 yield line

18

19 g1=tail('a.txt')

20 g2=grep(g1,'error')

21 g3=grep(g2,'404')

22

23 for i in g3:

24 print(i)

5.生成器的表达式形式

def foo():

print('starting')

while True:

x=yield #默认就是yield None

print('value :',x)

g=foo()

next(g)  #初始化,等同于g.send(None)

g.send(2)

将yield赋值给一个变量如x=yield,然后用send()传值,但注意要先做一个类似初始化的操作

g.send(2)的操作实际是先把2传值给yield,再由yield传值给x,send()既有传值的效果,又有next()的效果

生成器表达式形式应用示例

1 def init(func):

2 def wrapper(*args,**kwargs):

3 g=func(*args,**kwargs)

4 next(g)

5 return g

6 return wrapper

7 @init

8 def eater(name):

9 print('%s ready to eat' %name)

10 food_list=[]

11 while True:

12 food=yield food_list#return None

13 food_list.append(food)

14 print('%s start to eat %s' %(name,food))

15

16

17 e=eater('alex')

18 print(e.send('狗屎'))

19 print(e.send('猫屎'))

20 print(e.send('alex屎'))

21

22

23 def make_shit(people,n):

24 for i in range(n):

25 people.send('shit%s' %i)

26

27 e=eater('alex')

28 make_shit(e,5)

29 #from egon

30 #egon老师的例子有味道,但是我又忍不住不用这个

九、三元表达式

res= x if x>y else y----->判断条件x>y是否为真,为真则把x赋给res,否则把y赋给res

十、列表解析

s='hello'

res=[i.upper() for i in s]

print(res) #['H', 'E', 'L', 'L', 'O']

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值