This notebook is an exercise in the Python course. You can reference the tutorial at this link.
Try It Yourself
Think you are ready to use Booleans and Conditionals? Try it yourself and find out.
To get started, run the setup code below before writing your own code (and if you leave this notebook and come back later, don't forget to run the setup code again).
自己尝试一下
您认为您已准备好使用布尔值和条件吗? 自己尝试一下就知道了。
首先,在编写您自己的代码之前运行下面的设置代码(如果您离开此笔记本并稍后返回,请不要忘记再次运行设置代码)。
from learntools.core import binder; binder.bind(globals())
from learntools.python.ex3 import *
print('Setup complete.')
Setup complete.
Exercises
练习
1.
Many programming languages have sign
available as a built-in function. Python doesn't, but we can define our own!
In the cell below, define a function called sign
which takes a numerical argument and returns -1 if it's negative, 1 if it's positive, and 0 if it's 0.
1.
许多编程语言都有 sign
作为内置函数。 Python 没有,但我们可以定义自己的!
在下面的单元格中,定义一个名为sign
的函数,它接受一个数字参数,如果为负则返回 -1,如果为正则返回 1,如果为 0,则返回 0。
# Your code goes here. Define a function called 'sign'
def sign(x):
if x > 0:
return 1
elif x < 0:
return -1
else:
return 0
# Check your answer
q1.check()
Correct
#q1.solution()
2.
We've decided to add "logging" to our to_smash
function from the previous exercise.
2.
我们决定将日志记录
添加到上一个练习中的to_smash
函数中。
def to_smash(total_candies):
"""Return the number of leftover candies that must be smashed after distributing
the given number of candies evenly between 3 friends.
>>> to_smash(91)
1
"""
print("Splitting", total_candies, "candies")
return total_candies % 3
to_smash(91)
Splitting 91 candies
1
What happens if we call it with total_candies = 1
?
如果我们用total_candies = 1
调用它会发生什么?
to_smash(1)
Splitting 1 candies
1
That isn't great grammar!
Modify the definition in the cell below to correct the grammar of our print statement. (If there's only one candy, we should use the singular "candy" instead of the plural "candies")
这不是很好的语法!
修改下面单元格中的定义以更正打印语句的语法。 (如果只有一种糖果,我们应该使用单数candy
而不是复数candies
)
def to_smash(total_candies):
"""Return the number of leftover candies that must be smashed after distributing
the given number of candies evenly between 3 friends.
>>> to_smash(91)
1
"""
if total_candies > 1:
print("Splitting", total_candies, "candies")
elif total_candies == 1:
print("Splitting", total_candies, "candy")
return total_candies % 3
to_smash(91)
to_smash(1)
Splitting 91 candies
Splitting 1 candy
1
# Check your answer (Run this code cell to receive credit!)
q2.solution()
Solution: A straightforward (and totally fine) solution is to replace the original print
call with:
if total_candies == 1:
print("Splitting 1 candy")
else:
print("Splitting", total_candies, "candies")
Here's a slightly more succinct solution using a conditional expression:
print("Splitting", total_candies, "candy" if total_candies == 1 else "candies")
3. 🌶️
In the main lesson we talked about deciding whether we're prepared for the weather. I said that I'm safe from today's weather if...
- I have an umbrella...
- or if the rain isn't too heavy and I have a hood...
- otherwise, I'm still fine unless it's raining and it's a workday
The function below uses our first attempt at turning this logic into a Python expression. I claimed that there was a bug in that code. Can you find it?
To prove that prepared_for_weather
is buggy, come up with a set of inputs where either:
- the function returns
False
(but should have returnedTrue
), or - the function returned
True
(but should have returnedFalse
).
To get credit for completing this question, your code should return a Correct result.
3. 🌶️
在主课中,我们讨论了决定我们是否为天气做好了准备。 我说过今天的天气对我来说是安全的,如果……
- 我有雨伞...
- 或者如果雨不太大并且我有兜帽的话...
- 否则,我还是很好,除非下雨并且这是一个工作日
下面的函数是我们第一次尝试将此逻辑转换为 Python 表达式。 我声称该代码中有一个错误。 你能找到吗?
为了证明prepared_for_weather
有问题,请提出一组输入,其中:
- 函数返回
False
(但应该返回True
),或者 - 函数返回
True
(但应该返回False
)。
要获得完成此问题的积分,您的代码应返回正确结果。
def prepared_for_weather(have_umbrella, rain_level, have_hood, is_workday):
# Don't change this code. Our goal is just to find the bug, not fix it!
return have_umbrella or rain_level < 5 and have_hood or not rain_level > 0 and is_workday
# Change the values of these inputs so they represent a case where prepared_for_weather
# returns the wrong answer.
have_umbrella = False
rain_level = 0.0
have_hood = False
is_workday = False
# Check what the function returns given the current values of the variables above
actual = prepared_for_weather(have_umbrella, rain_level, have_hood, is_workday)
print(actual)
# Check your answer
q3.check()
False
Correct:
One example of a failing test case is:
have_umbrella = False
rain_level = 0.0
have_hood = False
is_workday = False
Clearly we're prepared for the weather in this case. It's not raining. Not only that, it's not a workday, so we don't even need to leave the house! But our function will return False on these inputs.
The key problem is that Python implictly parenthesizes the last part as:
(not (rain_level > 0)) and is_workday
Whereas what we were trying to express would look more like:
not (rain_level > 0 and is_workday)
失败的测试用例的一个示例是:
have_umbrella = False
rain_level = 0.0
have_hood = False
is_workday = False
显然,我们已经为这种情况做好了准备。 没有下雨。 不仅如此,今天不是工作日,所以我们甚至不需要离开家! 但我们的函数将在这些输入上返回 False。
关键问题是 Python 隐式地将最后一部分括起来:
(not (rain_level > 0)) and is_workday
而我们试图表达的内容看起来更像是:
not (rain_level > 0 and is_workday)
q3.hint()
q3.solution()
Hint: Take a look at how we fixed our original expression in the main lesson. We added parentheses around certain subexpressions. The bug in this code is caused by Python evaluating certain operations in the "wrong" order.
Solution: One example of a failing test case is:
have_umbrella = False
rain_level = 0.0
have_hood = False
is_workday = False
Clearly we're prepared for the weather in this case. It's not raining. Not only that, it's not a workday, so we don't even need to leave the house! But our function will return False on these inputs.
The key problem is that Python implictly parenthesizes the last part as:
(not (rain_level > 0)) and is_workday
Whereas what we were trying to express would look more like:
not (rain_level > 0 and is_workday)
4.
The function is_negative
below is implemented correctly - it returns True if the given number is negative and False otherwise.
However, it's more verbose than it needs to be. We can actually reduce the number of lines of code in this function by 75% while keeping the same behaviour.
See if you can come up with an equivalent body that uses just one line of code, and put it in the function concise_is_negative
. (HINT: you don't even need Python's ternary syntax)
4.
下面的函数is_negative
已正确实现 - 如果给定数字为负数,则返回 True,否则返回 False。
但是,它比需要的更详细。 实际上,我们可以将该函数中的代码行数减少75%,同时保持相同的行为。
看看你是否可以想出一个仅使用 一行 代码的等效主体,并将其放入函数 concise_is_negative
中。 (提示:你甚至不需要 Python 的三元语法)
def is_negative(number):
if number < 0:
return True
else:
return False
def concise_is_negative(number):
#pass # Your code goes here (try to keep it to one line!)
return number < 0
# Check your answer
q4.check()
Correct
#q4.hint()
q4.solution()
Solution:
return number < 0
5.
The boolean variables ketchup
, mustard
and onion
represent whether a customer wants a particular topping on their hot dog. We want to implement a number of boolean functions that correspond to some yes-or-no questions about the customer's order. For example:
5.
布尔变量番茄酱
、芥末
和洋葱
表示顾客是否想要在热狗上添加特定的配料。 我们想要实现一些布尔函数,这些函数对应于有关客户订单的一些是或否问题。 例如:
def onionless(ketchup, mustard, onion):
"""Return whether the customer doesn't want onions.
"""
return not onion
For each of the remaining functions, fill in the body to match the English description in the docstring.
对于其余每个函数,填写正文以匹配文档字符串中的英文描述。
def wants_all_toppings(ketchup, mustard, onion):
"""Return whether the customer wants "the works" (all 3 toppings)
"""
# pass
return ketchup and mustard and onion
# Check your answer
q5.a.check()
Correct
#q5.a.hint()
q5.a.solution()
Solution:
return ketchup and mustard and onion
def wants_plain_hotdog(ketchup, mustard, onion):
"""Return whether the customer wants a plain hot dog with no toppings.
"""
#pass
return not ketchup and not mustard and not onion
# Check your answer
q5.b.check()
Correct:
One solution looks like:
return not ketchup and not mustard and not onion
We can also "factor out" the nots to get:
return not (ketchup or mustard or onion)
#q5.b.hint()
#q5.b.solution()
def exactly_one_sauce(ketchup, mustard, onion):
"""Return whether the customer wants either ketchup or mustard, but not both.
(You may be familiar with this operation under the name "exclusive or")
"""
#pass
return ketchup and not mustard or (not ketchup and mustard)
# Check your answer
q5.c.check()
Correct
q5.c.hint()
q5.c.solution()
Hint: There are exactly two ways to set ketchup and mustard to make this true. What are they?
Solution:
return (ketchup and not mustard) or (mustard and not ketchup)
6. 🌶️
We’ve seen that calling bool()
on an integer returns False
if it’s equal to 0 and True
otherwise. What happens if we call int()
on a bool? Try it out in the notebook cell below.
Can you take advantage of this to write a succinct function that corresponds to the English sentence "does the customer want exactly one topping?"?
我们已经看到,如果整数等于 0,则调用bool()
将返回False
,否则返回True
。 如果我们对 bool 调用 int()
会发生什么? 在下面的笔记本单元中尝试一下。
你能利用这一点写一个简洁的函数来对应英语句子顾客想要一种配料吗?
?
def exactly_one_topping(ketchup, mustard, onion):
"""Return whether the customer wants exactly one of the three available toppings
on their hot dog.
"""
#pass
return (ketchup+mustard+onion) == 1
# Check your answer
q6.check()
Correct:
This condition would be pretty complicated to express using just and
, or
and not
, but using boolean-to-integer conversion gives us this short solution:
return (int(ketchup) + int(mustard) + int(onion)) == 1
Fun fact: we don't technically need to call int
on the arguments. Just by doing addition with booleans, Python implicitly does the integer conversion. So we could also write...
return (ketchup + mustard + onion) == 1
#q6.hint()
q6.solution()
Solution: This condition would be pretty complicated to express using just and
, or
and not
, but using boolean-to-integer conversion gives us this short solution:
return (int(ketchup) + int(mustard) + int(onion)) == 1
Fun fact: we don't technically need to call int
on the arguments. Just by doing addition with booleans, Python implicitly does the integer conversion. So we could also write...
return (ketchup + mustard + onion) == 1
7. 🌶️ (Optonal)
In this problem we'll be working with a simplified version of blackjack (aka twenty-one). In this version there is one player (who you'll control) and a dealer. Play proceeds as follows:
- The player is dealt two face-up cards. The dealer is dealt one face-up card.
- The player may ask to be dealt another card ('hit') as many times as they wish. If the sum of their cards exceeds 21, they lose the round immediately.
- The dealer then deals additional cards to himself until either:
- the sum of the dealer's cards exceeds 21, in which case the player wins the round
- the sum of the dealer's cards is greater than or equal to 17. If the player's total is greater than the dealer's, the player wins. Otherwise, the dealer wins (even in case of a tie).
When calculating the sum of cards, Jack, Queen, and King count for 10. Aces can count as 1 or 11 (when referring to a player's "total" above, we mean the largest total that can be made without exceeding 21. So e.g. A+8 = 19, A+8+8 = 17)
For this problem, you'll write a function representing the player's decision-making strategy in this game. We've provided a very unintelligent implementation below:
在这个问题中,我们将使用 blackjack 的简化版本(又名二十一点)。 在此版本中,有一名玩家(由您控制)和一名庄家。 比赛进行如下:
- 向玩家发两张面朝上的牌。 庄家收到一张面朝上的牌。
- 玩家可以要求再次发牌(“击中”),次数不限。 如果他们的牌总和超过21,他们立即输掉这一轮。
- 然后庄家给自己发额外的牌,直到:
- 庄家的牌总数超过 21 点,在这种情况下,玩家赢得该轮
- 庄家的牌总数大于或等于17。如果玩家的牌总数大于庄家的牌,则玩家获胜。 否则,庄家获胜(即使是平局)。
在计算牌的总和时,J、Q 和 K 计为 10。A 可以计为 1 或 11(上面提到玩家的“总数”时,我们指的是不超过 21 的最大总数。因此,例如 A+8 = 19, A+8+8 = 17)
对于这个问题,您将编写一个函数来表示玩家在该游戏中的决策策略。 我们在下面提供了一个非常不智能的实现:
def should_hit(dealer_total, player_total, player_low_aces, player_high_aces):
"""Return True if the player should hit (request another card) given the current game
state, or False if the player should stay.
When calculating a hand's total value, we count aces as "high" (with value 11) if doing so
doesn't bring the total above 21, otherwise we count them as low (with value 1).
For example, if the player's hand is {A, A, A, 7}, we will count it as 11 + 1 + 1 + 7,
and therefore set player_total=20, player_low_aces=2, player_high_aces=1.
See in-line for strategy.
"""
#If player total is less than 12
if (player_total < 12
# or player total is 12 and dealer total is not 4, 5, or 6
or (player_total == 12 and dealer_total not in (4,5,6))
# or player total is less than 17 and dealer total is greater than 6
or (player_total < 17 and dealer_total > 6)
# or player total is between 12 and 17 and player has 1 "high" ace
or (player_total > 12 and player_total < 18 and player_high_aces == 1)
):
#Hit!
return True
# Else, Stay
else:
return False
This very conservative agent always sticks with the hand of two cards that they're dealt.
We'll be simulating games between your player agent and our own dealer agent by calling your function.
Try running the function below to see an example of a simulated game:
这位非常保守的特工总是坚持发给他们的两张牌。
我们将通过调用您的函数来模拟您的玩家代理和我们自己的荷官代理之间的游戏。
尝试运行下面的函数来查看模拟游戏的示例:
q7.simulate_one_game()
Player starts with 6 and 6 (total = 12)
Dealer starts with 10
__Player's turn__
Player hits and receives A. (total = 13)
Player hits and receives 9. (total = 22)
Player busts! Dealer wins.
The real test of your agent's mettle is their average win rate over many games. Try calling the function below to simulate 50000 games of blackjack (it may take a couple seconds):
对你的经纪人勇气的真正考验是他们在许多比赛中的平均胜率。 尝试调用下面的函数来模拟 50000 场二十一点游戏(可能需要几秒钟):
q7.simulate(n_games=50000)
Player won 21323 out of 50000 games (win rate = 42.6%)
Our dumb agent that completely ignores the game state still manages to win shockingly often!
Try adding some more smarts to the should_hit
function and see how it affects the results.
我们完全无视游戏状态的愚蠢智能体仍然经常令人震惊地获胜!
尝试向should_hit
函数添加更多智能,看看它如何影响结果。
def should_hit(dealer_total, player_total, player_low_aces, player_high_aces):
"""Return True if the player should hit (request another card) given the current game
state, or False if the player should stay.
When calculating a hand's total value, we count aces as "high" (with value 11) if doing so
doesn't bring the total above 21, otherwise we count them as low (with value 1).
For example, if the player's hand is {A, A, A, 7}, we will count it as 11 + 1 + 1 + 7,
and therefore set player_total=20, player_low_aces=2, player_high_aces=1.
"""
return False
q7.simulate(n_games=50000)
Player won 19126 out of 50000 games (win rate = 38.3%)
有很多策略,具体可以看https://www.kaggle.com/discussions/getting-started/58735
Keep Going
Learn about lists and tuples to handle multiple items of data in a systematic way.
继续
了解 列表和元组 以系统的方式处理多项数据。
Have questions or comments? Visit the Learn Discussion forum to chat with other Learners.