(本号正在连续推出以Python官网文档为主线的系统学习Python的系列文章和视频,感兴趣的朋友们欢迎搜索关注。本文及后续文章如无特别声明均以Windows平台作为演示平台,Python版本为:3.8.1)

【本篇继上篇Python学习入门教程(28)—类(之三)继续讲解关于”类”的内容】

私有变量

在Python中不存在只能从对象内部访问的“私有”实例变量。但是,有一个约定是大多数Python代码都遵循的:以下划线(例如_spam)为前缀的名称应该被视为非公共部分(无论是函数、方法、还是数据成员)。这类变量应该被视为实现细节,是可以在不通知的情况下进行更改的。

为了避免当前类中定义的名称与其子类中定义的名称之间的冲突,Python提供称为命名重整(name mangling)的机制对此进行了有限的支持。任何形如__spam的标识符(至少有两个前导下划线,最多一个尾划线)都被替换成_classname_ spam的形式,其中classname是当前类名。标识符只要出现在类定义中不管其所在的位置在哪里都会被重整。命名重整有助于让子类重写方法而不破坏类内方法的调用。例如:

class Mapping:
    def __init__(self, iterable):
        self.items_list = []
        self.__update(iterable)
    def update(self, iterable):
        for item in iterable:
            self.items_list.append(item)
    __update = update   # private copy of original update() method
class MappingSubclass(Mapping):
    def update(self, keys, values):
        # provides new signature for update()
        # but does not break __init__()
        for item in zip(keys, values):
            self.items_list.append(item)

即使MappingSubclass引入了一个__update标识符,上面的示例也可以工作,因为它分别替换为Mapping中的_mapping__update和MappingSubclass类中的_mappingsubclass__update了。

重整规则的设计主要是为了避免冲突。尽管如此仍然可以访问或修改被认为是私有的变量。这在特殊情况下很有用,例如在调试器中。

空类的用处

有时需要用到类似于Pascal“record”或C“struct”的数据类型,这样的数据类型可以将一些命名的数据项捆绑在一起。Python中的空类就能实现这一需求:

class Employee:
    pass
john = Employee()  # Create an empty employee record
# Fill the fields of the record
john.name = 'John Doe'
john.dept = 'computer lab'
john.salary = 1000

一段期望特定抽象数据类型的Python代码通常可以使用一个可以模拟该数据类型的方法的类来代替。例如,如果有一个函数用来格式化来自文件对象的一些数据,那么可以定义一个具有从字符串缓冲区获取数据的read()和readline()方法的类,并将其作为参数传递给该函数。

实例的方法对象(假设为m)也有属性:m.self是具有方法m的实例,m.__func__是与此方法对应的函数对象。

具有迭代功能的类

到目前为止,我们见到大多数容器对象是可以使用for循环语句的,如:

for element in [1, 2, 3]:
		print(element)
for element in (1, 2, 3):
    print(element)
for key in {'one':1, 'two':2}:
    print(key)
for char in "123":
    print(char)
for line in open("myfile.txt"):
    print(line, end='')

这种访问方式清晰、简洁、方便,本质上是使用迭代器工作的。在Python中迭代器的使用是遍及和统一的。实际上,for语句调用了容器对象上的iter(),该函数返回一个迭代器对象,该对象定义了一次访问容器中一个元素的方法__next__()。当没有更多的元素时,__next__()引发一个StopIteration异常,该异常告诉for终止循环。可以使用next()内置函数调用__next__()方法python判断字符串为空python判断字符串为空,下面这个例子展示了它是如何工作的:

>>> s = 'abc'
>>> it = iter(s)
>>> it

>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
  File "", line 1, in 
    next(it)
StopIteration

了解了迭代器背后的运行机制之后,很容易将迭代器行为添加到自定义的类中:在类中定义一个__iter__()方法,让该方法返回一个具有__next__()方法的对象即可。如果类定义了__next__(),那么__iter__()直接返回self即可:

class Reverse:
    """Iterator for looping over a sequence backwards."""
    def __init__(self, data):
        self.data = data
        self.index = len(data)
    def __iter__(self):
        return self
    def __next__(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]

>>> rev = Reverse('spam')
>>> iter(rev)

>>> for char in rev:
...     print(char)
...
m
a
p
s

生成器

生成器是创建迭代器的简单而强大的工具。编写生成器像编写常规函数一样,但是在需要返回数据时使用yield语句。每次在其上调用next()时,生成器将从它上次停止的地方恢复执行(生成器记得所有数据值和最后执行的语句)。生成器可以很容易地创建,如下:

def reverse(data):
    for index in range(len(data)-1, -1, -1):
        yield data[index]

>>> for char in reverse('golf'):
...     print(char)
...
f
l
o
g

用生成器完成的任何工作也可以用基于类的迭代器完成。生成器之所以如此紧凑,是因为其__iter__()和__next__()方法是自动创建的。

另一个关键特性是生成器在相邻两次调用之间会自动保存本地变量和当前的执行状态。这使得该函数比使用self.index和self.data这样的实例变量更清晰且更容易编写。

除了自动创建方法和保存程序状态外,当生成器终止时,它们还会自动引发StopIteration。总之,这些特性使得创建迭代器不费吹灰之力,比编写一个常规函数容易的多。

生成器表达式

一些简单的生成器可以简单地编码为表达式,使用类似于列表推导式的语法,但使用圆括号而不是方括号。这些表达式是为包含生成器的函数立即使用该生成器的情况而设计的。与完整的生成器定义相比,生成器表达式更紧凑,但通用性差些,与等价的列表理解相比生成器表达式更节省内存。

例子:

>>> sum(i*i for i in range(10))                 # sum of squares
285
>>> xvec = [10, 20, 30]
>>> yvec = [7, 5, 3]
>>> sum(x*y for x,y in zip(xvec, yvec))         # dot product
260
>>> unique_words = set(word for line in page  for word in line.split())
>>> valedictorian = max((student.gpa, student.name) for student in graduates)
>>> data = 'golf'
>>> list(data[i] for i in range(len(data)-1, -1, -1))
['f', 'l', 'o', 'g']

【结束】

python基础教程教材 Python编程从零基础到项目实战实例

¥59

购买

篇尾寄语:万丈高楼平地起,是否具有扎实的基础决定一个人能否走远以及能走多远。Python的学习也是同样的道理!

限时特惠:本站每日持续更新海量设计资源,一年会员只需29.9元,全站资源免费下载
站长微信:ziyuanshu688