整理------函数

函数参数顺序

位置参数 > *args > 默认值参数 > **kwargs
 
动态参数的另一种传参方式  :  在实参位置上给一个序列,列表,可迭代对象前面加个*表示把这个序列按顺序打散
l = [11,22,33,44]
s = "臣妾做不到"
def fun(*args):
    print(args)     
fun(*l)       #fun打印结果为:      (11, 22, 33, 44)
fun(*s)       #fun打印结果为:     ('臣', '妾', '做', '不', '到')
在形参的位置上的* 表示把接收到的参数组合成一个元组
如果是一个字典, 那么也可以打散. 不过需要用两个*
def fun(**kwargs):
    print(kwargs)
dic = {'a':1, 'b':2}
fun(**dic)      #   {'a': 1, 'b': 2}
函数的注释:
def chi(food, drink):
"""
这里是函数的注释, 先写一下当前这个函数是干什么的, 比如我这个函数就是一个吃
:param :param food: 参数food是什么意思
:param :param drink: 参数drink是什么意思
:return :return: 返回的是什么东东
 """
print(food, drink)
return "very good"
命名空间
在python解释器开始执行之后, 就会在内存中开辟一个空间, 每当遇到一个变量的时候, 就把变量名和值之间的关系记录下来, 但是当遇到函数定义的时候, 解释器只是把函数名读入内存, 表示这个函数存在了, 至于函数内部的变量和逻辑, 解释器是不关心的. 也就是说一开始
的时候函数只是加载进来, 仅此而已, 只有当函数被调用和访问的时候, 解释器才会根据函数内部声明的变量来进行开辟变量的内部空间. 随着函数执行完毕而被清空.


命名空间分类:
1. 全局命名空间--> 我们直接在py文件中, 函数外声明的变量都属于全局命名空间
2. 局部命名空间--> 在函数中声明的变量会放在局部命名空间
3. 内置命名空间--> 存放python解释器为我们提供的名字, list, tuple, str, int这些都是内置命名空间
加载顺序:
1. 内置命名空间
2. 全局命名空间
3. 局部命名空间(函数被执行的时候)
取值顺序:
1. 局部命名空间
2. 全局命名空间
3. 内置命名空间
我们可以通过globals()函数来查看全局作用域中的内容, 也可以通过locals()来查看局部作
用域中的变量和函数信息
print(globals())    #{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00466590>, '__spec__': None, 
            '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:/Users/ZYP/PycharmProjects/python_ui/test_tools/test.py', '__cached__': None}
def func(): a = 10 print(locals()) #{'a': 10} func()
对于可变数据类型可以直接进行访问. 但是不能改地址. 说白了. 不能赋值
l = [11,22,33,44]
def fun():
    l.append(55)
    print(l)    #      [11, 22, 33, 44, 55]
fun()
print(l)         #      [11, 22, 33, 44, 55]

 

a = 2
def w():
    a +=1
    print(a)
w()      #报错,不能赋值
迭代器
闭包
闭包就是内层函数, 对外层函数(非全局)的变量的引用. 叫闭包
def func1():
  name = "zyp"
  def func2():
    print(name) # 闭包
  func2()
func1()
结果:
zyp
我们可以使用__closure__来检测函数是否是闭包. 使用函数名.__closure__返回cell就是闭包. 返回None就不是闭包
def func1():
    name = "zyp"
    def func2():
        print(name) # 闭包
    func2()
    print(func2.__closure__)
func1()
结果:
zyp
闭包的作用就是让一个变量能够常驻内存. 供后面的程序使用
 
生成器和迭成器表达式
生成器
什么是生成器.生成器其实就是迭代器
在python中有三种方式来获取生成器:
1. 通过生成器函数
2. 通过各种推导式来实现生成器
3. 通过数据的转换也可以获取生成器
def func():
print("111")
return 222
ret = func()
print(ret)
结果: 
111
222
将函数中的return换成yield就是生成器
def func():
print("111")
yield 222
ret = func()
print(ret)
结果: 
<generator object func at 0x10567ff68>
运行的结果和面⾯不一样. 为什么呢. 由于函数中存在了yield. 那么这个函数就是一个生成器函数. 这个时候. 我们再执行这个函数的时候. 就不再是函数的执行了. 而是获取这个生成器我们可以直接执行__next__()来执行以下生成器.
def func():
    print("111")
    yield 222
ret = func()
print("ret",ret)
a = ret.__next__()
print("a",a)

结果
ret <generator object func at 0x0209AF60>
111
a 222
那么我们可以看到, yield和return的效果是一样的. 有什么区别呢? yield是分段来执行一个函数. return呢? 直接停止执行函数.
def func():
print("111")
yield 222
print("333")
yield 444
gener = func()
ret = gener.__next__()
print(ret)
ret2 = gener.__next__()
print(ret2)
ret3 = gener.__next__() # 最后⼀个yield执⾏完毕. 再次__next__()程序报错, 也就是
说. 和return⽆关了.
print(ret3)
结果:
111
Traceback (most recent call last):
222
333
File "/Users/sylar/PycharmProjects/oldboy/iterator.py", line 55, in
<module>
444
ret3 = gener.__next__() # 最后⼀个yield执⾏完毕. 再次__next__()程序报错, 也
就是说. 和return⽆关了.
StopIteration
当程序运行完最后一个yield. 那么后面继续进行__next__()程序会报错.
生成器有什么作用呢?
占内存少,用多少取多少
send和__next__()⼀样都可以让生成器执行到下一个yield.
def eat():
    print("我吃什么啊")
    a = yield "馒头"
    print("a=",a)
    b = yield ""
    print("b=",b)
    c = yield "菜盒"
    print("c=",c)
    yield "GAME OVER"
gen = eat() # 获取⽣成器
ret1 = gen.__next__()
print(ret1)
ret2 = gen.send("胡辣汤")
print(ret2)
ret3 = gen.send("狗粮")
print(ret3)
ret4 = gen.send("猫粮")
print(ret4)


结果
我吃什么啊
馒头
a= 胡辣汤
饼
b= 狗粮
菜盒
c= 猫粮
GAME OVER
send和__next__()区别:
1. send和next()都是让生成器向下走一次
2. send可以给上面个yield的位置传递值, 不能给最后一个yield发送值. 在第一次执行生成器代码的时候不能使用send()

列表推导式, 生成器表达式以及其他推导式
列表推导式
lst = [i for i in range(1, 15)]
print(lst)
常用写法:
[ 结果 for 变量 in 可迭代对象]

我们还可以对列表中的数据进行筛选筛选模式:
[ 结果 for 变量 in 可迭代对象 if 条件 ]
# 获取1-100内所有的偶数
lst = [i for i in range(1, 100) if i % 2 == 0]
print(lst)
生成器表达式和列表推导式的语法基本上是一样的. 只是把[]替换成()
gen = (i for i in range(10))
print(gen)
结果: 
<generator object <genexpr> at 0x106768f10>
打印的结果就是一个⽣生成器. 我们可以使用for循环来循环这个生成器:
for i in gen:
print(i)
生成器表达式也可以进行筛选:
# 获取1-100内能被3整除的数
gen = (i for i in range(1,100) if i % 3 == 0)
for num in gen:
print(num)
生成器表达式和列表推导式的区别:
1. 列表推导式比较耗内存. 一次性加载. 生成器表达式几乎不占用内存. 使用的时候才分
配和使用内存
2. 得到的值不一样. 列表推导式得到的是一个列表. 生成器表达式获取的是个生成器

深坑==> 生成器. 要值得时候才拿值.

字典推导式:
dic = {"a":1,"b":2}
new_dic = {dic[key]:key for key in dic}
print(new_dic)   #{1: 'a', 2: 'b'}
lst1 = ['11', '22', '33']
lst2 = ['aa', 'bb', 'cc']
dic = {lst1[i]:lst2[i] for i in range(len(lst1))}
print(dic)   #{'11': 'aa', '22': 'bb', '33': 'cc'}
集合推导式:
集合推导式可以帮我们直接生成一个集合. 集合的特点: 无序, 不重复. 所以集合推导式自带去重功能
lst = [1, -1, 8, -8, 12]
s = {abs(i) for i in lst}    #绝对值abs
print(s)   #  {8, 1, 12}
总结: 推导式有, 列表推导式, 字典推导式, 集合推导式, 没有元组推导式
 
 
 
 
 
 
posted @ 2019-07-29 10:39  Aline2  阅读(159)  评论(0编辑  收藏  举报