python成长之路七-函数的进阶

1,python中,名称空间分三种:

  1. 全局命名空间

  2. 局部命名空间(临时命名空间)

  3. 内置名称空间

 

2,作用域(两种):

   1,全局作用域  包含:全局名称空间   内置名称空间

   2,局部作用域  包含:局部命名空间

 

  2.1,取值顺序:

    就近原则:局部名称空间 --> 全局名称空间 --> 内置名称空间   单向从小到大范围

  2.2, 加载顺序:

    内置名称空间 --> 全局名称空间(当程序执行时) -- > 局部名称空间(当函数调用的时候)

 

3,函数的嵌套:

  

def func1():
    print(111)
def func2():
    print(222)
    func1()
    print(333)
print(666)
func2()
print(555)
例子1
def func1():
    print(222)
    def func2():
        print(333)
    print(111)
    func2()
    print(666)
func1()

# 执行结果:
222 111 333 666
例子2

 

4,global   nonlocal

  局部名称空间对全局名称空间的变量可以引用,但是不能改变。

count = 1
def func1():
    count = 2
    print(count)
func1()
count = 1
def func1():
    # count = 3
    count = count + 1  # local variable 'count' referenced before assignment
    print(count)
func1()
报错

报错原因: 如果你在局部名称空间 对一个变量进行修改,那么解释器会认为你的这个变量在局部中已经定义了,但是对于上面的例题,局部中没有定义,所以他会报错,

 

  global

    1,在局部名称空间声明一个全局变量。

声明

    2,在局部名称空间声明可以对全局变量进行修改。

count = 1
def func1():
    global count
    count = count + 1
    print(count)
func1()
print(count)
修改

 

  nonlocal

    1,子函数对父函数的变量进行修改。

    2,此变量不能是全局变量

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

def func1():
    count = 666
    def inner():
        print(count)
        def func2():
            nonlocal count
            count += 1
            print("func2",count)
        func2()
        print("inner",count)
    inner()
    print("funcl",count)
func1()

# 运行结果:
666
func2 667
inner 667
funcl 667
global

 

5,函数的应用

  1,函数名就是函数的内存地址。

def func():
    pass
print(func) # <function func at 0x05958660>
View Code

  2,函数名可以作为变量。

def func1():
    print(666)
f1 = func1
f2 = f1
f2()
View Code

  3,函数名可以作为函数的参数。

def func():
    print(666)
def func1():
    func()
def func2(x):
    x()
func2(func1)
View Code

  4,函数名可以当作函数的返回值。

def wraaper():
    def inner():
        print("inner")
    return inner
ret = wraaper()
ret()
View Code

  5,函数名可以当作为容器类类型的元素。

def func1():
    print("in func1")
def func2():
    print("in func2")
def func3():
    print("in func3")
def func4():
    print("in func4")
l1 = [func1,func2,func3,func4]
for i in l1:
    i()
View Code

     向上面的函数名这种,第一个类对象。

 

6,globals()   locals()

  1,globals()  返回全局变量的一个字典。

  2,locals()   返回当前位置的局部变量的字典。

def funcl():
    a = 2
    b = 3
    # print(globals())
    # print(locals())
    def inner():
        c = 5
        d = 6
        print(globals())
        print(locals())
    inner()
print(globals())
print(locals())
funcl()
View Code

 

7,闭包

    --内层函数对外层函数的变量(非全局变量)的引用,并返回。这样就形成了闭包。

  1,迭代器的条件:

      1,必须要有函数嵌套。

      2,内层函数必须要引用外层函数中的变量(不能是全局变量)。

      3,外层函数必须返回内部中的函数名(引用)。
    
def wraaper():
    n = 1
    def inner():
        nonlocal n
        n += 1
        return n
    # inner()
    return inner
f = wraaper()
print(f())
print(f())
闭包

  2,闭包的作用:

      当程序执行时,遇到了函数执行,他会在内存开辟一个空间,局部名称空间,

      如果这个函数内部形成了闭包,

      那么他就不会随着函数的结束而消失。

 

# 1,写装饰器的时候用。
# 2,写爬虫的时候用。


from urllib.request import urlopen

def index():
    url = "http://www.xiaohua100.cn/index.html"
    def get():
        return urlopen(url).read()
    return get

xiaohua = index()  # get
content = xiaohua()  # get()
content = xiaohua()  # get()
print(content.decode('utf-8'))
作用

 

8,迭代器

  1,可迭代对象

    对象内部含有__iter__方法的就是可迭代对象。

    可迭代对象满足可迭代协议。

  2,判断是否是可迭代对象。

    

dic = {"name":"alex"}
print('__iter__' in dir(dic))
方法一
from collections import Iterable
from collections import Iterator
print(isinstance("alex",Iterable))
print(isinstance('alex',Iterator))
print(isinstance("alex",str))
方法二

  3,可迭代对象 vs 迭代器

    可迭代对象不能取值,迭代器是可以取值的。

    可迭代对象 可以转化成迭代器。

 

lis = [1,2,3]  # 可迭代对象
itet = lis.__iter__()  #迭代器
itet = iter(lis)  # 迭代器
print(itet)
View Code

    可迭代器如何取值?

      next一次,取值一次

      1,可迭代对象不能取值,迭代器是可以取值的。

      2,迭代器非常节省内存。

      3,迭代器每次只会取一个值。

      4,迭代器是单向的从上至下地取值,一条路走到头。

    1,迭代器原理

      1,将可迭代对象转化成迭代器。

      2,调用__next__方法取值。

      3,利用异常处理停止报错。

 

s1 = "asdfg"
iter1 = s1.__iter__()
while 1:
    try:
        print(iter1.__next__())
    except StopIteration:
        break
View Code
s1 = "asdfg"

# l1 = [i for i in range(100)]
# print(11)

ret = (i for i in range(10000))
print(ret.__next__())
print(ret.__next__())
print(ret.__next__())
View Code

 

9, 生成器

    --就是自己python用代码写的迭代器,生成器的本质就是迭代器。

  1,构建一个生成器的两种方式:

      1,通过生成器函数。

      2,生成器表达式。

   生成器函数:

def func1(x):
    x += 1
    return x
func1(5) # 函数的执行命令,并且接受函数的返回值
print(func1(5))
函数
def func1(x):
    x += 1
    print(111)
    print(111)
    print(111)
    yield x
    x += 2
    print(222)
    yield "alex"
    x += 3
g_obj = func1(5) # 生成器函数对象
# print(g_obj)
# print(g_obj.__next__())
print(g_obj.__next__())
生成器函数

    一个 naxt 对应一个 yield

    yield 将值返回给生成器对象 .__next__()

    yield 和 return区别

    return 结束函数,给函数的执行者返回值

    yield  不会结束函数,一个next 对应一个yield,给生成器对.__next__()返回值。

    

    生成器函数 和 迭代器 区别

      1,自定制的区别

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

def func1(x):
    x += 1
    yield x
    x += 3
    yield x
    x += 5
    yield x
g1 = func1(5)
print(g1.__next__())
print(g1.__next__())
print(g1.__next__())
区别1

      2,内存级别的区别

      迭代器是需要可迭代对象进行转化。可迭代对象非常占内存。

      生成器直接创建,不需要转化,从本质就节省内存。

 

def func1():
    for i in range(10000):
        yield i

g1 = func1()
for i in range(50):
    print(g1.__next__())

# ————————————————————————
def func1():
    print(1)
    count = yield 6
    print(count)
    print(2)
    count1 = yield 7
    print(count1)
    print(3)
    yield 8

g = func1()
next(g)
g.send("alex")
# g.send("太白")
print(g.__next__())
区别二

    

     send   与   naxt   区别

      send与next一样,也是对生成器取值(执行一个yield)的方法。

      send可以给上一个yield传值。

      第一次取值永远都是next。

      最后一个yield永远也得不到send传的值。

 

# 函数
def cloth1(n):
    for i in range(n+1):
        print("衣服%s号" % i)
cloth1(1000)
# --------------------------------
# 生成器函数
def cloth1(n):
    for i in range(1,n+1):
        yield ("衣服%s号" % i)
g = cloth1(1000)
for i in range(50):
    print(g.__next__())
# for i in range(50):
#     print(g.__next__())
函数 vs 生成器

 

   列表推导式:

      -- 一行代码几乎搞定你需要的任何的列表。

      优点:一行解决,方便

      缺点:容易着迷,不易排错,不能超过三次循环。

     列表推导式不能解决所有列表问题,所以不要太刻意用。

    循环模式   [变量(加工后的变量)for 变量 initerable]

l = [i for i in range(1,101)]
print(l)

l2 = print(["python%s期" % i for i in range(1,11)])

print([i*i for i in range(1,11)])
循环模式

    筛选模式  [变量(加工后的变量)in iterable if 条件]

l3 = [i for i in range(1,31) if i % 2 == 0]
print(l3)

print([i for i in range(1,31) if i % 3 == 0])

print([i**2 for i in range(1,31) if i % 3 == 0])


names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
# 请选出名字中带两个e的

print([j for i in names for j in i if  j.count("e") == 2])
筛选模式

 

   生成器表达式: 将列表推导式的 [ ] 换成 ( ) 即可。

g = (i for i in range(100000))
print(g)
print(g.__next__())
print(g.__next__())
for i in range(20): # 循环取取值
    print(g.__next__())
生成器表达式
mcase = {"a":10,"b":34}
mcase_frequency = {mcase[k]: k for k in mcase} # 将键值对反转
print(mcase_frequency)
元组表达式
squared = {x**2 for x in [1,-1,2]} # 将集合去重
print(squared)
集合表达式

 

 

 

posted @ 2018-08-16 17:00  温而新  阅读(343)  评论(1编辑  收藏  举报