Python


一. 函数名的运用

  • 函数名的内存地址
def func():
    print("呵呵")
print(func)

结果:
<function func at 0x1101e4ea0>

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

def func():
    print("123")
print(func)
a = func    #把函数当成一个变量赋值给另一个变量
a() # 函数调用func()

2.函数名可以当做容器类的元素(列表 lst)

def func1():
    print("hehe")
def func2():
    print("hehe")
def func3():
    print("hehe")

lst = [func1,func2,func3]
for i in lst:
    i()

3.函数名可以当做函数的参数

def func():
    print("123")

def func1(fn):
    print("我是func2")
    fn()    #执行传递过来的fn
    print("这里是函数1")
func2(func) #把函数func当成参数传递func2的参数fn

4.函数名可以作为函数的返回值

def func_1():
    print("这⾥是函数1")
    def func_2():
    print("这⾥是函数2")
    print("这⾥是函数1")
    return func_2

fn = func_1() # 执⾏函数1. 函数1返回的是函数2, 这时fn指向的就是上⾯函数2
fn() 

二. 闭包

  • 闭包就是内层函数对外层函数 (非全局) 的变量的引用
  • 内部函数访问外部函数的局部变量
  • 我们可以使用closure__来检测函数是否是闭包,使用函数名__closure 返回cell 就是闭包,返回None就不是闭包
def func1():
    name = "alex"     #常驻内存,防止其他程序改变这个变量
    def func2():
        print(name)    #在内层函数中调用了外层函数的变量,叫闭包,可以让局部变量常驻内存
    return func2
ret= func1()
ret() #执行的就是func2
结果:
alex
  • 闭包的好处

    1.安全

    2.常驻内存,提高效率

from urllib.request import urlopen


def but():
    content = urlopen("http://www.h3c.com/cn/").read()

    def inner():
        return content  # 再函数内部使用了外部的变量.闭包
    #print(inner.__closure__) #查看inner是否是闭包,有东西就是闭包,返回None 就不是闭包
    return inner


fn = but()
content = fn() #获取内容
print(content)
content1 = fn() #重新获取内容
print(content1)

三. 迭代器

​ 1.可迭代对象(Iterable): 内部包含iter () 方法

​ 2.迭代器(Iterator): 内部包含iter() next()

​ 3.可迭代对象: str list tuple set f文件句柄 dict

​ 4.可以使用dir函数来查看类中定义好的方法

s = "哈哈哈"
print(dir(s)) #可以打印对象中的方法和函数
print(dir(str)) #也可以打印类中声明的方法和函数

打印结果中如果有__iter__()函数 则表示是可迭代对象
# 模拟for 循环

lst = ["as", "aa", "bb"]

it = lst.__iter__()  # 拿到迭代器

while 1:
    try:
        name = it.__next__()  # 拿元素
        print(name)
    except StopIteration:  # 拿完了
        break
lst = [1,2,3]

from collections.abc import Iterable #可迭代的 #记得加abc 不然会有warning
from collections.abc import Iterator #迭代器

#isintance (对象,类型) 判断xx对象是否是xx类型的
print(isinstance(lst,Iterable))
print(isinstance(lst,Iterator))

it = lst.__iter__() #获取迭代器
print(isinstance(it,Iterable)) #判断是否可迭代的,迭代器一定是可迭代的
print(isinstance(it,Iterator)) #迭代器里面一定有 __iter__() 和 __next__()

print("__iter__"in dir(lst)) #确定是一个可迭代的
print("__next__" in dir(lst)) #确定不是一个迭代器

f = open("今日内容大纲",mode="r",encoding="utf-8") # 文件句柄 是可迭代的也是一个迭代器

print(isinstance(f,Iterable))
print(isinstance(f,Iterator))
  • 用isintance(对象,类型) 来判断对象是否是什么类型

总结:

​ iterable : 可迭代对象,内部包含iter()函数

​ iterator : 迭代器 内部包含iter() 和next() 函数

  • 迭代器的特点:

    1.节省内存

    ​ 2.惰性机制

    ​ 3.不能反复,只能向下执行

四.生成器和生成器表达式

​ 1.生成器

​ 生成器的本质就是迭代器

​ 在Python中有三种方式来获取生成器:1.通过生成器函数 2.通过各种推导式来实现生成器 3.通过数据的转换也可以获取生成器

  • 简单的example
def func():
    print("我是:")
    yield "99" #当函数中有了yield 就不是普通的函数了,是生成器函数
    print("你是?")
    yield "88"
    print("它是?")
    yield "77"
    print("6666?") #最后一个yield之后如果还执行__next__() 就会报错
g = func() # 拿到的是生成器.生成器的本质是迭代器,迭代器可以被迭代,生成器直接可以 for 循环 
print(g.__next__())

​ return 直接返回结果,结束函数的调用

​ yield 返回结果, 可以让函数分段执行

def func():
    yield 11
    yield 13
    yield 12

g = func() # 拿到的是生成器. 生成器的本质是迭代器. 迭代器可以被迭代 生成器可以直接for循环.

for i in g:
    print(i)  # 本质上执行的是 __next__()

it = g.__iter__()
while 1:
    try:
        print(it.__next__())
    except StopIteration:
        break

​ send() 方法

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)

send() 和 next()的区别:

1. send 和 next() 都是让生成器向下走一次
 2. send 可以给上一个yield的位置传递参数, 不能给最后一个yield发送值,在第一次执行生成器的时候不能使用send()

​ 4.生成器表达式

​ 生成器表达式和列表推导式差不多 只是把[] 替换成()

gen = (i for i in range(18))
print(gen)

结果: <generator object <genexpr> at 0x106768f10>

​ 打印的结果就是一个生成器, 我们可以使用 for 循环 来循环这个生成器:

gen = ("麻花藤我第%s次爱你" % i for i in range(10))
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)

# 100以内能被3整除的数的平⽅
gen = (i * i for i in range(100) if i % 3 == 0)
for num in gen:
     print(num)

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

# 不⽤推导式和表达式
result = []
for first in names:
     for name in first:
         if name.count("e") >= 2:
             result.append(name)
print(result)

# 推导式
gen = (name for first in names for name in first if name.count("e") >= 2)
for name in gen:
     print(name)

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

​ 1. 列表推导式比较耗内存,一次性加载, 生成器表达式几乎不占用内存, 使用的时候才分配和使用内存

​ 2. 得到的值不一样, 列表推导式得到的一个列表 , 生成器表达式获取的是一个生成器

​ 生成器的惰性的机制: 生成器只有在访问的时候才取值, 说白了 , 你找他要他才给值, 不找他,他不执行

def func():
     print(111)
     yield 222
g = func() # ⽣成器g
g1 = (i for i in g) # ⽣成器g1. 但是g1的数据来源于g
g2 = (i for i in g1) # ⽣成器g2. 来源g1

print(list(g)) # 获取g中的数据. 这时func()才会被执⾏. 打印111.获取到222. g完毕.
print(list(g1)) # 获取g1中的数据. g1的数据来源是g. 但是g已经取完了. g1 也就没有数据
了
print(list(g2)) # 和g1同理

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

五. 推导式

​ 1. 列表推导式

​ 列表推导式的常用写法

​ [结果 for 变量 in 可迭代对象]

​ 例. 从Python1 期到Python 141期 写入列表lst:

lst = ['python%s' %i for i in rang(1,15)]
print(lst)
lst = []
for i in range(1,15):
    lst.append(i)
pirnt(lst)

替换成列表推导式
lst = [i for i in rang(1,15)]
print(lst)

​ 列表推导式是通过一行来构建你要的列表, 列表推导式看起来代码简单,但出错后很难排查

​ 2. 字典推导式(推导出来的字典)

# 把字典中的key和value互换
dic = {'a': 1, 'b': '2'}
new_dic = {dic[key]: key for key in dic}
print(new_dic)

# 在以下list中. 从lst1中获取的数据和lst2中相对应的位置的数据组成⼀个新字典
lst1 = ['jay', 'jj', 'sylar']
lst2 = ['周杰伦', '林俊杰', '邱彦涛']
dic = {lst1[i]: lst2[i] for i in range(len(lst1))}
print(dic)

 3. 集合推导式
      1. 集合推导式可以帮我们直接生成一个集合, 集合的特点: 无序,不重复. 所以集合推导式自带去重功能
lst = [1, -1, 8, -8, 12]
# 绝对值去重
s = {abs(i) for i in lst}
print(s)

总结: 推导式 有, 列表推导式,字典推导式, 集合推导式,没有元组推导式

​ 生成器表达式: (结果 for 变量 in 可迭代对象 if 条件筛选)

​ 生成器表达式可以直接获取生成器对象, 生成器对象可以直接进行 for 循环 生成器具有惰性机制

六. 难度系数很高的面试题

def add(a, b):
    return a + b

def gen():
    for r_i in range(4):
         yield r_i

g = gen()

for n in [2, 10]:
    g = (add(n, i) for i in g)
print(list(g))

友情提⽰: 惰性机制, 不到最后不会拿值


Author: 二哈君
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source 二哈君 !
 Previous
Python Python
一.面向对象的初始​ 1.类 : 具有相同属性和技能的一类事物 ​ 2.对象 : 具体类的表现, 具体的实实在在的一个实例 ​ class Person: ''' 类体:两部分: 变量部分
2020-10-13 二哈君
Next 
Python Python
一.冒泡排序# 冒泡排序 lst = [11, 22, 35, 6, 2] for i in range(len(lst)): i = 0 while i < len(lst) - 1: if lst[
2020-09-25 二哈君
  TOC