人工智能和机器学习系列(三) Python 生成器和类

2021-08-24 10:57:05 浏览数 (2805)

简介

这是我们学习 Python 及其在机器学习 (ML) 和人工智能 (AI) 中的应用系列中的第三个模块。在上一个模块中,我们了解了数据结构和循环。现在让我们更深入地了解生成器和类。

生成器

创建自己的迭代器的一种方法是使用生成器函数。生成器函数使用yield关键字将下一个迭代器值传递给调用者。这类似于yield returnC# 中的关键字。一旦函数返回,就没有什么可以迭代的了。

让我们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)

__init__方法是构造函数。

length 是一个类方法

类方法的第一个参数是指正在处理的类实例。按照惯例,这称为self。(您可以将其命名为其他名称,但从来没有人这样做过。) 的作用self很像thisC# 和 Java 中的作用,即对当前对象的引用。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 没有诸如publicand 之类的访问修饰符private。所有变量都可以公开访问。以下划线开头的属性名称是一种告诉您的类的用户他们不应该使用该属性的方法,但这不是语言强制执行的。

继承

让我们演示如何从 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函数被 in 覆盖Bookoverride不需要关键字之类的东西),并且没有提及lengthinBook所以它只是从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", "...")
print(isinstance(doc, Book)) # False
print(isinstance(doc, Document)) # True

与 C# 和 Java 不同,Python 支持多重继承:Book(Document)您可以编写 class而不是编写 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__)

这个输出(<class '__main__.H'>, <class '__main__.F'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.A'>, <class '__main__.C'>, <class 'object'>)让你知道 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)

v1 = Vector(3, 2)
v2 = Vector(4, 1)
v3 = v1 + v2

__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)

这只是魔术方法的表面,您可以做的还有很多。

结论

在本模块中,我们讨论了迭代器、类、继承和魔术方法的生成器函数。现在我们已经了解了 Python 基础知识,接下来的模块,我们就可以开始接触人工智能和机器学习相关的内容了。