Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Cara menggunakan gelung Python dan iterator

Cara menggunakan gelung Python dan iterator

王林
王林ke hadapan
2023-05-20 15:04:11924semak imbas

Gambaran Keseluruhan Gelung

Dalam Python, seperti kebanyakan bahasa, terdapat dua gelung asas: while dan for. Gelung

while

while adalah sangat asas.

clue = None
while clue is None:
    clue = searchLocation()

clue is NoneDalam kes ini, kod untuk gelung akan dilaksanakan selagi keadaan gelung bernilai True.

Dalam Python, kami juga mempunyai beberapa kata kunci yang berguna: breakHentikan gelung serta-merta sambil continuemelompat ke lelaran seterusnya bagi gelung satu lelaran. Salah satu aspek yang paling berguna bagi

break ialah jika kita mahu menjalankan kod yang sama sehingga pengguna memberikan input yang sah.

while True:
    try:
        age = int(input("Enter your age: "))
    except ValueError:
        print(f"Please enter a valid integer!")
    else:
        if age > 0:
            break

Sebaik sahaja kami menemui kenyataan break ini, kami keluar dari gelung. Sudah tentu, di atas adalah contoh yang lebih kompleks, tetapi ia menunjukkan maksudnya. Anda juga sering melihat while True: digunakan dalam gelung permainan.

Nota: Jika anda pernah menggunakan gelung dalam mana-mana bahasa, anda sudah biasa dengan gelung tak terhingga (gelung tak terhingga). Ini biasanya disebabkan oleh keadaan while yang menilai kepada True dan tiada pernyataan break dalam gelung.

untuk

Daripada Java, C++ atau banyak bahasa gaya ALGOL yang serupa, anda mungkin biasa dengan gelung for tiga hala: for i := 1; i < 100; i := i + 1. Saya tidak tahu tentang anda, tetapi apabila saya mula-mula menghadapi situasi ini, saya terkejut. Saya gembira dengannya sekarang, tetapi ia tidak mempunyai kesederhanaan elegan Python.

Gelung for Python kelihatan sangat berbeza. Kod Python yang setara dengan pseudokod di atas ialah...

for i in range(1,100):
    print(i)

range() ialah "fungsi" khas dalam Python yang mengembalikan jujukan. (Secara teknikal, ia bukan satu fungsi sama sekali.)

Ini adalah perkara yang mengagumkan tentang Python - ia berulang pada jenis jujukan khas yang dipanggil iterable, Kita akan mengetahuinya kemudian .

Setakat ini, yang paling mudah difahami ialah kita boleh mengulang struktur data berjujukan, seperti tatasusunan (dipanggil "senarai" dalam Python).

Jadi kita boleh buat ini...

places = [&#39;Nashville&#39;, &#39;Norway&#39;, &#39;Bonaire&#39;, &#39;Zimbabwe&#39;, &#39;Chicago&#39;, &#39;Czechoslovakia&#39;]
for place in places:
    print(place)

print("...and back!")

Kita dapat ini...

Nashville
Norway
Bonaire
Zimbabwe
Chicago
Czechoslovakia
...and back!
untuk...lain

Python dalam gelungnya Di sana ialah satu lagi helah kecil yang unik: klausa else! Selepas gelung selesai, jika tidak menemui pernyataan , break akan dijalankan. Walau bagaimanapun, jika anda mengganggu gelung secara manual, ia else melangkau sepenuhnya. else

places = [&#39;Nashville&#39;, &#39;Norway&#39;, &#39;Bonaire&#39;, &#39;Zimbabwe&#39;, &#39;Chicago&#39;, &#39;Czechoslovakia&#39;]
villain_at = &#39;Mali&#39;

for place in places:
    if place == villain_at:
        print("Villain captured!")
        break
else:
    print("The villain got away again.")

Memandangkan "Mali" tiada dalam senarai, kami melihat mesej "Penjahat melarikan diri lagi." Walau bagaimanapun, jika kita menukar nilai daripada

kepada villain_at, kita akan melihat "Penjahat ditangkap!" Norway

Adakah...whiel?

Python tidak mempunyai

gelung. Jika anda sedang mencari cara untuk menggelung seperti ini, Python biasa ialah menggunakan do...while dengan while True: dalaman bersyarat, seperti yang kami tunjukkan sebelum ini. break

Struktur data (bekas)

Python mempunyai banyak

bekas atau struktur data yang menyimpan data. Kami tidak akan membincangkan mana-mana daripada mereka secara mendalam, tetapi saya ingin melihat dengan pantas bahagian yang paling penting:

senarai

senarai ialah jujukan boleh ubah (sebenarnya tatasusunan).

Ia ditakrifkan dengan kurungan segi empat sama

dan anda boleh mengakses elemennya mengikut indeks. [ ]

foo = [2, 4, 2, 3]

print(foo[1])
>>> 4

foo[1] = 42
print(foo)
>>> [2, 42, 2, 3]</code></p>Walaupun tiada keperluan teknikal yang ketat untuknya, konvensyen biasa ialah senarai hanya mengandungi unsur-unsur jenis yang sama ("homogen"). <p data-id="p838747a-P9ZA1elg"></p>tuple<h4 id="h7" data-id="h7f20189-K6dPB2JE"></h4>tuple ialah jujukan yang tidak berubah. Sebaik sahaja anda mentakrifkannya, anda <p data-id="p838747a-2knt7nOR">secara teknikal<em> tidak boleh mengubahnya (ingat semula maksud ketakbolehubahan sebelumnya). Ini bermakna selepas mentakrifkan tupel, anda tidak boleh menambah atau mengalih keluar elemen daripada tupel. </em></p>Tuple ditakrifkan dalam kurungan <p data-id="p838747a-ZzF8EUCk"> dan anda boleh mengakses elemennya mengikut indeks. <code>( )</code></p>
<pre class="brush:php;toolbar:false">foo = (2, 4, 2, 3)

print(foo[1])
>>> 4

foo[1] = 42
>>> TypeError: 'tuple' object does not support item assignment
Tidak seperti senarai, konvensyen standard membenarkan tupel mengandungi unsur jenis yang berbeza ("heterogen").

set

set是一个无序的可变集合,保证没有重复。记住“无序”很重要:不能保证单个元素的顺序!

一个集合在花括号中定义{ },但如果你想要一个空集合,你可以使用foo = set(), 或者foo = {}创建一个空的dict. 你不能通过索引访问它的元素,因为它是无序的。

foo = {2, 4, 2, 3}

print(foo)
>>> {2, 3, 4}

print(foo[1])
>>> TypeError: 'set' object does not support indexing

对于要添加到集合中的对象,它也必须是可散列的(hash)。一个对象是可散列的,如果:

  1. 它定义了方法__hash__(),该方法将哈希值(hash)作为整数返回。(见下文)

  2. 它定义了__eq__()比较两个对象的方法。

对于同一个对象(值),一个有效的散列值(hash)应该总是相同的,并且它应该是合理的唯一的,因此另一个对象返回相同的散列是不常见的。(两个或多个具有相同哈希值的对象称为哈希冲突,它们仍然会发生。)

dict

dict(字典)是键值数据结构。

它在花括号中定义{ }:用于分隔键和值。它是无序的,所以你不能通过索引访问它的元素;但是你可以通过[ ]加键值访问元素。

foo = {'a' : 1, 'b' : 2, 'c' : 3, 'd' : 4}

print(foo['b'])
>>> 2

foo['b'] = 42
print(foo)
>>> {'a': 1, 'b': 42, 'c': 3, 'd': 4}

只有可散列的对象可以用作字典键。(有关set哈希性的更多信息,请参阅官网的部分。)

其他

除了基础之外,Python 还提供了额外的容器/数据结构。可以在内置模块collections中找到它们。

拆包

有一个重要的 Python 语法我们还没有讨论过,但很快就会派上用场。我们可以将容器中的每个元素分配给一个变量!这称为拆包

当然,我们需要确切地知道我们要拆包多少才能结束,否则我们会得到一个ValueError的异常。

让我们看一个使用tuple元组的基本示例。

fullname = ('Carmen', 'Sandiego')
first, last = fullname
print(first)
>>> Carmen
print(last)
>>> Sandiego

看第二行代码,我们可以列出多个要分配的变量,用逗号分隔。Python 将拆分等号右侧的容器,将每个值按从左到右的顺序分配给一个变量。

注意:记住,set是无序的!虽然你可以在技术上使用集合来执行此操作,但你无法确定将什么值分配给什么变量。不保证按顺序进行分配,集合的值的分配顺序通常是偶然的!

in

Python 提供了一个关键字in ,用于检查是否在容器中找到了特定元素。

places = ['Nashville', 'Norway', 'Bonaire', 'Zimbabwe', 'Chicago', 'Czechoslovakia']

if 'Nashville' in places:
    print("Music city!")

这适用于许多容器,包括列表、元组、集合,甚至是字典键(但不是字典值)。

如果你希望你的自定义类之一支持in运算符,你只需要定义__contains__(self, item)方法,它应该返回Trueor False

迭代器

Python 的循环是配合我之前提到的迭代器一起使用前面提到的数据结构都是是可以使用迭代器迭代的对象。

好的,让我们从头开始。Python 容器对象,例如 list,也是一个可迭代对象,因为它的__iter__()方法,返回一个迭代器对象。

方法__next__()也是一个迭代器,在容器迭代器的情况下,返回下一项。即使是无序的容器,例如set(),也可以使用迭代器进行遍历。

__next__()不能返回任何其他内容时,它会抛出一个名为StopIteration的特殊异常。这可以使用try...except捕获异常。

让我们再看一下for遍历 list 的循环,例如...

dossiers = ['The Contessa', 'Double Trouble', 'Eartha Brute', 'Kneemoi', 'Patty Larceny', 'RoboCrook', 'Sarah Nade', 'Top Grunge', 'Vic the Slick', 'Wonder Rat']

for crook in dossiers:
    print(crook)

dossiers是一个list对象,它是一个可迭代的对象。当 Python 到达for循环时,它会做三件事:

  1. 调用iter(dossiers),依次执行dossiers.__iter__()。这将返回一个我们将调用的迭代器对象list_iter。这个迭代器对象将被循环使用。

  2. 对于循环的每次迭代,它都会调用next(list_iter),执行list_iter.__next__()并将返回的值分配给crook

  3. 如果迭代器抛出了特殊异常StopIteration,则循环结束,退出。

while True:如果我在循环中重写该逻辑可能会更容易理解......

list_iter = iter(dossiers)
while True:
    try:
        crook = next(list_iter)
        print(crook)
    except StopIteration:
        break

如果你尝试这两个循环,你会发现它们做的事情完全相同!

了解__iter__(),__next__()StopIteration异常的工作原理后,你现在可以使自己的类可迭代!

注意:虽然将迭代器类与可迭代类分开定义都可以,但你不一定必须这样做!只要这两种方法都在你的类中定义,并且__next__()行为适当,你就可以定义__iter__()return self.

值得注意的是迭代器本身是可迭代的:它们有一个__iter__()方法返回self

字典案例

假设我们有一本想要使用的字典......

locations = {
    'Parade Ground': None,
    'Ste.-Catherine Street': None,
    'Pont Victoria': None,
    'Underground City': None,
    'Mont Royal Park': None,
    'Fine Arts Museum': None,
    'Humor Hall of Fame': 'The Warrant',
    'Lachine Canal': 'The Loot',
    'Montreal Jazz Festival': None,
    'Olympic Stadium': None,
    'St. Lawrence River': 'The Crook',
    'Old Montréal': None,
    'McGill University': None,
    'Chalet Lookout': None,
    'Île Notre-Dame': None
    }

如果我们只想查看其中的每个项目,我们只需使用for循环。所以,这应该有效,对吧?

for location in locations:
    print(location)

哎呀!这只向我们展示了,而不是值。这并不是我们想要的,不是吗?

dict.__iter__()返回一个dict_keyiterator对象,该对象执行其类名的操作:它遍历键,但不遍历值。

同时获取键和值,我们需要调用locations.items()返回dict_items对象。dict_items.iter()返回 dict_itemiterator,它将字典中的每个键值对作为元组返回。

旧版说明:如果你使用的是 Python 2,则应改为调用locations.iteritems()

还记得刚才,当我们谈到拆包的时候吗?我们将每一对键值作为一个元组并拆分成两个变量。

for key, value in locations.items():
    print(f'{key} => {value}')

打印出以下内容:

Parade Ground => None
Ste.-Catherine Street => None
Pont Victoria => None
Underground City => None
Mont Royal Park => None
Fine Arts Museum => None
Humor Hall of Fame => The Warrant
Lachine Canal => The Loot
Montreal Jazz Festival => None
Olympic Stadium => None
St. Lawrence River => The Crook
Old Montréal => None
McGill University => None
Chalet Lookout => None
Île Notre-Dame => None

现在我们可以处理数据了。例如,我想在另一个字典中记录重要信息。

information = {}

for location, result in locations.items():
    if result is not None:
        information[result] = location

# Win the game!
print(information['The Loot'])
print(information['The Warrant'])
print(information['The Crook'])

print("Vic the Slick....in jaaaaaaaaail!")

这将找到 Loot、Warrant 和 Crook,并按正确顺序列出它们:

Lachine Canal
Humor Hall of Fame
St. Lawrence River
Vic the Slick....in jaaaaaaaaail!

自定义迭代器

我之前已经提到你可以制作自己的迭代器和迭代器,但现在来实现它!

想象一下,我们想方便保留一个代理列表,以便我们始终可以通过代理编号来识别它们。但是,有些代理是我们不能谈论的。我们可以通过将代理 ID 和名称存储在字典中,然后维护分类代理列表来轻松完成此操作。

注意:请记住,在我们对类的讨论中,Python 中实际上没有私有变量这样的东西。如果你真的打算保密,请使用行业标准的加密和安全实践,或者至少不要将你的 API 暴露给任何 VILE 操作员。;)

对于初学者,这是该类的基本结构:

class AgentRoster:
    def __init__(self):
        self._agents = {}
        self._classified = []

    def add_agent(self, name, number, classified=False):
        self._agents[number] = name
        if classified:
            self._classified.append(name)

    def validate_number(self, number):
        try:
            name = self._agents[number]
        except KeyError:
            return False
        else:
            return True

    def lookup_agent(self, number):
        try:
            name = self._agents[number]
        except KeyError:
            name = "<NO KNOWN AGENT>"
        else:
            if name in self._classified:
                name = "<CLASSIFIED>"
        return name

我们可以继续测试一下,只是为了后续:

roster = AgentRoster()

roster.add_agent("Ann Tickwitee", 2539634)
roster.add_agent("Ivan Idea", 1324595)
roster.add_agent("Rock Solid", 1385723)
roster.add_agent("Chase Devineaux", 1495263, True)

print(roster.validate_number(2539634))
>>> True
print(roster.validate_number(9583253))
>>> False

print(roster.lookup_agent(1324595))
>>> Ivan Idea
print(roster.lookup_agent(9583253))
>>> <NO KNOWN AGENT>
print(roster.lookup_agent(1495263))
>>> <CLASSIFIED>

太好了,这完全符合预期!现在,如果我们希望能够遍历整个字典怎么办。

但是,我们不想直接访问roster._agents字典,因为这将忽略这个类的整个“分类”方面。我们如何处理?

正如我之前提到的,我们可以让这个类也作为它自己的迭代器,这意味着它有一个__next__()方法。在这种情况下,我们只会 return self。但是,这里是超简单Python教程,所以让我们跳过烦人步骤,简化内容,实际创建一个单独的迭代器类。

在这个例子中,我实际上将字典变成了一个元组列表,这将允许我使用索引。(请记住,字典是无序的。)我还将计算出有多少代理分类。当然,所有这些逻辑都属于该__init__()方法:

class AgentRoster_Iterator:

    def __init__(self, container):
        self._roster = list(container._agents.items())
        self._classified = container._classified
        self._max = len(self._roster) - len(self._classified)
        self._index = 0

要成为迭代器,类必须有__next__()方法;这是唯一的要求!请记住,一旦我们没有更多数据要返回,该方法就需要抛出StopException异常。

我将定义AgentRoster_Iterator__next__()方法如下:

class AgentRoster_Iterator:

    # ...snip...

    def __next__(self):
        if self._index == self._max:
            raise StopIteration
        else:
            r = self._roster[self._index]
            self._index += 1
            return r

现在我们返回到AgentRoster类,我们需要在其中添加一个__iter__()返回迭代器对象的方法。

class AgentRoster:

    # ...snip...

    def __iter__(self):
        return AgentRoster_Iterator(self)

只需要一点点操作,现在我们的AgentRoster类的行为与循环的预期完全一样!这段代码如下...

roster = AgentRoster()

roster.add_agent("Ann Tickwitee", 2539634)
roster.add_agent("Ivan Idea", 1324595)
roster.add_agent("Rock Solid", 1385723)
roster.add_agent("Chase Devineaux", 1495263, True)

for number, name in roster:
    print(f'{name}, id #{number}')

产生的结果如下...

Ann Tickwitee, id #2539634
Ivan Idea, id #1324595
Rock Solid, id #1385723

Atas ialah kandungan terperinci Cara menggunakan gelung Python dan iterator. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam