1
0
mirror of https://github.com/apachecn/lmpythw-zh.git synced 2025-06-05 16:53:59 +00:00
lmpythw-zh/ex17.md
wizardforcel 9b8f8e3db3 ex17.
2017-08-07 21:06:31 +08:00

7.6 KiB
Raw Blame History

练习 17字典

你应该熟悉 Python 的dict类。无论什么时候,你编写这样的代码:

cars = {'Toyota': 4, 'BMW': 20, 'Audi': 10}

您在使用字典将车的品牌“丰田”“宝马”“奥迪”和你有的数量42010关联起来。现在使用这种数据结构应该是你的第二本能你可能甚至不考虑它是如何工作的。在本练习中您将通过从已经创建的数据结构实现自己的Dictionary来了解dict的工作原理。您在本练习中的目标是,根据我在这里写的代码实现自己的Dictionary版本。

挑战性练习

在本练习中,您将完全记录并理解我编写的一段代码,然后尽可能地,根据记忆编写自己的版本。本练习的目的是,学习剖析和理解复杂的代码。能够内在化或记忆,如何创建一个简单的数据结构(如字典)是很重要的性。我发现,学习剖析和理解一段代码的最好方法是,根据自己的学习和记忆来重新实现它。

将其看做一个“原件”类。原件来自绘画,其中你绘制一幅由他人创作的画,优于创作它的副本。这样做会教你如何绘画并且提高你的技能。代码和绘画是相似的,因为所有的信息都为复制准备好了,所以你可以通过复制他们的工作,轻松地向别人学习。

制作一份“代码大师的副本”

要创建一份“代码大师副本”,你将遵循这个的流程,我称之为 CASMIR 流程:

  • 复制代码,使其正常工作。你的副本应该完全一样。这有助于您了解它,并强制您仔细研究它。
  • 使用注释来标注代码,并为所有代码写一个分析,确保您了解每一行以及它的作用。这可能涉及到您编写的其他代码,来将整个概念结合在一起。
  • 使用简洁的说明,为这个代码的工作原理总结一般结构。这是函数列表和每个函数的作用。
  • 记住这个算法和关键代码段的简洁描述。
  • 根据记忆实现可以实现的东西,当你用尽细节时,回顾您的笔记和原始代码来记住更多内容。
  • 当你需要从你的记忆中复制的时候,重复此过程多次。你的记忆中的副本并不必须是完全一样的,但应接近,并通过你创建的相同测试。

这样做将使您深入了解数据结构的工作原理,但更为重要的是,帮助您内在化和回忆此数据结构。您终将能够理解该概念,并在需要创建数据结构时实现数据结构。这也是训练你的大脑,在未来记住其他的数据结构和算法。

警告

我要做的唯一的警告是,这是一个很简单,愚蠢,缓慢的Dictionary实现。你真的复制了一个简单愚蠢的Dictionary ,它具有所有的基本元素和作用,但需要大量改进来用于生产。当我们到达练习 19 并研究性能调整时,会进行这些改进。现在,只需实现这个简单的版本,就可以了解数据结构的基础知识。

复制代码

首先我们查看Dictionary的代码,你需要复制它:

from dllist import DoubleLinkedList

class Dictionary(object):
    def __init__(self, num_buckets=256):
        """Initializes a Map with the given number of buckets."""
        self.map = DoubleLinkedList()
        for i in range(0, num_buckets):
            self.map.push(DoubleLinkedList())

    def hash_key(self, key):
        """Given a key this will create a number and then convert it to
        an index for the aMap's buckets."""
        return hash(key) % self.map.count()

    def get_bucket(self, key):
        """Given a key, find the bucket where it would go."""
        bucket_id = self.hash_key(key)
        return self.map.get(bucket_id)

    def get_slot(self, key, default=None):
        """
        Returns either the bucket and node for a slot, or None, None
        """
        bucket = self.get_bucket(key)

        if bucket:
            node = bucket.begin
            i = 0

            while node:
                if key == node.value[0]:
                    return bucket, node
                else:
                    node = node.next
                    i += 1

        # fall through for both if and while above
        return bucket, None

    def get(self, key, default=None):
        """Gets the value in a bucket for the given key, or the default."""
        bucket, node = self.get_slot(key, default=default)
        return node and node.value[1] or node

    def set(self, key, value):
        """Sets the key to the value, replacing any existing value."""
        bucket, slot = self.get_slot(key)

        if slot:
            # the key exists, replace it
            slot.value = (key, value)
        else:
            # the key does not, append to create it
            bucket.push((key, value))

    def delete(self, key):
        """Deletes the given key from the Map."""
        bucket = self.get_bucket(key)
        node = bucket.begin

        while node:
            k, v = node.value
            if key == k:
                bucket.detach_node(node)
                break

    def list(self):
        """Prints out what's in the Map."""
        bucket_node = self.map.begin
        while bucket_node:
            slot_node = bucket_node.value.begin
            while slot_node:
                print(slot_node.value)
                slot_node = slot_node.next
            bucket_node = bucket_node.next

该代码使用您现有的DoubleLinkedList代码来实现dict数据结构。如果您不完全了解DoubleLinkedList,那么您应该尝试使用代码复制过程,让我们更好地理解它。一旦您确定您了解DoubleLinkedList,您可以键入此代码并使其正常工作。记住,在开始标注之前,它必须是完美的副本。你可以做的最糟糕的事情,是标注我的代码的破损或不正确的副本。

为了帮助您获得正确的代码,我写了一个快速和简陋的小型测试脚本:

from dictionary import Dictionary

# create a mapping of state to abbreviation
states = Dictionary()
states.set('Oregon', 'OR')
states.set('Florida', 'FL')
states.set('California', 'CA')
states.set('New York', 'NY')
states.set('Michigan', 'MI')

# create a basic set of states and some cities in them
cities = Dictionary()
cities.set('CA', 'San Francisco')
cities.set('MI', 'Detroit')
cities.set('FL', 'Jacksonville')

# add some more cities
cities.set('NY', 'New York')
cities.set('OR', 'Portland')


# print(out some cities
print('-' * 10)
print("NY State has: %s" % cities.get('NY'))
print("OR State has: %s" % cities.get('OR'))

# print(some states
print('-' * 10)
print("Michigan's abbreviation is: %s" % states.get('Michigan'))
print("Florida's abbreviation is: %s" % states.get('Florida'))

# do it by using the state then cities dict
print('-' * 10)
print("Michigan has: %s" % cities.get(states.get('Michigan')))
print("Florida has: %s" % cities.get(states.get('Florida')))

# print(every state abbreviation
print('-' * 10)
states.list()

# print(every city in state
print('-' * 10)
cities.list()

print('-' * 10)
state = states.get('Texas')

if not state:
  print("Sorry, no Texas.")

# default values using ||= with the nil result
# can you do this on one line?
city = cities.get('TX', 'Does Not Exist')
print("The city for the state 'TX' is: %s" % city)

我希望你也可以正确地键入这个代码,但是当你进入大师副本的下一个阶段时,你会把它变成一个正式的自动测试,你可以运行pytest。现在,只要让这个脚本工作,就可以让Dictionary类工作,之后你可以在下一个阶段清理它。