第四篇 函数

一.函数的定义

# 函数的定义

def 函数名(形参):
    '''
    文档字符串
    函数功能:
    函数参数:
    函数返回值
    '''
    function_body
    return [expression]

# 函数的使用
函数名(实参)
# 1. 函数的定义
def sayHello(name):
    print("你好,{},很高兴再次见到你".format(name))

    return "{}来北京看我了".format(name)


#函数的调用
print(sayHello("dali"))

# 输出
你好,dali,很高兴再次见到你
dali来北京看我了

 

# 2. 函数可以没有参数
def Hello():
    a= 3+4
    return a

print(Hello())

#输出
7

 

# 3. 定义一个变量,给变量的赋值是个函数名,就相当于把这个变量变成一个函数了

def sayHello2(name):
    print("你好,{},很高兴再次见到你".format(name))
    return 1
message = sayHello2
print(message("xiaochengzi"))

# 输出
你好,xiaochengzi,很高兴再次见到你
1

二.函数的参数

1. 必备参数 或者 位置参数

位置参数的特点:必须要给它传值,位置在最前面,定义了几个位置参数,调用函数的时候就必须传几个参数,否在会报错

# x,y 是位置参数,位置参数就是必须参数,函数调用时不能缺少
def add(x,y):
    return x+y

print(add(2,3))   #5
# 错误示例
def add(x,y):
    return x+y

print(add(2))  

# TypeError: add() missing 1 required positional argument: 'y'

2. 默认参数

如果不想给某个参数传值,但是参数个数还不减少,那可以在函数声明时设置默认参数,就是给某个参数一个默认值,

如果不传值,函数调用时,默认就用的是设置的默认参数,如果传值了,函数调用时就用的是传的值

特点:默认参数的位置,一定要放到所有的位置参数的后面

# # j 定义时就给了个默认参数,如果j不传值,就默认取0, 默认参数一定要放在所有参数的最后面
def add1(i,j=0):
    return i+j

print(add1(3))   # 3

3. 不定长参数

如果函数声明时,还不能确定到底会有多少个参数,可以定义不定长参数

特点:1) 不定长参数用*args表示, 2) *args的类型是元组 3)它的位置必须在默认参数后面

def add2(x,y=0,*args):
    print(args)
    return x + y

print(add2(2))
# 输出
()    # 此时x=2,y =0, *args没有传参,是个空元组
2

print(add2(4,5))
#输出
()   # 此时x=4,y =5, *args没有传参,是个空元组
9

print(add2(1,3,5,7,9))
# 输出
(5, 7, 9)  # 此时x=1,y =3, *args是个元组,其值是(5,7,9)
4
def add2(x,y=0,*args):
    print(args)
    return x + y + sum(args)  # 使用参数,要去掉*号


print(add2(1,3,5,7,9))

#输出
(5, 7, 9)
25

4. 关键字参数

如果想传的参数是字典,就可以用关键字参数

特点:关键字参数 **kargs ,其类型是字典,必须最最后面,以 a = 1的形式传参

def add4(x,y,*args,**kwargs):
    print(kwargs)
    return x + y + sum(args) + sum(kwargs.values())

print(add4(1,3,3,4,5,a=1,b=5,c=5,d=-5))

# 输出
{'a': 1, 'b': 5, 'c': 5, 'd': -5} # 此时,x=1,y=3, args=(3,4,5),kwargs = {'a': 1, 'b': 5, 'c': 5, 'd': -5}

22

5. 形参与实参

 

 

三.函数的作用域

函数作用域的寻找顺序:Local -> enclosing->global -> build-in

1. L(Local)局部作用域

变量是在函数内定义的

a = 3  # 全局作用域

def scope():
    a = 5   # 局部作用域
    print(a)

scope()

# 输出
5

 

2. E(Enclosing)闭包函数外的函数中

见后面闭包的介绍

 

3.G (Global)全局作用域

变量是在函数外定义的,是整个文件的

a = 3

def scope():
    print(a)

scope()
#输出
3

4. B(Built-in) 内建作用域

Python 自带的,预留的一些变量,函数名等

Python自带的不太适合举例说明

作用域的查找顺序是先局部,后全局,最后再内建,如果都没有该变量,就会报错

def scope():
    print(a)

scope()

# NameError: name 'a' is not defined

5. 作用域有两个函数:Locals() 和 globals()

a = 3

def scope():
    a = 5


print(globals())
# 输出
{'__name__': '__main__', '__doc__': '\n作用域生效机制\n局部  闭包函数外的函数中 全局 内建\n\n', '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x10511a470>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': '/Users/qiaoersun/Documents/千万别删/测试/Codes/testfanStudyPractice/lesson02/作用域.py', '__cached__': None, 'a': 3, 'scope': <function scope at 0x10529bd08>}

暂时还没弄明白

四.闭包(_closure_)

闭包的特点:

1. 闭包函数必须有内嵌函数

2. 内嵌函数需要引用嵌套函数的变量

3. 闭包函数必须返回内嵌函数

闭包的作用:

1. Python闭包就是装饰器(或叫修饰器)

2. 在不改原有函数任何内容的情况下,给原有函数增加功能

def greeting(name):
    '''
    1.在greeting函数中内嵌了一个greet函数
    2.greeting函数的返回值是一个函数greet

    '''
    def greet():
        print(name)
    return greet   # 函数的返回值是greet函数

# 定义一个func变量,调用greeting函数,因为greeting函数的返回值是greet,而greet也是个函数,所以就相当于func是个函数
# 此时只是返回了greet,greet函数并没有被调用,所以也不会有任何返回值
func = greeting('老刘')


# 那么再调用func这个函数就等于是调用的下面的部分
'''
    def greet():
        print(name)
'''
func()
# 输出
老刘
# greeting()其实就是greet函数,那么也可以用下面的方式调用
greeting("小猫")()
# 输出
小猫

对闭包函数的公式总结

def greeting(name):
    # 1. greeting函数里内嵌,嵌套了一个greet函数 --> 满足了:闭包函数必须有内嵌函数
    a = 5
    def greet():
        # 2.在内嵌函数里引用了嵌套函数(greeting)的变量:a 和 name, 这个变量必须是内嵌函数外层已经定义的,不能是全局变量--->
        # 满足了:内嵌函数必须要引用嵌套函数的变量
        print(name)
        print(a)
    # 3. greeting函数里返回了一个内嵌函数greet--->满足了:函数必须返回内嵌函数
    return greet   # 注意此处不能返回greet()

 # 4. 由上面3点的同时满足,才使得greeting成为一个闭包函数
 
 # 5. 闭包函数的调用,在上面已经有了,此处略

在Python里闭包其实就是装饰器

五.装饰器

 装饰器的作用:就是为已经存在的对象添加额外的功能

 装饰器的应用场景:插入日志,性能测试,事务处理,缓存,权限校验等等

示例:计算一个函数执行用了多长时间

'''
闭包的作用:
1. 在Python闭包就是装饰器(或叫修饰器)
2. 在不改原有函数任何内容的情况下,给原有函数增加功能

利用闭包实现修饰器
'''

'''
1. 计算原有函数wait()的执行时间,但是不能改wait()函数的任何代码
2. add()函数,把add()执行结果写入一个文件,不能改变add()函数的任何值
'''


import  time
import random

'''
解决办法:用闭包的方式解决,那么就要把原来已经存在的功能,即函数作为参数传递给闭包,此处形参用func代替
闭包一定是写在原还是的前面的
'''
# 2.用闭包的方式不改变原代码的情况下,新增计算时间的功能
def decorator(func):
    def wrapper():
        startTime = time.time()
        result = func()
        endTime = time.time()
        print("测试结束,花费时间{}秒".format(endTime-startTime))
        return result   # 上面已经执行过了result,这里为什么还要再返回一下result?不返回会有什么影响?
    return wrapper

'''
wait函数是已经存在的一段代码,假设有一万行,突然有个需求,要在wait上加一个功能,计算wait函数执行需要花多长时间
如果直接在wait函数上改,可能会引起其他bug,第二你也懒得看wait的代码,一个好的解决办法就是使用闭包,用装饰器来解决
这个问题
'''

# 1. 已有的功能
def wait():
    w = random.randint(5,10)
    print(w)
    time.sleep(w)
    print("执行wait完毕,用了{}秒".format(w))

# 3. 调用闭包,获取执行结果
a = decorator(wait)  # 相当于a 就是 wrapper函数里
a()  # 再调用wrapper函数, 就能得到计算的结果

# 输出
9
执行wait完毕,用了9秒
测试结束,花费时间9.005208253860474秒

上面利用闭包写好了修饰器,但是闭包的使用不是像上面那样通过a = decorator(wait)()的方式使用的,而是通过在原有函数的上面加@闭包函数名的方式使用

import  time
import random


# 2.用闭包的方式不改变原代码的情况下,新增计算时间的功能
def decorator(func):
    def wrapper():
        startTime = time.time()
        result = func()
        endTime = time.time()
        print("测试结束,花费时间{}秒".format(endTime-startTime))
        return result   
    return wrapper


# 3.通过@闭包函数名的方式,实现装饰器
@decorator
# 1. 已有的功能
def wait():
    w = random.randint(5,10)
    print(w)
    time.sleep(w)
    print("执行wait完毕,用了{}秒".format(w))

# 4. 直接调用原函数就可以实现功能
wait()

# 输出
10
执行wait完毕,用了10秒
测试结束,花费时间10.002923727035522秒

 

# 示例2

'''
已知:现有add函数
需求:add函数执行结果写到一个文件里去
'''


def writeAddtoFile(func):  # 闭包的参数func,将来传的就是原有的功能函数add,这是永远不变的,套路,固定写法;外面的函数传函数名
    def wrapper(a,b):      # 内嵌函数的参数,接受的是原函数add的参数,这也是永远不变的,套路,固定写法;里面的函数传的才是参数
        result = func(a,b)
        with open("add.txt",'a',encoding='utf-8') as f:
            f.write(str(result)+"\n")   # 换行写入,要在写入的内容后面 加 +"\n"
            f.close()
    return wrapper

@writeAddtoFile
def add(x,y):
    return x+y


add(5,8)
add(3,5)
add(1,1)
# 固定写法
def deco(func):    # 固定写法,这里的func将来接收的是add
    def wrapper(*args, **kargs):   #  固定写法:这里的参数将来接收的时候 add函数的a 和 b 两个参数
        result = func(args, kargs)    # 新功能在内嵌函数里写
        return result
    return wrapper   # 固定写法;要把内嵌的函数返回


def add(a,b):
    pass

练习:输入某年某月某日,判断这一天是这一年的第几天?

import time

def calDay(date):
    '''
    输入某个日期,计算是这一年的第几天
    :param date:
    :return:
    '''
    # 1. 先把输入的日期格式化
    fenGefu = ['/','.','-','','']
    try:
        for i in date:
            if i in fenGefu:
                date=date.replace(i,'-')
            elif i == '':
                date=date.replace(i,"")

        # 2.利用time模块函数得到
        forMatDate = time.strptime(date, '%Y-%m-%d')
        result = time.struct_time(forMatDate)
        # 3. 提取想要的结果返回
        days = result.tm_yday
        return "{}是今年的地{}天".format(date, days)
    except Exception:
        print("您输入的日期格式不对,请检查后重新输入")


date=input("请输入年月日:")

print(calDay(date))

 六.内置函数

1. 类型转换函数

bool , int , long ,float ,bytearray  str,  unicode, basestring,list tuple
set,dict, frozenset, complex

2.文件IO

input, print, open,file, format

3. 数学运算

abs,divmod, pow, sum, cmp, bin, oct, hex, chr, unichr, ord, max, min, round
# 1. 求模求余
divmod(99,1) # (14,1)

#2. 求幂
pow(2,3)    $ 8

# round()四舍五入, 有bug,慎用

 

4. 集合切片

len, range, iter, next, slice(切片), enumerate, sorted, reversed

 

data = ['a','b','c']
# enumerate 返回对象的下标
for i,v in enumerate(data): 
print(i,v)

# 输出

0 a
1 b
2 c

5. 高阶函数

高阶函数:返回值是函数,或者函数的参数是函数

any(任意一个满足条件,返回True), all(所有满足条件,返回TRUE), map,reduce, filter, zip

map,reduce,filter是Python里很常用的三个高阶函数

map(func,iter):第一个参数是个函数,第二个参数要是一个可迭代对象

# map的第一个参数是个函数,第二个参数是个可迭代对象
# map的作用:对data数据里的每个元素,分别执行函数pow
# map的返回是个map对象,所以,map的两种使用方法:1. 用list转化,  2.用for循环

data = [1,2,3,4,5,6,7,8,9]
def pow(n):
    return n**n

# map的第一个参数是个函数,第二个参数是个可迭代对象
# map的作用:对data数据里的每个元素,分别执行函数pow
# map的返回是个map对象,所以,map的两种使用方法:1. 用list转化,  2.用for循环


# 使用list获取map的返回值
print(list(map(pow,data)))
# 输出
[1, 4, 27, 256, 3125, 46656, 823543, 16777216, 387420489]

# map函数用for循环取结果
for p in map(pow,data):
    print(p)

# 输出
1
4
27
256
3125
46656
823543
16777216
387420489
# 还有更简单的,就是可以用lambda 匿名函数,替换 pow函数,就不用再定义上面的pow函数了

print(map(lambda n: n**2, data))

lambda 返回值:表达式

reduce(function,sequence): 第一个参数是个函数,

reduce():折叠函数,

# reduce函数:折叠函数
# 作用:类似于sum(),
# 函数的运行方式:data里的1和2先相加得到3,然后再用3+ data里的3,得到6,然后用6再加data里的4,依次类推,直到data的最后一个数

from functools import reduce  # reduce 在Python3里,要先导入才能使用
print(reduce(lambda x,y:x+y, data))
# 输出 45

filter(func, iter):过滤器

作用:filter函数作为过滤器,挑选满足条件的数据

# filter 函数
# 作用:filter函数作为过滤器,挑选满足条件的数据
# 从data里挑选出奇数
print(list(filter(lambda x:x % 2 !=0, data)))

# 输出
[1, 3, 5, 7, 9]
# 从data里取出偶数

print(list(filter(lambda x:x % 2 == 0, data )))

# 输出
[2, 4, 6, 8]

6. 反射与内省

type, isinstance,issubclass,callable,staticmethod,classmethod,getattr, setattr, delattr,hasattr,
super,dir,help,id,hash,object,__import__,compile,reload, repr,vars,locals,globals,eval,exec , execfile,
property,memoryview

 

posted @ 2019-08-03 22:14  mamingchen  阅读(242)  评论(0编辑  收藏  举报