day4 内置函数 迭代器&生成器 yield总结 三元运算 闭包
2024-09-28 02:52:39
内置函数:
内置函数 # abs()返回一个数字的绝对值。如果给出复数,返回值就是该复数的模。
b = -100
print(b)
print(abs(b)) # all() 所有为真才为真,只要有一个假就是假,判断假的条件--> 假: 0,None, 以及空值(“”(空字符串), [], (), {}),都为假,其他都为真
# all(iterable), iterable -- 元组或列表。
a = None
b = []
c = {}
d = ()
e = ""
e1 = " " # 空格是字符串,所以结果为True
f = 0
print(all([e1, f])) # 输出 False print(bool(a), bool(b), bool(c), bool(d), bool(e), bool(e1), bool(f))
# 输出(False, False, False, False, False, True, False)
li = [1, 2, 3, "", False]
l = [1, 2, 3, " "]
print(all(li)) # 输出False
print(all(l)) # 输出True # bool 判断真假
val = False
r = bool('False')
r1 = bool(val)
print(r) # 输出 True
print(r1) # 输出 False
# Python中除了''、""、0、()、[]、{}、None为False之外,其他的都是True。也就是说上面的'False'就是一个不为空的字符串,所以结果就为True了,将一个值转化成布尔值,使用标准的真值测试例程。如果x为假或者被忽略它返回False;否则它返回True。bool也是一个类,它是int的子类。bool不能被继承。它唯一的实例就是False和True。 # any() 一个为真就为真 同all相反,只有有真就返回True 真: 非0 非None 非空
li = [1, 2, 3, "", False]
l = [1, 2, 3, " "]
print(any(li)) # 输出True
print(any(l)) # 输出True # ascii(),很少用到,ascii等同于repr函数 固定用法:ascii(对象) ===去类中找 __repr__ 方法,获取返回值,自动去对象对应的类里面找_repr_方法
class Foo(object):
def __repr__(self):
return "hello repr 中文" li = Foo()
n = ascii(li)
print(n)
#输出:hello repr
# 转义汉字字符
r = ascii('哈哈')
print(r) # 输出'\u54c8\u54c8' # 进制转换:bin oct int hex 二进制 八进制 十进制 十六进制
# 任意进制转10进制
i = int('0b11', base=2) # 0b可省略
print(i) # 输出:3 i = int('', base=8)
print(i) # 输出:9 i = int('0x11', base=16)
print(i) # 输出:17 # 十进制转换为其他进制
r = oct(8) # 十进制转8进制
h = hex(14) # 十进制转16进制
print(r, h) # 输出('010', '0xe') # 进制互转
# bin() 可以将 八 十 十六 进制 转换成二进制
print(bin(10), bin(0o13), bin(0x14))
# oct() 可以将 二 十 十六 进制 转换为八进制
print(oct(10), oct(0b101), oct(0x14))
# int() 可以将 二 八 十六进制转换为十进制
print(int(0o13), int(0b101), int(0x14))
# hex() 可以将 二 八 十 进制转换为十六进制
print(hex(0b101), hex(110), hex(0o12)) # bytes字节 bytearray 字节列表
bytes("xxxx", encoding="utf-8")
bytearray([source[, encoding[, errors]]])
# 返回一个新的字节数组。bytearray类型是一个可变的整数序列,整数范围为0 <= x < 256(即字节)。 它有可变序列的大多数方法,参见Mutable Sequence Types,同时它也有str类型的大多数方法,参见String Methods。
举例:将字符串“杜拉拉”转换成UTF-8编码的字节类型 bytes('杜拉拉', encoding='utf-8') # chr ord 字符串、数字转换
c = chr(65)
i = ord("A")
print(c, i) # 输出('A', 65) 应用:生成验证码
import random
verification_code = ''
for i in range(6):
rand = random.randrange(0, 4)
if rand == 3 or rand == 1:
num = random.randint(0, 9)
verification_code += str(num)
else:
num = random.randint(65, 91)
letter = chr(num)
verification_code += letter
print(verification_code) import random
verification_code = ''
for i in range(6):
rand = random.randrange(0, 6)
if i == rand:
num = random.randint(0, 9)
verification_code += str(num)
else:
num = random.randint(65, 91)
letter = chr(num)
verification_code += letter
print(verification_code) # callable(object),检查某个对象是否可以被执行 即 对象()
# 如果object参数可调用,返回True;否则返回False。如果返回真,对其调用仍有可能失败;但是如果返回假,对object的调用总是失败。注意类是可调用的(对类调用返回一个新实例);如果类实例有__call__()方法,则它们也是可调用的。
def f1():
return
r = callable(f1) # 判断f1()是否可执行
print(r) # compile 编译 默认读文件都是字符串,经过编译变成python可执行的代码
# 例子:
code = 'def hellocute():return "name %s ,age %d" %(name,data[0],) '
func = compile(code, '<string>', "exec") # 把上面的字符串编译为函数 # dir 显示类的方法
如果没有参数,返回当前本地作用域内的名字列表。如果有参数,尝试返回参数所指明对象的合法属性的列表。
>>> import struct
>>> dir() # show the names in the module namespace
['__builtins__', '__doc__', '__name__', 'struct']
>>> dir(struct) # show the names in the struct module
['Struct', '__builtins__', '__doc__', '__file__', '__name__',
'__package__', '_clearcache', 'calcsize', 'error', 'pack', 'pack_into',
'unpack', 'unpack_from']
>>> class Shape(object):
def __dir__(self):
return ['area', 'perimeter', 'location']
>>> s = Shape()
>>> dir(s) 153 ['area', 'perimeter', 'location'] # divmod(10,3) 显示商和余数
# 分页 :余数大于0 商+1 为页数 (分页:每页存放10条数据,一共101条数据,需要几页? divmod(101,10) 可知为11页才能存放101条数据)
在长整数除法中,传入两个数字(非复数)作为参数,返回商和余数的二元组。
对于混合的操作数类型,应用二元算术运算符的规则。对于普通整数或者长整数,结果等同于(a // b, a % b)。对于浮点数结果是(q, a % b),q一般是math.floor(a / b),但也可能比那小1。
不管怎样,q * b + a % b非常接近于a,如果a % b非0,它和b符号相同且0 <= abs(a % b) < abs(b)。 # eval # 字符串 转算 执行表达式 结果放在返回值中,有返回值
eval(expression[, globals[, locals]])
参数是Unicode或者Latin-1编码的字符串,全局变量和局部变量可选。如果有全局变量,globals必须是个字典。如果有局部变量,locals可以是任何映射类型对象。
>>> x = 1
>>> print eval('x+1')
a = "1 + 3"
n = eval(a)
print(n)
ret = eval("a+60", {"a": 88})
print(ret) # exec: 执行py代码
没有返回值,直接输出结果:
exec("for i in range(3):print(i)") # globals() 获取所有的全局变量
# local() #获取所有局部变量
def f1():
name = 123
print(locals()) # 输出123
print(globals())
f1() # hash(对象) 计算获取对象hash值(长度固定) 内存优化
# 返回对象的hash(哈希/散列)值(如果有的话)。hash值是整数。它被用于在字典查找时快速比较字典的键。相同的数值有相同的hash(尽管它们有不同的类型,比如1和1.0)。
dic = {'dsaasd;sadasqwdzcs;121saddfsssxa': 1}
i = hash('dsaasd;sadasqwdzcs;121saddfsssxa')
print(i) #输出:9127798505667503991 # isinstance(对象,类) 判断对象是否是某个类创建的 父类的话也成立
li = [11, 22]
r = isinstance(li, list)
r1 = isinstance(li, dict)
print(r, r1) # 输出True False # iter 迭代器
obj = iter([1, 2, 3, 4])
print(obj)
next(obj) # 执行next方法
r = next(obj)
print(r)
# 输出:
# <list_iterator object at 0x000000000118E400>
# 2 # max,min 最大值,最小值
l1 = [1, 22, -1, 0, 5]
l2 = (111, 22, -11111, 0, 5)
print(max(l1))
print(min(l2)) # pow求次方
i = pow(2, 10)
print(i) 223 224 225 # round 四舍五入
print "round(80.23456, 2) : ", round(80.23456, 2)
print "round(100.000056, 3) : ", round(100.000056, 3)
print "round(-100.000056, 3) : ", round(-100.000056, 3)
round(80.23456, 2) : 80.23 230 round(100.000056, 3) : 100.0
round(-100.000056, 3) : -100.0 232 233 print(round(80.23456, 2))
# 输出80.23 print(round(4.56, 1))
# 输出4.6 # sum(iterable[, start]) 将start以及iterable的元素从左向右相加并返回总和。start默认为0。iterable的元素通常是数字,start值不允许是一个字符串。
r = sum(range(101)) # 计算1-100的和
print(r) 240 a = range(1,11)
b = range(1,10)
c = sum([item for item in a if item in b]) # 列表解析,再用sum求和
print(c) 244 245 246 # zip 拉链 将两个列表合起来,做成一个列表,元素为数组
>>> b 248 [1, 2, 3, 4] 249 >>> a
[5, 6, 7, 8, 9]
>>> zip(a,b)
[(5, 1), (6, 2), (7, 3), (8, 4)] # sort 函数, 数字和字母不支持一起排序,可以把数字用引号变为字符串,再排序
l = ['', '', '', '-1', '-66', '', 'a'] 257 l.sort() 258 print(l)
max函数用法补充:
# 可以通过传入命名参数key,指定取最大值方法。
max(-1,0,key = abs) # 传入了求绝对值函数,则参数都会进行求绝对值后再取较大者
-1 # key参数的另外一个作用是,不同类型对象本来不能比较取最大值的,传入适当的key函数,变得可以比较能取最大值了。
max(1,2,'',key = int) # 指定key为转换函数后,可以取最大值
''
max((1,2),[1,1],key = lambda x : x[1]) #指定key为返回序列索引1位置的元素后,可以取最大值 # x就是(1,2),[1,1]两个元组的传参
(1, 2) salaries = {
'egon': 3000,
'alex': 100000000,
'wupeiqi': 10000,
'yuanhao': 2000
}
a = max(salaries, key=lambda k: salaries[k])
print(a) # alex
lambda x,req:self.inprogress.remove(req) 执行lambda函数,形参:x,req;返回self.inprogress.remove(req)
__dict__与dir()区别:
Python下一切皆对象,每个对象都有多个属性(attribute),Python对属性有一套统一的管理方案。 __dict__与dir()的区别: dir()是一个函数,返回的是list;
__dict__是一个字典,键为属性名,值为属性值;
dir()用来寻找一个对象的所有属性,包括__dict__中的属性,__dict__是dir()的子集;
并不是所有对象都拥有__dict__属性。许多内建类型就没有__dict__属性,如list,此时就需要用dir()来列出对象的所有属性。 # __dict__属性:
# __dict__是用来存储对象属性的一个字典,其键为属性名,值为属性的值。 #!/usr/bin/python
# -*- coding: utf-8 -*-
class A(object):
class_var = 1
def __init__(self):
self.name = 'xy'
self.age = 2 @property
def num(self):
return self.age + 10 def fun(self):pass
def static_f():pass
def class_f(cls):pass if __name__ == '__main__':#主程序
a = A()
print a.__dict__ #{'age': 2, 'name': 'xy'} 实例中的__dict__属性
print A.__dict__
'''
类A的__dict__属性
{
'__dict__': <attribute '__dict__' of 'A' objects>, #这里如果想深究的话查看参考链接5
'__module__': '__main__', #所处模块
'num': <property object>, #特性对象
'class_f': <function class_f>, #类方法
'static_f': <function static_f>, #静态方法
'class_var': 1, 'fun': <function fun >, #类变量
'__weakref__': <attribute '__weakref__' of 'A' objects>,
'__doc__': None, #class说明字符串
'__init__': <function __init__ at 0x0000000003451AC8>}
''' a.level1 = 3
a.fun = lambda :x
print a.__dict__ #{'level1': 3, 'age': 2, 'name': 'xy','fun': <function <lambda> at 0x>}
print A.__dict__ #与上述结果相同 A.level2 = 4
print a.__dict__ #{'level1': 3, 'age': 2, 'name': 'xy'}
print A.__dict__ #增加了level2属性 print object.__dict__
'''
{'__setattr__': <slot wrapper '__setattr__' of 'object' objects>,
'__reduce_ex__': <method '__reduce_ex__' of 'object' objects>,
'__new__': <built-in method __new__ of type object at>,
等.....
''' # 从上述代码可知, 实例的__dict__仅存储与该实例相关的实例属性, 正是因为实例的__dict__属性,每个实例的实例属性才会互不影响。 类的__dict__存储所有实例共享的变量和函数(类属性,方法等),类的__dict__并不包含其父类的属性。 # dir()函数
# dir()是Python提供的一个API函数,dir()函数会自动寻找一个对象的所有属性(包括从父类中继承的属性)。 一个实例的__dict__属性仅仅是那个实例的实例属性的集合,并不包含该实例的所有有效属性。所以如果想获取一个对象所有有效属性,应使用dir()。 print dir(A)
'''
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'class_f', 'class_var', 'fun', 'level1', 'level2', 'name', 'num', 'static_f']
'''
a_dict = a.__dict__.keys()
A_dict = A.__dict__.keys()
object_dict = object.__dict__.keys()
print a_dict
print A_dict
print object_dict
'''
['fun', 'level1', 'age', 'name'] ['__module__', 'level2', 'num', 'static_f', '__dict__', '__weakref__', '__init__', 'class_f', 'class_var', 'fun', '__doc__'] ['__setattr__', '__reduce_ex__', '__new__', '__reduce__', '__str__', '__format__', '__getattribute__', '__class__', '__delattr__', '__subclasshook__', '__repr__', '__hash__', '__sizeof__', '__doc__', '__init__']
''' #因为每个类都有一个__doc__属性,所以需要去重,去重后然后比较
print set(dir(a)) == set(a_dict + A_dict + object_dict) #True # 结论
dir()函数会自动寻找一个对象的所有属性,包括__dict__中的属性。 __dict__是dir()的子集,dir()包含__dict__中的属性。
我们都知道Python一切皆对象,那么Python究竟是怎么管理对象的呢?
1、无处不在的__dict__
首先看一下类的__dict__属性和类对象的__dict__属性 # -*- coding: utf-8 -*- class A(object):
"""
Class A.
""" a = 0
b = 1 def __init__(self):
self.a = 2
self.b = 3 def test(self):
print 'a normal func.' @staticmethod
def static_test(self):
print 'a static func.' @classmethod
def class_test(self):
print 'a calss func.' obj = A()
print A.__dict__
print obj.__dict__ 运行结果如下: {'a': 0, '__module__': '__main__', 'b': 1, 'class_test': <classmethod object at 0x00000000021882E8>, '__dict__': <attribute '__dict__' of 'A' objects>, '__init__': <function __init__ at 0x00000000023A5BA8>, 'test': <function test at 0x00000000023A5C18>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': '\n Class A.\n ', 'static_test': <staticmethod object at 0x00000000021881C8>}
{'a': 2, 'b': 3} 由此可见, 类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类__dict__里的 对象的__dict__中存储了一些self.xxx的一些东西 2、Python里什么没有__dict__属性
虽然说一切皆对象,但对象也有不同,就好比不是每个人的女朋友都是一个人一样,一些内置的数据类型是没有__dict__属性的,如下: num = 3
ll = []
dd = {}
print num.__dict__
print ll.__dict__
print dd.__dict__ # 当我们运行这样的代码时,解释器就会告诉我们 Traceback (most recent call last):
File "f:\python\test.py", line 54, in <module>
print num.__dict__
AttributeError: 'int' object has no attribute '__dict__' Traceback (most recent call last):
File "f:\python\test.py", line 55, in <module>
print ll.__dict__
AttributeError: 'list' object has no attribute '__dict__' Traceback (most recent call last):
File "f:\python\test.py", line 56, in <module>
print dd.__dict__
AttributeError: 'dict' object has no attribute '__dict__' int, list, dict等这些常用的数据类型是没有__dict__属性的,其实这是可预料的,就算给了它们dict属性也没啥用,毕竟它们只是用来做数据容器的。 3、发生继承时候的__dict__属性
子类有自己的__dict__, 父类也有自己的__dict__,子类的全局变量和函数放在子类的dict中,父类的放在父类dict中。 # -*- coding: utf-8 -*- class Parent(object):
a = 0
b = 1 def __init__(self):
self.a = 2
self.b = 3 def p_test(self):
pass class Child(Parent):
a = 4
b = 5 def __init__(self):
super(Child, self).__init__()
# self.a = 6
# self.b = 7 def c_test(self):
pass def p_test(self):
pass p = Parent()
c = Child()
print Parent.__dict__
print Child.__dict__
print p.__dict__
print c.__dict__ # 运行上面的代码,结果入下: {'a': 0, '__module__': '__main__', 'b': 1, '__dict__': <attribute '__dict__' of 'Parent' objects>, 'p_test': <function p_test at 0x0000000002325BA8>, '__weakref__': <attribute '__weakref__' of 'Parent' objects>, '__doc__': None, '__init__': <function __init__ at 0x0000000002325B38>}
{'a': 4, 'c_test': <function c_test at 0x0000000002325C88>, '__module__': '__main__', 'b': 5, 'p_test': <function p_test at 0x0000000002325CF8>, '__doc__': None, '__init__': <function __init__ at 0x0000000002325C18>}
{'a': 2, 'b': 3}
{'a': 2, 'b': 3} 1)上段输出结果中,用红色字体标出的是类变量和函数,由结果可知,每个类的类变量、函数名都放在自己的__dict__中 2) 再来看一下实力变量的__dict__中,由蓝色字体标识,父类和子类对象的__dict__是公用的 总结: 1) 内置的数据类型没有__dict__属性 2) 每个类有自己的__dict__属性,就算存着继承关系,父类的__dict__ 并不会影响子类的__dict__ 3) 对象也有自己的__dict__属性, 存储self.xxx 信息,父子类对象公用__dict__
__setattr__:
# __setattr__ 每次给对象的属性设置值之前,会调用这个函数(每个设置值的方式都会进入这个方法)。
class A(object): def __init__(self, value, n):
print("into __init__")
self.value = value
print("set n")
self.n = n
print("leave __init__") def __setattr__(self, name, value):
print("into __setattr__")
print("name:", name)
print("value:", value)
if value == 10:
print("from __init__")
# self.name = value # 这样会导致死循环
object.__setattr__(self, name, value) a = A(10,100)
print(a.__dict__)
# 输出
# into __init__
# into __setattr__
# name: value
# value: 10
# from __init__
# set n
# into __setattr__
# name: n
# value: 100
# leave __init__
# {'value': 10, 'n': 100} class _const(object):
def __setattr__(self, name, value):
if name in self.__dict__:
raise ValueError("Can't rebind const (%s)" % name)
if not name.isupper():
raise ValueError("Const must be upper.")
self.__dict__[name] = value
print(self.__dict__) const = _const() const.DB_CONFIG_ITEM = 'databases'
const.NW_SALT = 'nw'
const.ALY_SALT = 'aly' # 输出:
# {'DB_CONFIG_ITEM': 'databases'}
# {'NW_SALT': 'nw', 'DB_CONFIG_ITEM': 'databases'}
# {'ALY_SALT': 'aly', 'NW_SALT': 'nw', 'DB_CONFIG_ITEM': 'databases'}
__getattr__:
# __getattr__:
# 当访问一个不存在的属性的时候,会抛出异常,提示我们不存在这个属性。
# 而这个异常就是__getattr__方法抛出的,其原因在于他是访问一个不存在的属性的最后落脚点,作为异常抛出的地方提示出错再适合不过了。
class A(object):
def __init__(self, value):
self.value = value def __getattr__(self, item):
print(item)
print("into __getattr__")
return "can not find" a = A(10)
print(a.value) https://www.cnblogs.com/xybaby/p/6280313.html
三元运算:
flag = True
name = "whisky" if flag else ""
print(name) # whisky
生成器:
# 生成器,普通函数中如果使用了yield则表示这个函数变为生成器函数 def xrange():
print(11)
yield 1 # yield后面的值返回给__next__方法接收 print(22)
yield 2 print(33)
yield 3 print(44)
yield 4 print(55)
yield 5 r = xrange() # 执行这个函数创建一个生成器
ret = r.__next__() # 执行函数寻找下一个yeild
print(ret)
ret = r.__next__()
print(ret)
ret = r.__next__()
print(ret)
#单步调试可以看到执行顺序
def xrange():
print('start')
start = 0
while True:
yield start
start += 1 obj = xrange()
r = obj.__next__()
r = obj.__next__()
r = obj.__next__()
print(r) #输出
start
2
#生成器, yield,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。保存上一次执行位置 def xrange(n):
start = 0
while True:
if start > n:
return
yield start
start += 1 obj = xrange(15)
for i in obj: # 直接使用for循环来迭代
print(i)
补充:
def xrange():
start = 0
while True:
yield start
start += 1 obj = xrange()
for i in obj: # 直接使用for循环来迭代
if i > 10:
break
print(i) # 等价于 a = (x for x in range(4))
def gen():
for l in range(4):
yield l
a = gen() for i in a:
print(i)
生成器表达式和列表解析
迭代器协议
1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前退) 2.可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个__iter__()方法) 3.协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(如for循环,sum,min,max函数等)使用迭代器协议访问对象。 for循环的本质:循环所有对象,全都是使用迭代器协议。 正本清源: 很多人会想,for循环的本质就是遵循迭代器协议去访问对象,那么for循环的对象肯定都是迭代器了啊,没错,那既然这样,for循环可以遍历(字符串,列表,元组,字典,集合,文件对象),那这些类型的数据肯定都是可迭代对象啊?但是,我他妈的为什么定义一个列表l=[1,2,3,4]没有l.next()方法,打脸么。 (字符串,列表,元组,字典,集合,文件对象)这些都不是可迭代对象,只不过在for循环式,调用了他们内部的__iter__方法,把他们变成了可迭代对象 然后for循环调用可迭代对象的__next__方法去取值,而且for循环会捕捉StopIteration异常,以终止迭代 for循环就是基于迭代器协议提供了一个统一的可以遍历所有对象的方法,即在遍历之前,先调用对象的__iter__方法将其转换成一个迭代器,然后使用迭代器协议去实现循环访问,这样所有的对象就都可以通过for循环来遍历了 l=['a','b','c']
#一:下标访问方式
print(l[0])
print(l[1])
print(l[2])
# print(l[3])#超出边界报错:IndexError #二:遵循迭代器协议访问方式
diedai_l=l.__iter__()
print(diedai_l.__next__())
print(diedai_l.__next__())
print(diedai_l.__next__())
# print(diedai_l.__next__())#超出边界报错:StopIteration #三:for循环访问方式
#for循环l本质就是遵循迭代器协议的访问方式,先调用diedai_l=l.__iter__()方法,或者直接diedai_l=iter(l),然后依次执行diedai_l.next(),直到for循环捕捉到StopIteration终止循环
#for循环所有对象的本质都是一样的原理 for i in l:#diedai_l=l.__iter__()
print(i) #i=diedai_l.next() #四:用while去模拟for循环做的事情
diedai_l=l.__iter__()
while True:
try:
print(diedai_l.__next__())
except StopIteration:
print('迭代完毕了,循环终止了')
break 什么是生成器?
可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他的数据类型需要调用自己内置的__iter__方法),所以生成器就是可迭代对象 生成器分类及在python中的表现形式:(Python有两种不同的方式提供生成器) 1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行 2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表 为何使用生成器之生成器的优点 Python使用生成器对延迟操作提供了支持。所谓延迟操作,是指在需要的时候才产生结果,而不是立即产生结果。这也是生成器的主要好处。 生成器小结: 1.是可迭代对象 2.实现了延迟计算,省内存 3.生成器本质和其他的数据类型一样,都是实现了迭代器协议,只不过生成器附加了一个延迟计算省内存的好处,其余的可迭代对象可没有这点好处 # 生成器表达式和列表解析 egg_list=['鸡蛋%s' %i for i in range(10)] #列表解析 laomuji=('鸡蛋%s' %i for i in range(10))#生成器表达式
print(laomuji)
print(next(laomuji)) #next本质就是调用__next__
print(laomuji.__next__())
print(next(laomuji)) 总结: 1.把列表解析的[]换成()得到的就是生成器表达式 2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存 3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和: sum(x ** 2 for x in xrange(4)) 而不用多此一举的先构造一个列表:sum([x ** 2 for x in xrange(4)]) 八 生成器总结
综上已经对生成器有了一定的认识,下面我们以生成器函数为例进行总结 语法上和函数类似:生成器函数和常规函数几乎是一样的。它们都是使用def语句进行定义,差别在于,生成器使用yield语句返回一个值,而常规函数使用return语句返回一个值
自动实现迭代器协议:对于生成器,Python会自动实现迭代器协议,以便应用到迭代背景中(如for循环,sum函数)。由于生成器自动实现了迭代器协议,所以,我们可以调用它的next方法,并且,在没有值可以返回的时候,生成器自动产生StopIteration异常
状态挂起:生成器使用yield语句返回一个值。yield语句挂起该生成器函数的状态,保留足够的信息,以便之后从它离开的地方继续执行 优点:生成器的好处是延迟计算,一次返回一个结果。也就是说,它不会一次生成所有的结果,这对于大数据量处理,将会非常有用。
#列表解析
sum([i for i in range(100000000)])#内存占用大,机器容易卡死 #生成器表达式
sum(i for i in range(100000000))#几乎不占内存 注意事项:生成器只能遍历一次 人口信息.txt文件内容:
{'name':'北京','population':10}
{'name':'南京','population':100000}
{'name':'山东','population':10000}
{'name':'山西','population':19999}
def get_provice_population(filename):
with open(filename) as f:
for line in f:
p = eval(line)
yield p['population'] gen = get_provice_population('a') all_population = sum(gen)
# for p in gen:
# print(p / all_population)
print(all_population) def test():
for i in range(4):
yield i g = test() g1 = (i for i in g)
g2 = (i for i in g1)
g3 = (i for i in g) print(list(g1)) # [0, 1, 2, 3]
print(list(g2)) # [] 生成器只能生成一次,所以为空列表
print(list(g3)) # [] 生成器只能生成一次,所以为空列表 对于生成一个列表: #循环方法(效率低):
goods_list = []
for i in range(10):
goods_list.append(i)
print(goods_list) # 列表解析方法:
goods_list = [i for i in range(10)] # 列表解析中还可以加条件goods_list2 = [i for i in range(10) if i > 5] # 三元运算
name = 'alex'
ret = 'SB' if name == 'alex' else 'blex'
print(ret) 当goods_list非常大时列表解析方法耗内存严重 # 生成器表达式方法:
goods_list3 = (i for i in range(10)) # 生成器对象转列表:goods_list3 = list((i for i in range(10))) print(goods_list3) # 返回一个生成器对象
迭代器,生成器
def add(n, i):
print('n:', n, 'i:', i, 'n+i:', n + i)
return n + i def test():
for i in range(4):
yield i g = test()
print('g: ========', g)
for n in [1, 10]: # 生成两个生成器迭代对象,第一个生成器迭代对象的结果赋值给第二个生成器中的i,n的值始终覆盖为10
print(n, 1)
g = (add(n, i) for i in g)
print(g)
print(n, 10) print('g: ========', g)
print(list(g))
练习
'''
闭包:在一个作用域里放入定义变量,相当于打了一个包
'''
def father(name):
def son():
# name='alex'
print('我爸爸是 [%s]' %name)
def grandson():
# name='wupeiqi'
print('我爷爷是 [%s]' %name)
grandson()
son() father('whisky')
yield使用总结:
def yield_test(n):
for i in range(n): #
yield call(i) # 2 # 执行call函数之后,返回值给外面的for循环,
print("in yield_test -- i=", i) #
# 做一些其它的事情
print("do something.")
print("end.") def call(i):
return i * 2 # # 使用for循环
for i in yield_test(5): # 0 # 5
print(i, "in for---") # 4 # 理解的关键在于:下次迭代时,代码从yield的下一跳语句开始执行。
# 输出:
# 0 in for---
# in yield_test -- i= 0
# 2 in for---
# in yield_test -- i= 1
# 4 in for---
# in yield_test -- i= 2
# 6 in for---
# in yield_test -- i= 3
# 8 in for---
# in yield_test -- i= 4
# do something.
# end. 小结yeild:
0.yeild用于函数中
1.执行了yield,就相当于返回一个生成器对象,可用于迭代
2.yield 是一个类似 return 的关键字,迭代一次遇到yield时就返回yield后面(右边)的;下一次迭代时,从上一次迭代遇到的yield后面的代码(下一行)开始执行
3. yield 可以返回变量,也可以返回函数
主要记住两点:
1.yield退出所在函数并返回一个生成器,可迭代对象;
2.迭代这个生成器时,继续从上次yield的位置向后执行
参考:
https://www.jianshu.com/p/d09778f4e055
列表推导式:
# 有一个嵌套列表,a=[[1,2],[3,4],[5,6]],要提取列表里的每一个元素 用for循环处理: for i in a:
for j in i:
print(j) b=[j for i in a for j in i] # 左侧是外层循环,右侧是内层for循环 print(b) >>> b
[1, 2, 3, 4, 5, 6]
https://blog.csdn.net/weixin_44695969/article/details/96889580
最新文章
- [C#] C# 知识回顾 - 表达式树 Expression Trees
- vmware 安装xp 流水账
- memcached的图形界面监控
- iOS Debug日志 viewhierarchy调试笔记
- 华清远见金牌讲师名家大讲堂Android开发篇成功举办
- Python命令行中输入pip提示不是内部或外部命令
- (转)ReSharper 配置及用法
- How to install VXDIAG Honda, Toyota and JLR SDD software
- VC++判断是否连网
- mac git 的安装 及实现自动补全
- KeepAlive随笔
- mac安装brew简单方法
- 关于RecyclerView你知道的不知道的都在这了(上)
- 字符设备驱动(二)---key的使用:查询方式
- eclipse debug模式
- 我对if(!this.IsPostBack)的理解
- Win(Phone)10开发第(2)弹,导出APPX包并签名部署
- 软工网络15团队作业8——Beta阶段敏捷冲刺(Day3)
- OpenSSL 给自己颁发根证书,由根证书签发下级证书的步骤。
- 第二章C++实验