函数

函数是带名字的代码块,它的定义方法是

def  function(argument):
    pass
    return ret
#函数声明 函数名(参数)
#   函数执行过程
#   返回 返回值

函数是以功能为导向的,尽量不要在函数中插入print语句,

return 语句的作用:1、遇到return语句则结束函数

           2、返回返回值:

                                         不写return 返回 None
                                         return None 返回 None
                                         return 单个值 返回此单个值
                                         return 多个值 将多个值包在元组中,返回给调用者此元组

函数的参数

函数的参数分为形参和实参,形参即我们定义函数时使用的形式参数,在真正调用函数时形参就会被实参取代,即我们真正用户函数的参数。

从实参的角度来说,函数的传参方法有如下几点:
    按位置传参:实参和形参必须一一对应
    按关键字传参
    混合传参:关键字参数和未知参数混用,但位置参数必须在前面
从形参的角度来说,函数的传参方法有如下几点:

     1,位置参数
     2,默认参数,一般用于变化比较小的值

Ps:三元法则算法

#当我们用到 if  else语句时,如果可以用如下方式一句代码实现一个简单的 if else功能
z = x if x> y else y
#当满足if else中间的条件时输出左边的x ,否则输出y

 不定长参数:*args,**kwargs。

*args,即形参前面加*在形参位置,它可以接受任意长度的位置参数,并把它们放到为名args的一个元祖里。不过这里要注意,在形参里用的时候要放在默认参数的前面,而且要放在位置参数的后面,因为把它写在前面会导致写在后面的位置参数接收不到任何实参。

def func(a,b,c,*args,gender='male'):
    print(a)
    print(b)
    print(c)
    print(args)
    print(gender)
func(1,2,'aaa','sss','mhbjh',gender='ddd')
#输出:1
2
aaa
('sss', 'mhbjh')
ddd

*args

**kwargs,在形参前面加**,它可以接受任意长度的默认参数,然后把对应的默认参数放在字典里。

def func(**kwargs):
    print(kwargs)
func(a=1,b=4,c=3,d=2)
#输入:{'a': 1, 'b': 4, 'c': 3, 'd': 2}

**kwargs

形参的大致位置是,位置参数,*args,默认参数,**kwargs。不过很多时候我们用到的都是万能参数  def  func(*args,**kwargs),这样可以接收任意数量的任意形式的参数,为以后拓展功能提供了参数入口。

Ps:魔法运算:打散

当我们使用万能参数的时候,*args总是把接收的实参变成一个元组,如果在实参的前面加入一个*,那么这个实参会被迭代着加入args形成的元组,不管他是列表,元组还是字符串,甚至是字典的所有的键。这里需要注意,*和**的意思是在执行程序时把可迭代对象参数打散,接收时是把散的参数聚合。

def func2(*args,**kwargs):
    print(args)
l1 = [1,2,3]
l2 = {'a':4,'b':5,'c':6}
l3=(7,8,9)
l4='def'
func2(*l1,*l2,*l3,*l4)
#输出:(1, 2, 3, 'a', 'b', 'c', 7, 8, 9, 'd', 'e', 'f')

把 ** 加入到字典类型的形参前面,它会把实参字典中的键值对提取出来迭代着加入kwargs形成的字典中,使用时要注意两个不同的字典实参里的键不能有重复的,不然会报错。

def func3(*args,**kwargs):
    print(kwargs)
dic = {'name1':'wang','age1':998}
dic1 = {'name2':'ba','age2':99}
func3(**dic,**dic1,woai='wojia')
#输出:{'name1': 'wang', 'age1': 998, 'name2': 'ba', 'age2': 99, 'woai': 'wojia'}

参数陷阱:当默认参数是一个可变数据类型时,如列表。

def defult_param(a,l = []):
    l.append(a)
    print(l)
defult_param('abc')
defult_param('123')
#输出:['alex']
['alex', 'egon']


#这里的 l 是一个默认形参,在这里每次调用函数都应该被重置成空列表,但是列表却每一次调用函数都加了一个元素。说明这个列表的内存元素一直在改变却没有被重置。

 函数的嵌套

def f1():
    a = 1
    def f2():
        def f3():
            print(a)
        f3()
    f2()
f1()
#输出:1

 

名称空间

名称空间(命名空间)分为全局名称空间,局部名称空间和内置名称空间。

内置命名空间就是python解释器为我们提供的一些列名字,如input,len,print....等。

三种命名空间的加载顺序为:内置名称空间,全局名称空间,局部名称空间(执行函数时)。

而变量的取值顺序为:局部名称空间,全局名称空间,内置名称空间。

作用域:作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域。

全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效

局部作用域:局部名称空间,只能在局部范围生效

globals(),locals()以字典的形式显示全局和局部的全部变量

c=5
d=99
def func():
    a = 12
    b = 20
    d=88
    print(locals())
    print(globals())
func()
#输出:{'d': 88, 'b': 20, 'a': 12}
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000018EA1F2A4E0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/Pycharm10/实验用/实验三.py', '__cached__': None, 'c': 5, 'd': 99, 'func': <function func at 0x0000018EA1ED3E18>}

global和nonelocal 

global:1、声明一个全局变量   2、在局部作用域引用一个全局变量使用并改变它

#声明一个全局变量
def func():
    global a
    a = 3
func()
print(a)
#输出:3

#引用并改变一个全局变量
count = 1
def search():
    global count
    count = 2
search()
print(count)
#输出:2

global

另外,在局部引用全局中的可变数据类型列表和字典不用global

li = [1,2,3]
dic = {'a':'b'}

def change():
    li.append('a')
    dic['q'] = 'g'
    print(dic)
    print(li)
change()
print(li)
print(dic)
#输出:{'a': 'b', 'q': 'g'}
[1, 2, 3, 'a']
[1, 2, 3, 'a']
{'a': 'b', 'q': 'g'}

nonelocal:

  1,不能修改全局变量。

  2,在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从那层及以下此变量全部发生改变。

def add_b():
    b = 42
    def do_global():
        b = 10
        print(b)
        def dd_nonlocal():
            nonlocal b
            b = b + 20
            print(b)
        dd_nonlocal()
        print(b)
    do_global()
    print(b)
add_b()
#输出:10
30
30
42    #这里输出42是因为nonelocal只对它的上一级起作用。

nonelocal

 函数名的实质

函数名的实质就是函数的内存地址,

1、函数名可以赋值给其他变量

def f1():
    print('f1')
func=f1
print(func())         #首先调用函数 func(),也就是f1(),然后打印f1()的返回值
#输出:f1
None

2、函数名可以当做容器类如列表、字典等数据类型的元素

def f1():
    print('f1')
def f2():
    print('f2')
def f3():
        print('f3')
li=[f1,f2,f3]
dic={'f1':f1,'f2':f2,'f3':f3}
tu=(f1,f2,f3)
li[0]()
dic['f2']()
tu[2]()
#输出:f1
f2
f3

作为元素

3、函数名可以当做函数的参数和返回值

def f1():
    print('f1')
def func1(argv):
    argv()
    return f1
f = func1(f1)
f()
#输出:f1
f1

 Ps:函数名就是第一类变量

第一类对象(first-class object)指

1.可在运行期创建 2.可用作函数参数或返回值 3.可存入变量的实体。

闭包

内层函数对外层函数(非全局)的变量的引用,叫做闭包。

#不含参数的闭包
def wrapper():
    name = 'ming'
    def inner():
        print(name)
    inner()
    print(inner.__closure__)    # 检测是不是闭包 开头是cell 就是闭包
wrapper()
#输出:ming
(<cell at 0x0000018AA00395B8: str object at 0x0000018AA00C93B0>,)


#
name = 'ming'
def wrapper():
    def inner():
        print(name)
    inner()
    print(inner.__closure__)    # 检测是不是闭包 开头是cell 就是闭包
wrapper()
#输出:ming
None


#含特定参数的闭包
def out(x):
    def inner():
        print(x)
    inner()
    print(inner.__closure__)
out('ming')
#输出:ming
(<cell at 0x0000024B243A95B8: str object at 0x0000024B24439570>,)

#带返回值的闭包
def out():
    def inner():
        print('ming')
    return inner
out()()          #out() 在这里代表 inner 这个函数名
#输出:ming

闭包的用处:如果说内存函数是个闭包,python内部有一个机制,遇到闭包,python会在内存中开启一个内存空间,且不会随着函数的结束而关闭,这样可以保护内存。

装饰器

装饰器是在不改变函数的原来内容的情况下,为函数增添额外的功能的一种函数方式

#简单的装饰器         在不改变函数func的情况下,测得函数运行时间   
import time              #调用time类
def func():
    print('我爱中国')
def timmer(f):
    def inner():
        start_time = time.time()          #记录开始时间
        time.sleep(0.1)                       #程序延时0.1秒
        f()                                         #执行函数
        end_time = time.time()           #记录程序结束时间
        print('----> 执行时间%s' % (end_time - start_time))      #打印程序运行时间
    return inner
func = timmer(func)  #这里的func相当于 inner
func() #这一句相当于 inner()    
#输出:
我爱中国
----> 执行效率0.10044384002685547


@语法糖使用结构:
装饰器
@装饰器的函数名
要被装饰的函数

import time
def timmer(f):
    def inner(*args,**kwargs):        #推荐使用万能参数
        start_time = time.time()
        time.sleep(0.1)
        ret = f(*args,**kwargs)       #推荐使用万能参数
        end_time = time.time()
        print('----> 执行效率%s' % (end_time - start_time))
        return ret           #返回值
    return inner         #返回inner的函数名
@timmer  # 语法糖  相当于func = timmer(func)
def func(a):        #被装饰的函数
    return 222
print(func('abc'))
#输出:----> 执行效率0.10044264793395996
222


#通用装饰器
def wrapper(func):
    def inner(*args,**kwargs):
        '''执行函数前操作'''
        ret = func(*args,**kwargs)
        '''执行函数后的操作'''
        return ret
    return inner

@wrapper
def func():
    print(66)
func()

 带参数的额装饰器:当我们需要装饰大量函数时,可通过带参数的装饰器来控制装饰器的开关。

# 带参数的装饰器
import time
flag = False                 #相当于装饰器的开关,当为True时装饰,False则不对函数进行装饰操作
def timmer_out(f):
    def timmer(func):
        def inner(*args,**kwargs):
            '''执行函数前操作'''
            if flag:                       #判断flag的内容来决定是否装饰
                start_time = time.time()
                time.sleep(0.3)
                ret = func(*args,**kwargs)
                '''执行函数后操作'''
                end_time = time.time()
                print('执行效率%s'%(end_time - start_time))
                return ret
            else:
                ret = func(*args,**kwargs)
                return ret
        return inner
    return timmer
@timmer_out(flag)  # 1, timmer_out(flag)  返回 timmer  --->
def f1():         # 2,  @timmer 就是你认识的装饰器 f1 = timmer(f1)
    print(666)
@timmer_out(flag)  # f2 = timmer(f2)
def f2():
    print(777)
f1()
f2()

#输出:666
           777

带参数的装饰器

def outer(flag):
    def timer(func):
        def inner(*args,**kwargs):
            if flag:
                print('''执行函数之前要做的''')
            re = func(*args,**kwargs)
            if flag:
                print('''执行函数之后要做的''')
            return re
        return inner
    return timer

@outer(False)
def func():
    print(111)

func()

控制装饰器开关的另一种方法

 多个装饰器装饰一个函数时:

def wrapper1(func):  # func = f
    def inner1():
        print('wrapper1 ,before func')
        func()
        print('wrapper1 ,after func')
    return inner1

def wrapper2(func):  # func = inner1
    def inner2():
        print('wrapper2 ,before func')
        func()
        print('wrapper2 ,after func')
    return inner2

@wrapper2     # f = wrapper2(f)  里面的f == inner1   外面的f = inner2
@wrapper1     # f = wrapper1(f)  返回inner1    f = inner1
def f():
    print('in f')
f()  # inner2()

#输出:wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func

多个装饰器装饰一个函数 

开放封闭原则

1、开放功能扩展:对以后的产品升级和功能扩展开放

2、封闭函数修改:在一个函数交付使用后,对它的改变可能引起连锁的影响使用这个函数的代码。

而装饰器完美的契合了以上开放封闭。

获取函数的有用信息

def f1():
    '''
    本函数的功能:绘图功能,实时接收数据并绘图.
    return: 返回值
    '''
    print(f1.__doc__)
    print(f1.__name__)
    print(666)
print(f1.__doc__)  #获取函数的说明信息
print(f1.__name__)  # 获取函数的名字
f1()
#输出:    本函数的功能:绘图功能,实时接收数据并绘图.
    return: 返回值
    
f1

    本函数的功能:绘图功能,实时接收数据并绘图.
    return: 返回值
    
f1
666

获取函数名和注释内容

def wrapper(func):
    def inner(*args,**kwargs):
        '''执行函数前进行的操作'''
        ret = func(*args,**kwargs)
        '''执行函数后进行的操作'''
        return ret
    return inner

@wrapper                  
def f1():
    '''
    本函数的功能:绘图功能,实时接收数据并绘图.
    :return: 绘图需要的数据,返回给前端某标签
    '''
    print(f1.__doc__)
    print(f1.__name__)      ##这里我们想得到f1函数的信息,但是却得到了inner函数的信息
f1()
#输出:执行函数前进行的操作
inner


#下面调用funcrools的wraps模块输出f1的函数信息
from functools import wraps
def wrapper(func):
    @wraps(func)
    def inner(*args,**kwargs):
        '''执行函数前进行的操作'''
        ret = func(*args,**kwargs)
        '''执行函数后进行的操作'''
        return ret
    return inner
@wrapper
def f1():
    '''
    本函数的功能:绘图功能,实时接收数据并绘图.
    return: 绘图需要的数据,返回给前端某标签
    '''
    print(f1.__doc__)
    print(f1.__name__)
f1()

#输出:
    本函数的功能:绘图功能,实时接收数据并绘图.
    return: 绘图需要的数据,返回给前端某标签
    
f1

装饰器获取原函数信息

 生成器和迭代器

迭代器

判断可迭代对象和迭代器的方法一:

1、dir(被测对象)  如果它含有 __iter__而不含__next__,那么这个对象就是可迭代对象不是迭代器

2、dir(被测对象)  如果它既含有 __iter__又含有__next__,那么这个对象就是迭代器

a = 'abcdef'
b = (x*x for x in range(1,10))   #等号右边类似一个列表生成器,[x*x for x in range(10)]
print('__iter__' in dir(a))
print('__next__' in dir(b))
print('__next__' in dir(a))
print('__next__' in dir(b))
#输出:
True
True
False
True

#这说明a是可迭代对象不是迭代器,b是迭代器

迭代器和迭代对象判断方法一

方法二:

引用模块判断

from collections import Iterable
from collections import Iterator

a = 'abcdef'
b = (x*x for x in range(1,10))   #等号右边类似一个列表生成器,[x*x for x in range(10)]
print(isinstance(a,Iterable))     #检测是否是可迭代对象
print(isinstance(a,Iterator))     #检测是否是迭代器
print(isinstance(b,Iterable))
print(isinstance(b,Iterator))
#输出:
True
False
True
True

方法二

可迭代对象可以改变成迭代器

from collections import Iterable
from collections import Iterator
list=[1,2,3,4,5]
print(isinstance(list,Iterable))
print(isinstance(list,Iterator))
list=iter(list)                           #将可迭代对象 list 变换成迭代器。

#list=list.__iter__()  这句和上句效果一样
print(isinstance(list,Iterable))
print(isinstance(list,Iterator))

可迭代对象转换成迭代器

迭代器取值,__next__和next。因为迭代器是惰性的,每次调用只能取一个值

list=[1,2,3,4,5]
list=list.__iter__()

print(next(list))      #通过next(迭代器对象)取值
print(list.__next__())   #通过__next__对迭代器取值
print(next(list))
print(list.__next__())
print(next(list))
print(list.__next__())      #这一句时超出迭代器的取值范围,会报StopIteration的错误

#输出:
1
2
3
4
5
StopIteration的错误

迭代器取值

迭代器的意义:
1,迭代器节省内存。
2,迭代器惰性机制。
3,迭代器不能反复,一直向下执行.

for循环的机制.
内部含有__iter__方法,他会将可迭代对象先转化成迭代器.
,然后在调用__next__方法.
他通过 try...ecpect 语句处理异常。

可迭代对象:str list tuple dict set range
迭代器: 文件句柄 

生成器

生成器的本质就是迭代器,生成器是自己用python代码写的迭代器.\
1,可以用生成器函数。
2,可以用各种推导式构建迭代器。
3,可以通过数据转化,将写的列表生成器的[]换成(),或者通过 iter 语句转换。list(),tuple()语句将生成器对象转化,一般不这样用,因为当数据量大时,会占用大量内存。

#生成器函数
def gener():
    print('aaa')
    yield 222
    print('bbb')
    yield 333
    print('ccc')
g = gener()
print(next(g))     #调用函数运行到第一个yield
print(next(g))     #调用函数运行到第二个yield
#输出:
aaa
222
bbb
333

生成器构建

send和next函数

1,send 和next功能一样
2, 给上一个yiled和后面的值 整体发送一个值
send不能给最后一个yield发送值
获取第一个值的时候,不能用send 只能用next

def gener():
    yield 222
    count = yield 333
    print('-------->',count)
    yield 'aaa'
    yield 'bbb'
g = gener()
print(g.send(None))
print(g.send('AAAA'))
print(g.send('wwwwww'))

#输出:
222
333
--------> wwwwww
aaa

send

 列表生成式:

1、1到10的所有数的平方

l1=[x*x for x in range(1,11)]

2、1到10的所有数的平方是偶数的数(加判断)

l1=[x*x for x in range(1,11) if x%2==0]

3、找到嵌套的列表中含有两个‘m’的元素(双层循环)

li=[['11','ming','jiang','qqq','sss','misimy'],['mm','gg','mim','ss','mhom']]
l1=[x for i in li for x in i if x.count('m')==2]    
print(l1)
#输出:
['misimy', 'mm', 'mim', 'mhom']

列表生成式和生成器表达式的区别:

1、列表生成式比较直观,占用内存;

2、生成器表达式不容易看出内存,省内存。

字典生成式:

将字典的key和value对调

dic = {'a':11,'b':22}
dic1 = {dic[k]:k for k in dic}
print(dic1)
#输出:
{11: 'a', 22: 'b'}

集合生成式:

计算每个值的平方并去重

set1 = {x*x for x in [1,-1,2,-2]}
print(set1)
#输出:
{1, 4}

内置函数

range(),input(),len(),print(),dir(),max(),min()等python内置函数,

#print()

print(1234)
print(5,6,7,8)
print(1234,end='')        #print默认在后面加入‘\n’,此处为将换行符换为空
print(5,6,7,8,sep='*')    #print可以在输出元素之间插入符号,默认是空格
#输出:
1234
5 6 7 8
12345*6*7*8
#print还可以往文件里写入,操作如下
f = open('file','w',encoding='utf-8')
print(666,file=f)
f.close()


#dir() 查找对象的所有方法
# print(dir([]))

#locals()  将局部的变量储存起来
#globals() 将全局的变量,函数名,等等 储存起来.
#数据类型的转换 list() str() tuple() set() dict() int()
# help(str) 将你查询的对象所有信息都拿出来.
# abs()取绝对值     
#max()最大值,可设置函数
# ret = max(1,2,-3,key=abs)
# print(ret)    #输出:-3   绝对值最大的数
#min()最小值
#sum (iterable,初始值)
# ret = sum([1,2,3],10)
# print(ret)      #输出:16
#hash() 通过哈希表的规则,将对象转换成哈希值
#print(hash('fdsakf'))
#十进制转化成二进制
# print(bin(100))
# #将十进制转化成八进制
# print(oct(9))
# #将十进制转化成十六进制
# print(hex(33))
#float  :有限小数,无线循环小数,不包含(无线不循环小数)
# print(1.35432,type(1.35432))
# print(float(3))
#divmod() 分页
# print(divmod(7,2)) #(商,余数)
#complex()复数

#enumerate(iterable,start 起始值) 枚举
# l = ['手机','电话']
# for i in enumerate(l):
#     print(i)

s = "{'name':'alex'}"
s1 = "1+2+3+4"
#eval 有返回值 除去字符串两边的引号,返回里面的内容
#exec 没有返回值 除去字符串两边的引号,执行里面的代码

内置函数 

内置函数链接: http://www.runoob.com/python/python-built-in-functions.html

 filter:在return语句中写判断语句时,返回的是原参数,而不是True和False