Python 小型项目大全 11~15

十一、标题党生成器
原文:http://inventwithpython.com/bigbookpython/project11.html

我们的网站需要欺骗人们去看广告!但是想出有创意的原创内容太难了。幸运的是,有了标题党生成器,我们可以让一台计算机产生数百万个令人发指的虚假标题。都是低质量的,但读者似乎并不介意。这个程序根据你的需要从一个 MadLibs 风格的模板中生成尽可能多的标题。
这个程序中有很多标题模板的文本,但是代码本身很简单,适合初学者。
运行示例
当您运行clickbait.py时,输出将如下所示:
Clickbait Headline Generator
By Al Sweigart email@protectedOur 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

柯拉茨序列,也称为3n + 1问题,是最简单的不可能数学问题。(不过不用担心,程序本身对初学者来说已经足够简单了。)从一个起始数字,n,遵循三个规则得到序列中的下一个数字:
- 如果
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@protectedThe 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, 1Collatz 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, timeprint('''Collatz Sequence, or, the 3n + 1 Problem
By Al Sweigart email@protectedThe 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 // 2else: # Otherwise, n is odd...n = 3 * n + 1print(', ' + 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

康威的生命游戏是一种细胞自动机模拟,它遵循简单的规则来创建有趣的模式。它是由数学家约翰·康威在 1970 年发明的,并由马丁·加德纳在《科学美国人》的“数学游戏”专栏推广开来。今天,它是程序员和计算机科学家的最爱,尽管它更像是一个有趣的可视化而不是真正的“游戏”二维棋盘有一个“单元格”网格,每个单元格都遵循三个简单的规则:
- 具有两个或三个邻居的活细胞在模拟的下一步中保持存活。
- 在模拟的下一步中,正好有三个邻居的死细胞变成活的。
- 在模拟的下一步中,任何其他细胞死亡或保持死亡。
下一步模拟中细胞的活或死状态完全取决于它们的当前状态。这些细胞不会“记住”任何旧的状态。关于这些简单规则产生的模式,有大量的研究。不幸的是,康威教授于 2020 年 4 月因并发症在新冠肺炎去世。更多关于康威《生命的游戏》的信息可以在en.wikipedia.org/wiki/Conway%27s_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 OOOO O O O OOOOO OO OO OO OOOO O O OOO OO OO OO OOOO OO OOOO O OO OO O O O OO OO O O OOO O O O O OO O O OOOO 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%27s_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) % WIDTHright = (x + 1) % WIDTHabove = (y - 1) % HEIGHTbelow = (y + 1) % HEIGHT# Count the number of living neighbors:numNeighbors = 0if 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 == 2or numNeighbors == 3):# Living cells with 2 or 3 neighbors stay alive:nextCells[(x, y)] = ALIVEelif cells[(x, y)] == DEAD and numNeighbors == 3:# Dead cells with 3 neighbors become alive:nextCells[(x, y)] = ALIVEelse:# Everything else dies or stays dead:nextCells[(x, y)] = DEADtry: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

这个程序显示一个数字计时器,倒计时到零。第六十四个项目的sevseg.py模块“七段显示模块”为每个数字生成图形,而不是直接呈现数字字符。您必须先创建这个文件,倒计时程序才能运行。然后,将倒计时设置为你喜欢的任何秒数、分钟数和小时数。这个程序类似于项目 19,“数字钟。”
运行示例
当您运行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 = 30try: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 * * * *')breakprint()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

这个节目是一个永远深入地下的深洞的动画。虽然很短,但这个程序利用了计算机屏幕的滚动特性,产生了一个有趣且无休止的可视化效果,证明了制作有趣的东西并不需要太多代码。这个项目类似于 58 项目“彩虹”
运行示例
当您运行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 = 10while True:# Display the tunnel segment:rightWidth = WIDTH - gapWidth - leftWidthprint(('#' * 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,会得到什么错误信息?


