Skip to content

Lesson 6

dict 类型(Dictionaries)

我们已经学习过 listtuple 这样的数据类型,也通过习题了解到 string 类型也可以像列表或者一样使用整数地址来访问其中的元素。在习题中的第9题,我们尝试着出了一题关于“字典”类型的题目,但是就作业的情况看没有人做出来。

创建与访问 dict

dict 类型是一种复合类型,是Python的内置类型。他的基本构成是由 key-value 对组成的。使用下列的方法可以建立一个空 dict:

an_empty_dict = {}
another_empty_dict = dict()

建立起一个空的dict后,我们就可以往里放入 key-value 对了。这种键值对的本质其实是一种映射的关系,即将key的值映射到value上,不严格的说也可以看做将key看做访问字典里value的地址。

下面我们创建一个 dict ,我们使用这个 dict描述一个游戏中的玩家角色。

player = dict()

player["name"] = "Jack Ma"
player["age"] = 48
player["money"] = 10000
player["weapons"] = ["m4a1", "C4", "knife"]

这样我们就定义了一个叫 player 的 dict, 这样我们就能使用这个角色去进行操作了。现在我们将字典 print 出来看看:

player = dict()

player["name"] = "Jack Ma"
player["age"] = 48
player["money"] = 10000
player["weapons"] = ["m4a1", "C4", "knife"]

print(player)

输出结果

{'name': 'Jack Ma', 'age': 48, 'money': 10000, 'weapons': ['m4a1', 'C4', 'knife']}

输出:

注意, dict 中的key和value可以使用目前我们学过的任何类型(有的要有特殊处理,以后遇到再讲)

现在我们期望给player添加一个背包的属性。我们可以先定义一个背包,每个key表示的是背包内的物品名称,value 则是该物品的数量。

bag = {
    "pizza": 3,
    "bottles": 4,
    "rope": 1,
}

定义好背包了,现在我们可以把 bag 这个变量放到 player 上了,下面是这个 player 的完整代码:

player = dict()

player["name"] = "Jack Ma"
player["age"] = 48
player["money"] = 10000
player["weapons"] = ["m4a1", "C4", "knife"]

bag = {
    "pizza": 3,
    "bottles": 4,
    "rope": 1,
    "bullets": 300
}

player["level1_bag"] = bag

print(player)

运行程序显示的结果为:

{'name': 'Jack Ma', 'age': 48, 'money': 10000, 'weapons': ['m4a1', 'C4', 'knife'], 'level1_bag': {'pizza': 3, 'bottles': 4, 'rope': 1}}

字典的基本操作

例子:我们可以封装一个函数,用于表示当我们捡到某个物品item时,把他放到你的背包中去。

def pickup(player, item, number):
    bag = player["level1_bag"]
    if item in bag:
        bag[item] = bag[item] + number
    else:
        bag[item] = number

当我们使用背包里的用品时,我们可能需要首先检查背包中有没有这个物品。那如何在一个字典内查询是否存在该 key:

def consume_bag(bag, item, number):
    if item in bag:
        if number > bag[item]:
            print("数量不够")
        else:
            bag[item] = bag[item] - number
            print("使用了", number,"数量的", item, ", 还有", bag[item], "。")
    else:
        print("不存在该物品")

从上面的两个代码可以看出,我们使用 in 操作符来获得某键值是否存在,使用 [] 来访问键值对应的值, 当然我们也可以用赋值来改变key的value。

获得全部键值

我们可以用 `keys()` 方法来获得所有key值的列表:
print(player.keys())
print(bag.keys())

遍例字典所有的 key-value pairs.

for k, v in bag.items():
    print(k,+ ": " + v)

获得 dict 中所以key-value pairs 的数量

同样的,我们使用 len 来获取key-pairs的数量。下面定义了一个函数 check_bag ,函数会整理出玩家身上背包里有物品种类的数量。

def check_bag(player):
    print("玩家共有", len(player["level1_bag"]), "种物品。")

小任务

现在我们来继续丰富我们的主角player的属性。

  1. 给 player 添加以下键值,并赋予合适的值:

    key value note
    skills ['Stabbing', 'Kicking', 'Cutting', 'Shooting'] 技巧
    blood 100 血量
    energy 100 精力值
    defense 10 防护
  2. 尝试创建一个敌人的 dict ,并定义合适的属性。

    enemy = {
        blood: 100,
        # ...
    }
    
  3. 写一个函数 kick ,他的参数有两个,第一个为踢人者,第二个为被踢者。这个函数表示踢人者踢了被踢者一脚,并且造成了双方状态的改变:花费踢人者 energy 10个点, 而被踢者失去 blood 值10个点,外加可能随机产生的1-5个点附加伤害。

    import random
    
    def kick(kicker, kick):
        # First check if "Kicking" is in the kicker's skills.
        if "Kicking" not in kicker["skills"]:
            return
    
        random_damage = random.randint(1, 6)
        #
    
  4. 你对这个 kick 函数有什么建议吗?你能设计一个你的 Kick 伤害算法吗?用语言描述出来。

  5. 可以定义一个enemy的列表吗, 尝试生成3个敌人, 然后你可写一段程序,用来表示3个敌人对玩家进行了长达二十轮的围殴吗(注意,玩家也可能有反抗)?

提示

enemy_list = []
enemy1 = {
    "name": "Rager B",
    "blood": 100,
    # ...
    }
enemy_list.append(enemy1)

字符串的一些遗留问题

字符串中的特殊字符

如何在字符串表示换行,只需要添加 "\n" 。注意,在字符串中,以反斜杠 "\" 开头的都是有特殊含义的字符,在编程语言中叫转义字符(Escape Character)。如果你要表示反斜杠本身的话,就要使用两个"\"。

还有很多的特殊含义字符,小伙伴们可以访问W3School Python转义字符,也可以用关键词 Escape Character Python 在搜索引擎中搜索得到。

字符串格式化

请先看这段上面出现的代码:

print("使用了", number,"数量的", item, ", 还剩下", bag[item], "。")

在上面的例子中,在输出字符串时,写的代码非常破碎,不能完整的展示我们想要的效果,而且还非常容易出错,这时候我们就可以使用字符串的格式化功能。

这样,上面的例子可以改写成:

output_str = "使用了{}数量的{}, 还剩下{}。".format(number, item, bag[item])
print(output_str)

这样, print 的代码就显得清爽了很多, 也很直观。同时也可以很清楚的看到: {} 位置的内容会被 format 里的内容一一替换

重要的工具——时间日期类 datetime

时间在实际生活中是必不可少的概念。所以在程序设计中如何表示时间也是非常重要的。在Python中内置了一个时间日期模块 datetime,里面提供了丰富的日期相关类库。下面介绍最基本的使用方法。

在使用日期功能前,需要先将 datetimeimport 语句引入,然后就可以使用 datetimenow() 方法来获取当前计算机的时间。 now() 方法返回的是一个时间日期类,

from datetime import datetime
moment = datetime.now()
print(moment)

程序输出:

2020-11-04 13:07:40.695187
' 我们还有以下常用的字段去获取年、月、日等你需要的数据。

from datetime import datetime
moment = datetime.now()
# 获得年,月,日

year = moment.year
month = moment.month
day = moment.day

# 获得小时,分钟和秒

hour = moment.hour
minute = moment.minute
second = moment.second

print("{}{}{}{}{}{}秒".format(year, month, day, hour, minute, second))

文件的简单读写

在我们玩游戏时有一个很常用的功能:保存进度。实际上就将程序加载到内存中的这些对象有状态,属性全部记录下来,保存到磁盘文件中。再到下次打开游戏时,把存档中的所有资料又加载到内存中,这样又相当于还原了游戏当时的状态。

Python中提供了非常方便的文件处理功能。现在我们简单的学习如何打开文件和保存文件。

from datetime import datetime
# 写文件
f = open("greetings.txt", "w")
now = datetime.now()
write_string = "Hello world!\n\nTheia Academy\n{}-{}-{}".format(now.year, now.month, now.day)
f.write(write_string)
f.close()

现在,在和你Python代码相同的路径下,就会出现一个叫 greetings.txt 的文件,你可以打开他,看看里面是什么内容?

那我们怎么把文件中的代码读进来呢?

f = open("greetings.txt", "r")
content = f.read()
f.close()
print(content)

这样,我们就把文件中的内容读取进来了,并且赋给了变量 content ,接着我们把它打印到了屏幕上。

思考题

思考一下如何将player, enemy的状态保存到文件里来。