十一、标题党生成器
原文:http://inventwithpython.com/bigbookpython/project11.html
这个程序中有很多标题模板的文本,但是代码本身很简单,适合初学者。
运行示例
当您运行clickbait.py
时,输出将如下所示:
Clickbait Headline Generator
By Al Sweigart email@protected
Our website needs to trick people into looking at ads!
Enter the number of clickbait headlines to generate:
> 1000
Big Companies Hate Him! See How This New York Cat Invented a Cheaper Robot
What Telephone Psychics Don't Want You To Know About Avocados
You Won't Believe What This North Carolina Shovel Found in Her Workplace
`--snip--`
14 Reasons Why Parents Are More Interesting Than You Think (Number 1 Will Surprise You!)
What Robots Don't Want You To Know About Cats
This Florida Telephone Psychic Didn't Think Robots Would Take Her Job. She Was Wrong.
工作原理
这个程序有几个函数来生成不同类型的标题党。他们每个人都从STATES
、NOUNS
、PLACES
、WHEN
和其他列表中获得随机单词。这些函数然后用format()
字符串方法将这些单词插入到一个模板字符串中,然后返回这个字符串。这就像一本“Mad Libs”活动书,只是电脑会填空,让程序在几秒钟内生成数千个标题党。
"""Clickbait Headline Generator, by Al Sweigart email@protected
A clickbait headline generator for your soulless content farm website.
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: large, beginner, humor, word"""
import random
# Set up the constants:
OBJECT_PRONOUNS = ['Her', 'Him', 'Them']
POSSESIVE_PRONOUNS = ['Her', 'His', 'Their']
PERSONAL_PRONOUNS = ['She', 'He', 'They']
STATES = ['California', 'Texas', 'Florida', 'New York', 'Pennsylvania',
'Illinois', 'Ohio', 'Georgia', 'North Carolina', 'Michigan']
NOUNS = ['Athlete', 'Clown', 'Shovel', 'Paleo Diet', 'Doctor', 'Parent',
'Cat', 'Dog', 'Chicken', 'Robot', 'Video Game', 'Avocado',
'Plastic Straw','Serial Killer', 'Telephone Psychic']
PLACES = ['House', 'Attic', 'Bank Deposit Box', 'School', 'Basement',
'Workplace', 'Donut Shop', 'Apocalypse Bunker']
WHEN = ['Soon', 'This Year', 'Later Today', 'RIGHT NOW', 'Next Week']
def main():
print('Clickbait Headline Generator')
print('By Al Sweigart email@protected')
print()
print('Our website needs to trick people into looking at ads!')
while True:
print('Enter the number of clickbait headlines to generate:')
response = input('> ')
if not response.isdecimal():
print('Please enter a number.')
else:
numberOfHeadlines = int(response)
break # Exit the loop once a valid number is entered.
for i in range(numberOfHeadlines):
clickbaitType = random.randint(1, 8)
if clickbaitType == 1:
headline = generateAreMillenialsKillingHeadline()
elif clickbaitType == 2:
headline = generateWhatYouDontKnowHeadline()
elif clickbaitType == 3:
headline = generateBigCompaniesHateHerHeadline()
elif clickbaitType == 4:
headline = generateYouWontBelieveHeadline()
elif clickbaitType == 5:
headline = generateDontWantYouToKnowHeadline()
elif clickbaitType == 6:
headline = generateGiftIdeaHeadline()
elif clickbaitType == 7:
headline = generateReasonsWhyHeadline()
elif clickbaitType == 8:
headline = generateJobAutomatedHeadline()
print(headline)
print()
website = random.choice(['wobsite', 'blag', 'Facebuuk', 'Googles',
'Facesbook', 'Tweedie', 'Pastagram'])
when = random.choice(WHEN).lower()
print('Post these to our', website, when, 'or you're fired!')
# Each of these functions returns a different type of headline:
def generateAreMillenialsKillingHeadline():
noun = random.choice(NOUNS)
return 'Are Millenials Killing the {} Industry?'.format(noun)
def generateWhatYouDontKnowHeadline():
noun = random.choice(NOUNS)
pluralNoun = random.choice(NOUNS) 's'
when = random.choice(WHEN)
return 'Without This {}, {} Could Kill You {}'.format(noun, pluralNoun, when)
def generateBigCompaniesHateHerHeadline():
pronoun = random.choice(OBJECT_PRONOUNS)
state = random.choice(STATES)
noun1 = random.choice(NOUNS)
noun2 = random.choice(NOUNS)
return 'Big Companies Hate {}! See How This {} {} Invented a Cheaper {}'.format(pronoun, state, noun1, noun2)
def generateYouWontBelieveHeadline():
state = random.choice(STATES)
noun = random.choice(NOUNS)
pronoun = random.choice(POSSESIVE_PRONOUNS)
place = random.choice(PLACES)
return 'You Won't Believe What This {} {} Found in {} {}'.format(state, noun, pronoun, place)
def generateDontWantYouToKnowHeadline():
pluralNoun1 = random.choice(NOUNS) 's'
pluralNoun2 = random.choice(NOUNS) 's'
return 'What {} Don't Want You To Know About {}'.format(pluralNoun1, pluralNoun2)
def generateGiftIdeaHeadline():
number = random.randint(7, 15)
noun = random.choice(NOUNS)
state = random.choice(STATES)
return '{} Gift Ideas to Give Your {} From {}'.format(number, noun, state)
def generateReasonsWhyHeadline():
number1 = random.randint(3, 19)
pluralNoun = random.choice(NOUNS) 's'
# number2 should be no larger than number1:
number2 = random.randint(1, number1)
return '{} Reasons Why {} Are More Interesting Than You Think (Number {} Will Surprise You!)'.format(number1, pluralNoun, number2)
def generateJobAutomatedHeadline():
state = random.choice(STATES)
noun = random.choice(NOUNS)
i = random.randint(0, 2)
pronoun1 = POSSESIVE_PRONOUNS[i]
pronoun2 = PERSONAL_PRONOUNS[i]
if pronoun1 == 'Their':
return 'This {} {} Didn't Think Robots Would Take {} Job. {} Were Wrong.'.format(state, noun, pronoun1, pronoun2)
else:
return 'This {} {} Didn't Think Robots Would Take {} Job. {} Was Wrong.'.format(state, noun, pronoun1, pronoun2)
# If the program is run (instead of imported), run the game:
if __name__ == '__main__':
main()
在输入源代码并运行几次之后,尝试对其进行实验性的修改。你也可以自己想办法做到以下几点:
- 添加其他类型的标题党。
- 添加新的单词类别,超出
NOUNS
、STATES
等。
探索程序
试着找出下列问题的答案。尝试对代码进行一些修改,然后重新运行程序,看看这些修改有什么影响。
- 如果删除或注释掉第 34 行的
numberOfHeadlines = int(response)
,会得到什么错误信息? - 如果将第 34 行的
int(response)
改为response
,会得到什么错误信息? - 如果将第 19 行改为
WHEN = []
,会得到什么错误信息?
十二、柯拉茨序列
原文:http://inventwithpython.com/bigbookpython/project12.html
- 如果
n
是偶数,那么下一个数字n
就是n / 2
。 - 如果
n
是奇数,那么下一个数n
就是n * 3 1
。 - 如果
n
为 1,则停止。否则,重复。
一般认为,但迄今为止没有数学证明,每个起始数最终终止于 1。关于柯拉茨序列的更多信息可以在en.wikipedia.org/wiki/Collatz_conjecture
找到。
运行示例
当您运行collatz.py
时,输出将如下所示:
Collatz Sequence, or, the 3n 1 Problem
By Al Sweigart email@protected
The Collatz sequence is a sequence of numbers produced from a starting
number n, following three rules:
`--snip--`
Enter a starting number (greater than 0) or QUIT:
> 26
26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1
Collatz Sequence, or, the 3n 1 Problem
By Al Sweigart email@protected
`--snip--`
Enter a starting number (greater than 0) or QUIT:
> 27
27, 82, 41, 124, 62, 31, 94, 47, 142, 71, 214, 107, 322, 161, 484, 242, 121, 364, 182, 91, 274, 137, 412, 206, 103, 310, 155, 466, 233, 700, 350, 175, 526, 263, 790, 395, 1186, 593, 1780, 890, 445, 1336, 668, 334, 167, 502, 251, 754, 377, 1132, 566, 283, 850, 425, 1276, 638, 319, 958, 479, 1438, 719, 2158, 1079, 3238, 1619, 4858, 2429, 7288, 3644, 1822, 911, 2734, 1367, 4102, 2051, 6154, 3077, 9232, 4616, 2308, 1154, 577, 1732, 866, 433, 1300, 650, 325, 976, 488, 244, 122, 61, 184, 92, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1
工作原理
模数运算符可以帮助您确定一个数字是偶数还是奇数。记住这个操作符是一种“余数”操作符。23 除以 7 是 3 余 2,而23 mod 7
只是 2。偶数除以 2 没有余数,奇数除以 2 有余数 1。当n
为偶数时,第 33 行if n % 2 == 0:
中的条件求值为True
。当n
为奇数时,计算结果为False
。
"""Collatz Sequence, by Al Sweigart email@protected
Generates numbers for the Collatz sequence, given a starting number.
More info at: https://en.wikipedia.org/wiki/Collatz_conjecture
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: tiny, beginner, math"""
import sys, time
print('''Collatz Sequence, or, the 3n 1 Problem
By Al Sweigart email@protected
The Collatz sequence is a sequence of numbers produced from a starting
number n, following three rules:
1) If n is even, the next number n is n / 2.
2) If n is odd, the next number n is n * 3 1.
3) If n is 1, stop. Otherwise, repeat.
It is generally thought, but so far not mathematically proven, that
every starting number eventually terminates at 1.
''')
print('Enter a starting number (greater than 0) or QUIT:')
response = input('> ')
if not response.isdecimal() or response == '0':
print('You must enter an integer greater than 0.')
sys.exit()
n = int(response)
print(n, end='', flush=True)
while n != 1:
if n % 2 == 0: # If n is even...
n = n // 2
else: # Otherwise, n is odd...
n = 3 * n 1
print(', ' str(n), end='', flush=True)
time.sleep(0.1)
print()
探索程序
试着找出下列问题的答案。尝试对代码进行一些修改,然后重新运行程序,看看这些修改有什么影响。
- 以 32 开头的柯拉茨序列中有多少个数字?
- 以 33 开头的柯拉茨序列中有多少个数字?
- 起始数为 2 的幂(2、4、8、16、32、64、128 等等)的排序序列是否总是只由偶数组成(除了最后的 1)?
- 输入
0
作为起始整数会发生什么?
#13 康威的生命游戏
原文:http://inventwithpython.com/bigbookpython/project13.html
- 具有两个或三个邻居的活细胞在模拟的下一步中保持存活。
- 在模拟的下一步中,正好有三个邻居的死细胞变成活的。
- 在模拟的下一步中,任何其他细胞死亡或保持死亡。
下一步模拟中细胞的活或死状态完全取决于它们的当前状态。这些细胞不会“记住”任何旧的状态。关于这些简单规则产生的模式,有大量的研究。不幸的是,康威教授于 2020 年 4 月因并发症在新冠肺炎去世。更多关于康威《生命的游戏》的信息可以在en.wikipedia.org/wiki/Conway's_Game_of_Life
找到,更多关于马丁·加德纳的信息可以在en.wikipedia.org/wiki/Martin_Gardner
找到。
运行示例
当您运行conwaysgameoflife.py
时,输出将如下所示:
O O OO O O
O O O O O O OOOO O OO
OO O O O O O O O
OO O O OO OO
OO OO O O O OO
OO O O O OO
OOO OO OO O
O OOO
O O O O
OO OO OO OO O
OOO OO OOOO O O
O OO O O O OO OO O O OO
O O O O O OO O O OOO
O OOOO OO OO O OOOOO O
OO O O OOO O OOO OOOO O
工作原理
单元的状态存储在字典中的cells
和nextCells
变量中。两个字典都有键的(x, y)
元组(其中x
和y
是整数),活细胞的'O'
,死细胞的' '
。第 40 到 44 行被设置为将这些字典的表示打印到屏幕上。cells
变量的字典表示单元的当前状态,而nextCells
存储模拟下一步中单元的字典。
"""Conway's Game of Life, by Al Sweigart email@protected
The classic cellular automata simulation. Press Ctrl-C to stop.
More info at: https://en.wikipedia.org/wiki/Conway's_Game_of_Life
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: short, artistic, simulation"""
import copy, random, sys, time
# Set up the constants:
WIDTH = 79 # The width of the cell grid.
HEIGHT = 20 # The height of the cell grid.
# (!) Try changing ALIVE to '#' or another character:
ALIVE = 'O' # The character representing a living cell.
# (!) Try changing DEAD to '.' or another character:
DEAD = ' ' # The character representing a dead cell.
# (!) Try changing ALIVE to '|' and DEAD to '-'.
# The cells and nextCells are dictionaries for the state of the game.
# Their keys are (x, y) tuples and their values are one of the ALIVE
# or DEAD values.
nextCells = {}
# Put random dead and alive cells into nextCells:
for x in range(WIDTH): # Loop over every possible column.
for y in range(HEIGHT): # Loop over every possible row.
# 50/50 chance for starting cells being alive or dead.
if random.randint(0, 1) == 0:
nextCells[(x, y)] = ALIVE # Add a living cell.
else:
nextCells[(x, y)] = DEAD # Add a dead cell.
while True: # Main program loop.
# Each iteration of this loop is a step of the simulation.
print('n' * 50) # Separate each step with newlines.
cells = copy.deepcopy(nextCells)
# Print cells on the screen:
for y in range(HEIGHT):
for x in range(WIDTH):
print(cells[(x, y)], end='') # Print the # or space.
print() # Print a newline at the end of the row.
print('Press Ctrl-C to quit.')
# Calculate the next step's cells based on current step's cells:
for x in range(WIDTH):
for y in range(HEIGHT):
# Get the neighboring coordinates of (x, y), even if they
# wrap around the edge:
left = (x - 1) % WIDTH
right = (x 1) % WIDTH
above = (y - 1) % HEIGHT
below = (y 1) % HEIGHT
# Count the number of living neighbors:
numNeighbors = 0
if cells[(left, above)] == ALIVE:
numNeighbors = 1 # Top-left neighbor is alive.
if cells[(x, above)] == ALIVE:
numNeighbors = 1 # Top neighbor is alive.
if cells[(right, above)] == ALIVE:
numNeighbors = 1 # Top-right neighbor is alive.
if cells[(left, y)] == ALIVE:
numNeighbors = 1 # Left neighbor is alive.
if cells[(right, y)] == ALIVE:
numNeighbors = 1 # Right neighbor is alive.
if cells[(left, below)] == ALIVE:
numNeighbors = 1 # Bottom-left neighbor is alive.
if cells[(x, below)] == ALIVE:
numNeighbors = 1 # Bottom neighbor is alive.
if cells[(right, below)] == ALIVE:
numNeighbors = 1 # Bottom-right neighbor is alive.
# Set cell based on Conway's Game of Life rules:
if cells[(x, y)] == ALIVE and (numNeighbors == 2
or numNeighbors == 3):
# Living cells with 2 or 3 neighbors stay alive:
nextCells[(x, y)] = ALIVE
elif cells[(x, y)] == DEAD and numNeighbors == 3:
# Dead cells with 3 neighbors become alive:
nextCells[(x, y)] = ALIVE
else:
# Everything else dies or stays dead:
nextCells[(x, y)] = DEAD
try:
time.sleep(1) # Add a 1 second pause to reduce flickering.
except KeyboardInterrupt:
print("Conway's Game of Life")
print('By Al Sweigart email@protected')
sys.exit() # When Ctrl-C is pressed, end the program.
在输入源代码并运行几次之后,尝试对其进行实验性的修改。标有(!)
的注释对你可以做的小改变有建议。你也可以自己想办法做到以下几点:
- 调整开始为活细胞的百分比,而不是总是使用 50%。
- 添加从文本文件中读取初始状态的功能,这样用户可以手动编辑起始单元格状态。
探索程序
试着找出下列问题的答案。尝试对代码进行一些修改,然后重新运行程序,看看这些修改有什么影响。
- 把 10 行的
WIDTH = 79
改成WIDTH = 7
会怎么样? - 如果删除或注释掉第 36 行的
print('n' * 50)
会发生什么? - 如果把第 28 行的
random.randint(0, 1)
改成random.randint(0, 10)
会怎么样? - 如果把第 85 行的
nextCells[(x, y)] = DEAD
改成nextCells[(x, y)] = ALIVE
会怎么样?
十四、倒计时
原文:http://inventwithpython.com/bigbookpython/project14.html
运行示例
当您运行countdown.py
时,输出将如下所示:
__ __ __ __ __ __
| | | | * | | | | * __| |__|
|__| |__| * |__| |__| * |__ __|
Press Ctrl-C to quit.
工作原理
运行import sevseg
之后,您可以调用sevseg.getSevSegStr()
函数来获得一个包含七个段数字的多行字符串。然而,倒计时程序需要在时、分、秒之间显示一个由星号组成的冒号。这需要用splitlines()
方法将这些数字的三行多行字符串分割成三个单独的字符串。
"""Countdown, by Al Sweigart email@protected
Show a countdown timer animation using a seven-segment display.
Press Ctrl-C to stop.
More info at https://en.wikipedia.org/wiki/Seven-segment_display
Requires sevseg.py to be in the same folder.
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: tiny, artistic"""
import sys, time
import sevseg # Imports our sevseg.py program.
# (!) Change this to any number of seconds:
secondsLeft = 30
try:
while True: # Main program loop.
# Clear the screen by printing several newlines:
print('n' * 60)
# Get the hours/minutes/seconds from secondsLeft:
# For example: 7265 is 2 hours, 1 minute, 5 seconds.
# So 7265 // 3600 is 2 hours:
hours = str(secondsLeft // 3600)
# And 7265 % 3600 is 65, and 65 // 60 is 1 minute:
minutes = str((secondsLeft % 3600) // 60)
# And 7265 % 60 is 5 seconds:
seconds = str(secondsLeft % 60)
# Get the digit strings from the sevseg module:
hDigits = sevseg.getSevSegStr(hours, 2)
hTopRow, hMiddleRow, hBottomRow = hDigits.splitlines()
mDigits = sevseg.getSevSegStr(minutes, 2)
mTopRow, mMiddleRow, mBottomRow = mDigits.splitlines()
sDigits = sevseg.getSevSegStr(seconds, 2)
sTopRow, sMiddleRow, sBottomRow = sDigits.splitlines()
# Display the digits:
print(hTopRow ' ' mTopRow ' ' sTopRow)
print(hMiddleRow ' * ' mMiddleRow ' * ' sMiddleRow)
print(hBottomRow ' * ' mBottomRow ' * ' sBottomRow)
if secondsLeft == 0:
print()
print(' * * * * BOOM * * * *')
break
print()
print('Press Ctrl-C to quit.')
time.sleep(1) # Insert a one-second pause.
secondsLeft -= 1
except KeyboardInterrupt:
print('Countdown, by Al Sweigart email@protected')
sys.exit() # When Ctrl-C is pressed, end the program.)
在输入源代码并运行几次之后,尝试对其进行实验性的修改。你也可以自己想办法做到以下几点:
- 提示用户输入开始倒计时的时间。
- 让用户输入在倒计时结束时显示的消息。
探索程序
试着找出下列问题的答案。尝试对代码进行一些修改,然后重新运行程序,看看这些修改有什么影响。
- 如果把第 13 行的
secondsLeft = 30
改成secondsLeft = 30.5
会怎么样? - 如果把第 30、33、36 行的
2
改成1
会怎么样? - 如果把 52 行的
time.sleep(1)
改成time.sleep(0.1)
会怎么样? - 如果把 53 行的
secondsLeft -= 1
改成secondsLeft -= 2
会怎么样? - 如果删除或注释掉第 18 行的
print('n' * 60)
会发生什么? - 如果删除或注释掉第 10 行的
import sevseg
,会得到什么错误信息?
十五、深坑
原文:http://inventwithpython.com/bigbookpython/project15.html
运行示例
当您运行deepcave.py
时,输出如下:
Deep Cave, by Al Sweigart email@protected
Press Ctrl-C to stop.
#################### ########################################
#################### #########################################
#################### ########################################
#################### ########################################
##################### #######################################
###################### ######################################
##################### #######################################
#################### ########################################
################### #########################################
`--snip--`
工作原理
这个程序利用了这样一个事实,即打印新行最终会导致前面的行在屏幕上上移。通过在每行上打印一个稍微不同的间隙,程序创建了一个滚动动画,看起来好像观众在向下移动。
左侧的井号字符数由leftWidth
变量跟踪。中间的空格数由gapWidth
变量跟踪。右侧标签字符的数量从WIDTH - gapWidth - leftWidth
开始计算。这确保了每一行总是相同的宽度。
"""Deep Cave, by Al Sweigart email@protected
An animation of a deep cave that goes forever into the earth.
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: tiny, beginner, scrolling, artistic"""
import random, sys, time
# Set up the constants:
WIDTH = 70 # (!) Try changing this to 10 or 30.
PAUSE_AMOUNT = 0.05 # (!) Try changing this to 0 or 1.0.
print('Deep Cave, by Al Sweigart email@protected')
print('Press Ctrl-C to stop.')
time.sleep(2)
leftWidth = 20
gapWidth = 10
while True:
# Display the tunnel segment:
rightWidth = WIDTH - gapWidth - leftWidth
print(('#' * leftWidth) (' ' * gapWidth) ('#' * rightWidth))
# Check for Ctrl-C press during the brief pause:
try:
time.sleep(PAUSE_AMOUNT)
except KeyboardInterrupt:
sys.exit() # When Ctrl-C is pressed, end the program.
# Adjust the left side width:
diceRoll = random.randint(1, 6)
if diceRoll == 1 and leftWidth > 1:
leftWidth = leftWidth - 1 # Decrease left side width.
elif diceRoll == 2 and leftWidth gapWidth < WIDTH - 1:
leftWidth = leftWidth 1 # Increase left side width.
else:
pass # Do nothing; no change in left side width.
# Adjust the gap width:
# (!) Try uncommenting out all of the following code:
#diceRoll = random.randint(1, 6)
#if diceRoll == 1 and gapWidth > 1:
# gapWidth = gapWidth - 1 # Decrease gap width.
#elif diceRoll == 2 and leftWidth gapWidth < WIDTH - 1:
# gapWidth = gapWidth 1 # Increase gap width.
#else:
# pass # Do nothing; no change in gap width.
在输入源代码并运行几次之后,尝试对其进行实验性的修改。标有(!)
的注释对你可以做的小改变有建议。
探索程序
试着找出下列问题的答案。尝试对代码进行一些修改,然后重新运行程序,看看这些修改有什么影响。
- 如果把第 23 行的
(' ' * gapWidth)
改成('.' * gapWidth)
会怎么样? - 如果把第 32 行的
random.randint(1, 6)
改成random.randint(1, 1)
会怎么样? - 如果把第 32 行的
random.randint(1, 6)
改成random.randint(2, 2)
会怎么样? - 如果删除或注释掉第 17 行的
leftWidth = 20
,会得到什么错误信息? - 如果把第 10 行的
WIDTH = 70
改成WIDTH = -70
会怎么样? - 如果将第 11 行的
PAUSE_AMOUNT = 0.05
改为PAUSE_AMOUNT = -0.05
,会得到什么错误信息?