• 魔法方法
    关于魔法方法,其实是有比较多的,但我现在接触的最多的莫过于“构造函数”了,而在之前的文章中同样对于该函数有过介绍,这次主要是将我对这个知识点的一个困惑写出来,希望能对有相同困惑的读者提供一点点帮助,也是为自己做下记录。
    1、子类继承父类(也就是在class B(A))之后,没有重写父类的构造函数,那么也不需要在子类中重新对父类的构造函数重新初始化了,就像我的第一张截图上所定义的子类,其中没有任何的初始化函数,但是子类的实例依然完成了父类构造函数的初始化。
    2、子类继承父类后,自己重写了构造函数,这个时候就要在子类的构造函数中重新对父类的构造函数进行初始化,不然子类的实例只会对子类的构造函数进行初始化,而不会对父类的构造函数进行初始化。
    总的来说,若是子类没有重写构造函数,那么子类的实例就会直接初始化父类的构造函数;若是子类重写了构造函数,就相当于对父类的构造函数进行了覆盖,若想初始化父类的构造函数,就必须要在子类的构造函数中再进行定义
    这是因为我在之前总是以为,当子类继承了父类之后,其中的属性和方法均完全继承过来,所以我在看到重写子类构造函数时候还要再重新对父类的构造函数进行初始化感到困惑。
  • 生成器&迭代器
  • 生成器
    关于生成器,不知道大家是否还记得我之前文章中介绍的列表推导式,而我们不管是使用列表推导式还是循环的方式,都是直接生成全部的列表,但是若是列表中的元素过多,而我们一时又不需要使用那么多的元素,这样就会造成内存的大量浪费,而生成器则是边循环、边计算的机制,我觉得在现在这个刚开始的阶段,这样理解是可以的,而从代码的层面上来说,最简单的一种方式,就是将列表推导式的中括号变为小括号,即创建了一个生成器。
# 列表生成式
 lis = [x*x for x in range(10)]
 print(lis)

 # 生成器
 generator_ex = (x*x for x in range(10))
 print(generator_ex)

 # 结果:
 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
 <generator object <genexpr> at 0x000002A4CBF9EBA0>

从上面的代码的结果我们可以看出,列表生成式中生成的以列表,而生成器生成的则是生成器对象,我们可以通过next方法将其值打印出来。但实际上述代码只是为了方便理解,而实际上生成器中会使用关键字 yield来对返回值进行操作,但其要和next和其进行配合,调用一次next方法,会返回一次yield对应的值,同时在进行下一次迭代的时候,会从yield的下一句开始执行,直至遇到下一个yield

>>> def func(n):
 ...     yield n * 2
 ...
 >>> g = func(5)
 >>> g
 <generator object func at 0x102ae8ba0>
 >>> next(g)
 10
  • 迭代器
    迭代器就是用于迭代操作(for循环)的对象,它像列表一样可以迭代选取其中的每一个元素,任何实现了__next__方法的对象都可以称之为迭代器。

它与列表的区别在于,构建迭代器的时候,不像列表把所有元素一次性加载到内存,而是以一种延迟计算(lazy evaluation)方式返回元素,这正是它的优点。比如列表含有中一千万个整数,需要占超过400M的内存,而迭代器只需要几十个字节的空间。因为它并没有把所有元素装载到内存中,而是等到调用 next 方法时候才返回该元素(按需调用 call by need 的方式,本质上 for 循环就是不断地调用迭代器的next方法)。

  • 另外:生成器本身就是一种迭代器
    ⚠️:可迭代对象和迭代器的区别
    可迭代对象:一个实现了iter方法的对象是可迭代的:字符串、列表、元组、字典、集合(但是他们可以通过使用iter()函数获得一个迭代器对象。)
    迭代器:一个实现next方法的对象是迭代器。
    文件既是可迭代对象又是迭代器

因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。