Python中的生成器、类、继承和魔术方法

在机器学习和人工智能领域,Python语言因其简洁和强大的库支持而备受欢迎。在之前的模块中,探讨了数据结构和循环。现在,让进一步了解生成器和类的概念。

生成器

生成器是创建自定义迭代器的一种方式。生成器函数使用yield关键字将下一个迭代值传递给调用者。这与C#中的yield return关键字似。一旦函数返回,就没有更多的迭代对象了。

让通过一个生成器函数来演示yield关键字,该函数生成斐波那契数列的前n个数字:

def fibonacci(n): a = 1 b = 1 for i in range(n): if i < 2: yield 1 else: c = a + b a = b b = c yield c

现在可以像使用range函数一样使用这个函数,例如在循环中:

for f in fibonacci(10): print(f)

这将打印出前十个斐波那契数。

也可以使用生成器函数来生成无限多的元素。

与C#或Java一样,Python也有类。Python提供了面向对象编程的所有标准特性。

让通过一个简单的例子来了解Python中的类:

from math import sqrt class Vector: def __init__(self, x, y): self.x = x self.y = y def length(self): return sqrt(self.x ** 2 + self.y ** 2)

在Python中,__init__方法是构造函数。length是一个类方法。类方法的第一个参数指的是正在处理的类实例。按照惯例,这被称为self。(可以用别的名字命名它,但没人这么做。)self的作用类似于C#和Java中的this,是对当前对象的引用。在Python中的区别是,不能只使用x而不是self.x,而且Python要求明确地将其作为第一个方法参数包含在内。

现在可以像下面这样使用这个类:

v = Vector(1, 1) print(v.length()) print(v.x) print(v.y)

如上所见,可以访问xy属性,也可以对其进行修改:

v.x = 2 print(v.length())

Python没有像publicprivate这样的访问修饰符。所有变量都是公开可访问的。以下划线开头的属性名是告诉的用户他们不应该使用该属性,但这不是由语言强制执行的。

继承

让演示如何在Python中从类派生。将创建一个基类Document和一个派生类Book:

class Document: def __init__(self, author, content): self.author = author self.content = content def length(self): return len(self.content) def info_summary(self): return "Document written by " + self.author class Book(Document): def __init__(self, author, content, pages): super().__init__(author, content) self.pages = pages def info_summary(self): return "Book written by {} of {} pages".format(self.author, self.pages)

Book类从Document类派生。在Book类的__init__方法中,这行代码调用了超类的构造函数:

super().__init__(author, content)

info_summary函数在Book中被覆盖(不需要像override关键字那样明确指出),Book中没有提到length,所以它只是从Document派生的。

book = Book("me", "... content ...", 50) print(book.length()) print(book.info_summary())

如果想检查某个对象是否属于某个类,可以使用isinstance函数:

print(isinstance(book, Book)) # True print(isinstance(book, Document)) # True print(isinstance(book, object)) # True doc = Document("someone else", "... content ...") print(isinstance(doc, Book)) # False print(isinstance(doc, Document)) # True

与C#和Java不同,Python支持多重继承:可以写成class Book(Document),也可以写成class Book(Document, AnotherClass, PerhapsEvenMore)。如果超类中有同名的方法,子类只能派生其中的一个。当调用一个方法(没有明确覆盖)时,Python使用名为C3线性化的算法来确定在超类中查找的顺序。如果想查看所谓的方法解析顺序,可以查看YourClassName.__mro__属性。这里有一个人为的例子来演示这一点:

class A: pass class B: pass class C: pass class D(A, C): pass class F(B, C): pass class G(A): pass class H(F, B, D, A): pass print(H.__mro__)

这将输出(, , , , , , ),所以就知道Python会首先在H类中查找,其次是B、D、A,最后是C。

魔术方法

Python提供了许多“魔术方法”,允许进行操作符重载,将类实例视为迭代器等等。

魔术方法就像普通方法一样,但是有一个特定的名称格式__method_name__。已经知道一个魔术方法__init__。另一个例子是__add__魔术方法,用于重载+操作符:

class Vector: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): return Vector(self.x + other.x, self.y + other.y)

__iter__和__next__魔术方法使能够迭代实例。这个方法返回下一个迭代值或引发StopIteration来表示结束。

class Fibonacci: def __init__(self, n): self.prev = 1 self.prev_prev = 1 self.n = n self.i = 0 def __iter__(self): return self def __next__(self): self.i += 1 if self.i == self.n + 1: raise StopIteration if self.i <= 2: return 1 else: current = self.prev + self.prev_prev self.prev_prev = self.prev self.prev = current return current

for fib in Fibonacci(10): print(fib)

这只是魔术方法的表面,可以做更多。如果感兴趣,可以参考这个指南。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485