阿里云python训练营-Python基础学习03

函数

函数的定义¶

还记得 Python 里面"万物皆对象"么?Python 把函数也当成对象,可以从另一个函数中返回出来而去构建高阶函数,比如: 参数是函数、返回值是函数。

我们首先来介绍函数的定义。

函数以def关键词开头,后接函数名和圆括号()。

函数执行的代码以冒号起始,并且缩进。

return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回None。

def functionname (parameters): "函数_文档字符串" function_suite

函数文档

def MyFirstFunction(name): "函数定义过程中name是形参" # 因为Ta只是一个形式,表示占据一个参数位置 print('传递进来的{0}叫做实参,因为Ta是具体的参数值!'.format(name)) MyFirstFunction('老马的程序人生') # 传递进来的老马的程序人生叫做实参,因为Ta是具体的参数值! print(MyFirstFunction.doc) # 函数定义过程中name是形参 help(MyFirstFunction) # Help on function MyFirstFunction in module main: # MyFirstFunction(name) # 函数定义过程中name是形参

函数参数

Python 的函数具有非常灵活多样的参数形态,既可以实现简单的调用,又可以传入非常复杂的参数。从简到繁的参数形态如下:

  • 位置参数 (positional argument)
  • 默认参数 (default argument)
  • 可变参数 (variable argument)
  • 关键字参数 (keyword argument)
  • 命名关键字参数 (name keyword argument)
  • 参数组合
  1. 位置参数

def functionname(arg1): "函数_文档字符串" function_suite return [expression]

  • arg1
  1. 默认参数

def functionname(arg1, arg2=v): "函数_文档字符串" function_suite return [expression]

  • arg2 = v
  • 默认参数一定要放在位置参数 后面,不然程序会报错。
  • Python 允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
  1. 可变参数

顾名思义,可变参数就是传入的参数个数是可变的,可以是 0, 1, 2 到任意个,是不定长的参数。

def functionname(arg1, arg2=v, *args): "函数_文档字符串" function_suite return [expression]

  • *args
  • 加了星号(*)的变量名会存放所有未命名的变量参数。

def printinfo(arg1, *args): print(arg1) for var in args: print(var) printinfo(10) # 10 printinfo(70, 60, 50) # 70 # 60 # 50

  1. 关键字参数

def functionname(arg1, arg2=v, *args, **kw):

"函数_文档字符串"

function_suite

return [expression]

  • `**kw` - 关键字参数,可以是从零个到任意个,自动组装成字典。

def printinfo(arg1, *args, **kwargs): print(arg1) print(args) print(kwargs) printinfo(70, 60, 50) # 70 # (60, 50) # {} printinfo(70, 60, 50, a=1, b=2) # 70 # (60, 50) # {'a': 1, 'b': 2}

「可变参数」和「关键字参数」的同异总结如下:

  • 可变参数允许传入零个到任意个参数,它们在函数调用时自动组装为一个元组 (tuple)。
  • 关键字参数允许传入零个到任意个参数,它们在函数内部自动组装为一个字典 (dict)。
  1. 命名关键字参数

def functionname(arg1, arg2=v, *args, *, nkw, **kw):

"函数_文档字符串"

function_suite

return [expression]

  • `*, nkw` - 命名关键字参数,用户想要输入的关键字参数,定义方式是在nkw 前面加个分隔符 `*`。

  • 如果要限制关键字参数的名字,就可以用「命名关键字参数」

  • 使用命名关键字参数时,要特别注意不能缺少参数名。

  1. 参数组合

在 Python 中定义函数,可以用位置参数、默认参数、可变参数、命名关键字参数和关键字参数,这 5 种参数中的 4 个都可以一起使用,但是注意,参数定义的顺序必须是:

  • 位置参数、默认参数、可变参数和关键字参数。

  • 位置参数、默认参数、命名关键字参数和关键字参数。

要注意定义可变参数和关键字参数的语法:

  • `*args` 是可变参数,`args` 接收的是一个 `tuple`

  • `**kw` 是关键字参数,`kw` 接收的是一个 `dict`

命名关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。定义命名关键字参数不要忘了写分隔符 `*`,否则定义的是位置参数。

警告:虽然可以组合多达 5 种参数,但不要同时使用太多的组合,否则函数很难懂。

变量作用域

  • Python 中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。
  • 定义在函数内部的变量拥有局部作用域,该变量称为局部变量。
  • 定义在函数外部的变量拥有全局作用域,该变量称为全局变量。
  • 局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。

当内部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字

闭包

  • 是函数式编程的一个重要的语法结构,是一种特殊的内嵌函数。
  • 如果在一个内部函数里对外层非全局作用域的变量进行引用,那么内部函数就被认为是闭包。
  • 通过闭包可以访问外层非全局作用域的变量,这个作用域称为 闭包作用域。

闭包的返回值通常是函数。

def make_counter(init): counter = [init] def inc(): counter[0] += 1 def dec(): counter[0] -= 1 def get(): return counter[0] def reset(): counter[0] = init return inc, dec, get, reset inc, dec, get, reset = make_counter(0) inc() inc() inc() print(get()) # 3 dec() print(get()) # 2 reset() print(get()) # 0

如果要修改闭包作用域中的变量则需要 nonlocal 关键字

def outer(): num = 10 def inner(): nonlocal num # nonlocal关键字声明 num = 100 print(num) inner() print(num) outer() # 100 # 100

递归

  • 如果一个函数在内部调用自身本身,这个函数就是递归函数。

【例子】n! = 1 x 2 x 3 x ... x n

利用循环 n = 5 for k in range(1, 5): n = n * k print(n) # 120 # 利用递归 def factorial(n): if n == 1: return 1 return n * factorial(n - 1) print(factorial(5)) # 120

设置递归的层数,Python默认递归层数为 100

import sys sys.setrecursionlimit(1000)

Lambda 表达式

匿名函数的定义

在 Python 里有两类函数:

  • 第一类:用 `def` 关键词定义的正规函数

  • 第二类:用 `lambda` 关键词定义的匿名函数

Python 使用 `lambda` 关键词来创建匿名函数,而非`def`关键词,它没有函数名,其语法结构如下:

> lambda argument_list: expression

  • `lambda` - 定义匿名函数的关键词。

  • `argument_list` - 函数参数,它们可以是位置参数、默认参数、关键字参数,和正规函数里的参数类型一样。

  • `:`- 冒号,在函数参数和表达式中间要加个冒号。

  • `expression` - 只是一个表达式,输入函数参数,输出一些值。

注意:

  • `expression` 中没有 return 语句,因为 lambda 不需要它来返回,表达式本身结果就是返回值。

  • 匿名函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。

匿名函数的应用

函数式编程 是指代码中每一块都是不可变的,都由纯函数的形式组成。这里的纯函数,是指函数本身相互独立、互不影响,对于相同的输入,总会有相同的输出,没有任何副作用。

def f(x): for i in range(0, len(x)): x[i] += 10 return x x = [1, 2, 3] f(x) print(x) # [11, 12, 13]

匿名函数 常常应用于函数式编程的高阶函数 (high-order function)中,主要有两种形式:

  • 参数是函数 (filter, map)
  • 返回值是函数 (closure)

如,在 filter和map函数中的应用:

filter(function, iterable) 过滤序列,过滤掉不符合条件的元素,返回一个迭代器对象,如果要转换为列表,可以使用 list() 来转换。

map(function, *iterables) 根据提供的函数对指定序列做映射。

类与对象

对象 = 属性 + 方法

对象是类的实例。换句话说,类主要定义对象的结构,然后我们以类为模板创建对象。类不但包含方法定义,而且还包含所有实例共享的数据。

  • 封装:信息隐蔽技术

我们可以使用关键字 class 定义 Python 类,关键字后面紧跟类的名称、分号和类的实现。

  • 继承:子类自动共享父类之间数据和方法的机制
  • 多态:不同对象对同一方法响应不同的行动

self 是什么?

Python 的 self 相当于 C++ 的 this 指针。

类的方法与普通的函数只有一个特别的区别 ------ 它们必须有一个额外的第一个参数名称(对应于该实例,即该对象本身),按照惯例它的名称是 self。在调用方法时,我们无需明确提供与参数 self 相对应的参数。

class Ball: def setName(self, name): self.name = name def kick(self): print("我叫%s,该死的,谁踢我..." % self.name) a = Ball() a.setName("球A") b = Ball() b.setName("球B") c = Ball() c.setName("球C") a.kick() # 我叫球A,该死的,谁踢我... b.kick() # 我叫球B,该死的,谁踢我...


Python 的魔法方法

据说,Python 的对象天生拥有一些神奇的方法,它们是面向对象的 Python 的一切...

它们是可以给你的类增加魔力的特殊方法...

如果你的对象实现了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Python 所调用,而这一切都是自动发生的...

类有一个名为__init__(self[, param1, param2...])的魔法方法,该方法在类实例化时会自动调用。

公有和私有

在 Python 中定义私有变量只需要在变量名或函数名前加上"__"两个下划线,那么这个函数或变量就会为私有的了。

class JustCounter: __secretCount = 0 # 私有变量 publicCount = 0 # 公开变量 def count(self): self.__secretCount += 1 self.publicCount += 1 print(self.__secretCount ,'====',self.publicCount) counter = JustCounter() counter.count() # 1 counter.count() # 2 print(counter.publicCount) # 2 # Python的私有为伪私有 print(counter._JustCounter__secretCount) print(counter._JustCounter__secretCount) # 2 print(counter.__secretCount) # AttributeError: 'JustCounter' object has no attribute '__secretCount'

继承

Python 同样支持类的继承,派生类的定义如下所示:

class DerivedClassName(BaseClassName):

statement-1

.

.

.

statement-N

BaseClassName(基类名)必须与派生类定义在一个作用域内。除了类,还可以用表达式,基类定义在另一个模块中时这一点非常有用:

class DerivedClassName(modname.BaseClassName):

statement-1

.

.

.

statement-N

【例子】如果子类中定义与父类同名的方法或属性,则会自动覆盖父类对应的方法或属性。

多继承

Python 虽然支持多继承的形式,但我们一般不使用多继承,因为容易引起混乱。

class DerivedClassName(Base1, Base2, Base3):

statement-1

.

.

.

statement-N

需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,Python 从左至右搜索,即方法在子类中未找到时,从左到右查找父类中是否包含方法

组合

class Turtle: def init(self, x): self.num = x class Fish: def init(self, x): self.num = x class Pool: def init(self, x, y): self.turtle = Turtle(x) self.fish = Fish(y) def print_num(self): print("水池里面有乌龟%s只,小鱼%s条" % (self.turtle.num, self.fish.num)) p = Pool(2, 3) p.print_num()

类、类对象和实例对象

类对象:创建一个类,其实也是一个对象也在内存开辟了一块空间,称为类对象,类对象只有一个。

class A(object): pass

实例对象:就是通过实例化类创建的对象,称为实例对象,实例对象可以有多个。

类属性:类里面方法外面定义的变量称为类属性。类属性所属于类对象并且多个实例对象之间共享同一个类属性,说白了就是类属性所有的通过该类实例化的对象都能共享。

注意:属性与方法名相同,属性会覆盖方法。 【例子】 class A: def x(self): print('x_man') ​ aa = A() aa.x() # x_man aa.x = 1 print(aa.x) # 1 aa.x() # TypeError: 'int' object is not callable

什么是绑定?

Python 严格要求方法需要有实例才能被调用,这种限制其实就是 Python 所谓的绑定概念。

Python 对象的数据属性通常存储在名为.__ dict__的字典中,我们可以直接访问__dict__,或利用 Python 的内置函数vars()获取.__ dict__。

class CC: def setXY(self, x, y): self.x = x self.y = y def printXY(self): print(self.x, self.y) dd = CC() print(dd.dict) # {} print(vars(dd)) # {} print(CC.dict) # {'module': 'main', 'setXY': <function CC.setXY at 0x000000C3473DA048>, 'printXY': <function CC.printXY at 0x000000C3473C4F28>, 'dict': <attribute 'dict' of 'CC' objects>, 'weakref': <attribute 'weakref' of 'CC' objects>, 'doc': None} dd.setXY(4, 5) print(dd.dict) # {'x': 4, 'y': 5} print(vars(CC)) # {'module': 'main', 'setXY': <function CC.setXY at 0x000000632CA9B048>, 'printXY': <function CC.printXY at 0x000000632CA83048>, 'dict': <attribute 'dict' of 'CC' objects>, 'weakref': <attribute 'weakref' of 'CC' objects>, 'doc': None} print(CC.dict) # {'module': 'main', 'setXY': <function CC.setXY at 0x000000632CA9B048>, 'printXY': <function CC.printXY at 0x000000632CA83048>, 'dict': <attribute 'dict' of 'CC' objects>, 'weakref': <attribute 'weakref' of 'CC' objects>, 'doc': None}

一些相关的内置函数(BIF)

issubclass(class, classinfo) 方法用于判断参数 class 是否是类型参数 classinfo 的子类。

一个类被认为是其自身的子类。

classinfo可以是类对象的元组,只要class是其中任何一个候选类的子类,则返回True。

class A: pass class B(A): pass print(issubclass(B, A)) # True print(issubclass(B, B)) # True print(issubclass(A, B)) # False print(issubclass(B, object)) # True

  • isinstance(object, classinfo) 方法用于判断一个对象是否是一个已知的类型,类似type()。
  • type()不会认为子类是一种父类类型,不考虑继承关系。
  • isinstance()会认为子类是一种父类类型,考虑继承关系。
  • 如果第一个参数不是对象,则永远返回False。
  • 如果第二个参数不是类或者由类对象组成的元组,会抛出一个TypeError异常。

hasattr(object, name)用于判断对象是否包含对应的属性。

getattr(object, name[, default])用于返回一个对象属性值。

class A(object): bar = 1 a = A() print(getattr(a, 'bar')) # 1 print(getattr(a, 'bar', 3)) # 3 a.bar =2 print(getattr(a, 'bar')) print(getattr(a, 'bar',4))

setattr(object, name, value)对应函数 getattr(),用于设置属性值,该属性不一定是存在的。

class A(object): bar = 1 a = A() print(getattr(a, 'bar')) # 1 setattr(a, 'bar', 5) print(a.bar) # 5 setattr(a, "age", 28) print(a.age) # 28

delattr(object, name)用于删除属性。

class Coordinate: x = 10 y = -5 z = 0 point1 = Coordinate() print('x = ', point1.x) # x = 10 print('y = ', point1.y) # y = -5 print('z = ', point1.z) # z = 0 delattr(Coordinate, 'z') print('--删除 z 属性后--') # --删除 z 属性后-- print('x = ', point1.x) # x = 10 print('y = ', point1.y) # y = -5 # 触发错误 print('z = ', point1.z) # AttributeError: 'Coordinate' object has no attribute 'z'

class property([fget[, fset[, fdel[, doc]]]])用于在新式类中返回属性值。

  • fget -- 获取属性值的函数
  • fset -- 设置属性值的函数
  • fdel -- 删除属性值函数
  • doc -- 属性描述信息

魔法方法

魔法方法总是被双下划线包围,例如__init__。

魔法方法是面向对象的 Python 的一切,如果你不知道魔法方法,说明你还没能意识到面向对象的 Python 的强大。

魔法方法的"魔力"体现在它们总能够在适当的时候被自动调用。

魔法方法的第一个参数应为cls(类方法) 或者self(实例方法)。

  • cls:代表一个类的名称
  • self:代表一个实例对象的名称

基本的魔法方法

  • init(self[, ...]) 构造器,当一个实例被创建的时候调用的初始化方法

class Rectangle: def init(self, x, y): self.x = x self.y = y def getPeri(self): return (self.x + self.y) * 2 def getArea(self): return self.x * self.y rect = Rectangle(4, 5) print(rect.getPeri()) # 18 print(rect.getArea()) # 20

new_(cls[, ...]) 在一个对象实例化的时候所调用的第一个方法,在调用__init__初始化前,先调用__new__。

  • new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由 Python 解释器自动提供,后面的参数直接传递给__init
  • new__对当前类进行了实例化,并将实例返回,传给__init__的self。但是,执行了__new,并不一定会进入__init__,只有__new__返回了,当前类cls的实例,当前类的__init__才会进入。

class A(object): def init(self, value): print("into A init") self.value = value def new(cls, *args, **kwargs): print("into A new") print(cls) return object.new(cls) class B(A): def init(self, value): print("into B init") self.value = value def new(cls, *args, **kwargs): print("into B new") print(cls) return super().new(cls, *args, **kwargs) b = B(10) # 结果: # into B new # <class 'main.B'> # into A new # <class 'main.B'> # into B init class A(object): def init(self, value): print("into A init") self.value = value def new(cls, *args, **kwargs): print("into A new") print(cls) return object.new(cls) class B(A): def init(self, value): print("into B init") self.value = value def new(cls, *args, **kwargs): print("into B new") print(cls) return super().new(A, *args, **kwargs) # 改动了cls变为A b = B(10) # 结果: # into B new # <class 'main.B'> # into A new # <class 'main.A'>

若__new__没有正确返回当前类cls的实例,那__init__是不会被调用的,即使是父类的实例也不行,将没有__init__被调用。

单例模式

利用__new__实现单例模式。

class Earth: pass ​ a = Earth() print(id(a)) # 260728291456 b = Earth() print(id(b)) # 260728291624 ​ class Earth: __instance = None # 定义一个类属性做判断 ​ def new(cls): if cls.__instance is None: cls.__instance = object.new(cls) return cls.__instance else: return cls.__instance ​ a = Earth() print(id(a)) # 512320401648 b = Earth() print(id(b)) # 512320401648

__new__方法主要是当你继承一些不可变的 class 时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径。

回收算法

del(self) 析构器,当一个对象将要被系统回收之时调用的方法。

Python 采用自动引用计数(ARC)方式来回收对象所占用的空间,当程序中有一个变量引用该 Python 对象时,Python 会自动保证该对象引用计数为 1;当程序中有两个变量引用该 Python 对象时,Python 会自动保证该对象引用计数为 2,依此类推,如果一个对象的引用计数变成了 0,则说明程序中不再有变量引用该对象,表明程序不再需要该对象,因此 Python 就会回收该对象。

大部分时候,Python 的 ARC 都能准确、高效地回收系统中的每个对象。但如果系统中出现循环引用的情况,比如对象 a 持有一个实例变量引用对象 b,而对象 b 又持有一个实例变量引用对象 a,此时两个对象的引用计数都是 1,而实际上程序已经不再有变量引用它们,系统应该回收它们,此时 Python 的垃圾回收器就可能没那么快,要等专门的循环垃圾回收器(Cyclic Garbage Collector)来检测并回收这种引用循环。

str(self):

  • 当你打印一个对象的时候,触发__str__
  • 当你使用%s格式化的时候,触发__str__
  • str强转数据类型的时候,触发__str__

repr(self):

repr是str的备胎

  • 有__str__的时候执行__str__,没有实现__str__的时候,执行__repr__
  • repr(obj)内置函数对应的结果是__repr__的返回值
  • 当你使用%r格式化的时候 触发__repr__

str(self) 的返回结果可读性强。也就是说,str 的意义是得到便于人们阅读的信息,就像下面的 '2019-10-11' 一样。

repr(self) 的返回结果应更准确。怎么说,repr 存在的目的在于调试,便于开发者使用。

add(self, other)定义加法的行为:+

sub(self, other)定义减法的行为:-

mul(self, other)定义乘法的行为:*

truediv(self, other)定义真除法的行为:/

floordiv(self, other)定义整数除法的行为://

mod(self, other) 定义取模算法的行为:%

divmod(self, other)定义当被 divmod() 调用时的行为

divmod(a, b)把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a // b, a % b)。

pow(self, other[, module])定义当被 power() 调用或 ** 运算时的行为

lshift(self, other)定义按位左移位的行为:

rshift(self, other)定义按位右移位的行为:>>

and(self, other)定义按位与操作的行为:&

xor(self, other)定义按位异或操作的行为:^

or(self, other)定义按位或操作的行为:|

radd(self, other)定义加法的行为:+

rsub(self, other)定义减法的行为:-

rmul(self, other)定义乘法的行为:*

rtruediv(self, other)定义真除法的行为:/

rfloordiv(self, other)定义整数除法的行为://

rmod(self, other) 定义取模算法的行为:%

rdivmod(self, other)定义当被 divmod() 调用时的行为

rpow(self, other[, module])定义当被 power() 调用或 ** 运算时的行为

rlshift(self, other)定义按位左移位的行为:

rrshift(self, other)定义按位右移位的行为:>>

rand(self, other)定义按位与操作的行为:&

rxor(self, other)定义按位异或操作的行为:^

ror(self, other)定义按位或操作的行为:|

增量赋值运算符

iadd(self, other)定义赋值加法的行为:+=

isub(self, other)定义赋值减法的行为:-=

imul(self, other)定义赋值乘法的行为:*=

itruediv(self, other)定义赋值真除法的行为:/=

ifloordiv(self, other)定义赋值整数除法的行为://=

imod(self, other)定义赋值取模算法的行为:%=

ipow(self, other[, modulo])定义赋值幂运算的行为:**=

ilshift(self, other)定义赋值按位左移位的行为:

irshift(self, other)定义赋值按位右移位的行为:>>=

iand(self, other)定义赋值按位与操作的行为:&=

ixor(self, other)定义赋值按位异或操作的行为:^=

ior(self, other)定义赋值按位或操作的行为:|=

一元运算符

neg(self)定义正号的行为:+x

pos(self)定义负号的行为:-x

abs(self)定义当被abs()调用时的行为

invert(self)定义按位求反的行为:~x

属性访问

getattr(self, name): 定义当用户试图获取一个不存在的属性时的行为。

getattribute(self, name):定义当该类的属性被访问时的行为(先调用该方法,查看是否存在该属性,若不存在,接着去调用__getattr__)。

setattr(self, name, value):定义当一个属性被设置时的行为。

delattr(self, name):定义当一个属性被删除时的行为。

描述符

描述符就是将某种特殊类型的类的实例指派给另一个类的属性。

get(self, instance, owner)用于访问属性,它返回属性的值。

set(self, instance, value)将在属性分配操作中调用,不返回任何内容。

del(self, instance)控制删除操作,不返回任何内容。

定制序列

协议(Protocols)与其它编程语言中的接口很相似,它规定你哪些方法必须要定义。然而,在 Python 中的协议就显得不那么正式。事实上,在 Python 中,协议更像是一种指南。

容器类型的协议

如果说你希望定制的容器是不可变的话,你只需要定义__len__()和__getitem__()方法。

如果你希望定制的容器是可变的话,除了__len__()和__getitem__()方法,你还需要定义__setitem__()和__delitem__()两个方法。

迭代器

  • 迭代是 Python 最强大的功能之一,是访问集合元素的一种方式。
  • 迭代器是一个可以记住遍历的位置的对象。
  • 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。
  • 迭代器只能往前不会后退。
  • 字符串,列表或元组对象都可用于创建迭代器:

迭代器有两个基本的方法:iter() 和 next()。

iter(object) 函数用来生成迭代器。

next(iterator[, default]) 返回迭代器的下一个项目。

iterator -- 可迭代对象

default -- 可选,用于设置在没有下一个元素时返回该默认值,如果不设置,又没有下一个元素则会触发 StopIteration 异常

把一个类作为一个迭代器使用需要在类中实现两个魔法方法 iter() 与 next() 。

iter(self)定义当迭代容器中的元素的行为,返回一个特殊的迭代器对象, 这个迭代器对象实现了 next() 方法并通过 StopIteration 异常标识迭代的完成。

next() 返回下一个迭代器对象。

StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 next() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。

生成器

在 Python 中,使用了 yield 的函数被称为生成器(generator)。

跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。

调用一个生成器函数,返回的是一个迭代器对象。

def libs(n): a = 0 b = 1 while True: a, b = b, a + b if a > n: return yield a for each in libs(100): print(each, end=' ') # 1 1 2 3 5 8 13 21 34 55 89

相关推荐
A尘埃26 分钟前
大模型应用python+Java后端+Vue前端的整合
java·前端·python
A尘埃31 分钟前
LLM大模型评估攻略
开发语言·python
一晌小贪欢1 小时前
【Python办公】处理 CSV和Excel 文件操作指南
开发语言·python·excel·excel操作·python办公·csv操作
檀越剑指大厂2 小时前
【Python系列】fastapi和flask中的阻塞问题
python·flask·fastapi
YoungHong19923 小时前
【Python进阶】告别繁琐Debug!Loguru一键输出异常日志与变量值
python·debug·异常处理·日志·loguru·log·logger
AiXed3 小时前
PC微信协议之nid算法
python·网络协议·算法·微信
小李哥哥4 小时前
基于数据的人工智能建模流程及源码示例
python
APIshop4 小时前
实战解析:苏宁易购 item_search 按关键字搜索商品API接口
开发语言·chrome·python
蓝桉~MLGT5 小时前
Python学习历程——Python面向对象编程详解
开发语言·python·学习
larance5 小时前
Python 中的 *args 和 **kwargs
开发语言·python