一些好玩的程序
Python 不仅仅可以用来处理枯燥的数据和复杂的算法,它同样可以用来编写一些极其有趣、富有创意甚至“脑洞大开”的程序。
纯中文编程
Python 3 将源代码视为 UTF-8 编码。这意味着只要是 Unicode 字符集中被归类为“字母”的字符(包括汉字),都可以用作标识符。在某些特定领域(如针对非英语母语者的教学,或者特定业务逻辑极其复杂的金融/法律系统),使用中文变量名有时能提高代码对业务专家的可读性。
下面的演示是一个“决战紫禁之巅”的文字武侠小游戏。在这个程序中,除了 Python 的保留关键字(如 def, class, if, while, import, return 等),所有的自定义名称全部使用了中文。
import random as 天意
import time as 时光
# 将 Python 内置函数取个中文别 名,显得更“原生”
输出 = print
等待 = 时光.sleep
class 侠客:
def __init__(本座, 尊姓大名, 初始内力, 独门绝技):
本座.名号 = 尊姓大名
本座.内力 = 初始内力
本座.绝技 = 独门绝技
本座.状态 = "生龙活虎"
def 展示名帖(本座):
输出(f"【{本座.名号}】 踏入了江湖,内力深厚:{本座.内力}")
def 出招(本座, 对手):
# 随机决定是否发动暴击
运势 = 天意.randint(1, 10)
if 运势 > 8:
伤害 = 天意.randint(25, 40)
输出(f"⚡ {本座.名号} 怒吼一声,使出了毕生绝学「{本座.绝技}」!")
输出(f" 天崩地裂!对 {对手.名号} 造成了 {伤害} 点暴击伤害!")
else:
伤害 = 天意.randint(10, 20)
招式列表 = ["黑虎掏心", "白鹤亮翅", "太祖长拳", "扫堂腿"]
普通一招 = 天意.choice(招式列表)
输出(f"⚔️ {本座.名号} 使出一招「{普通一招}」,击中了 {对手.名号}。")
输出(f" 造成了 {伤害} 点伤害。")
对手.受伤(伤害)
def 受伤(本座, 伤害值):
本座.内力 = 本座.内力 - 伤害值
if 本座.内力 <= 0:
本座.内力 = 0
本座.状态 = "重伤倒地"
输出(f"aaa {本座.名号} 吐出一口鲜血,支撑不住了!")
else:
输出(f" {本座.名号} 剩余内力:{本座.内力}")
等待(1) # 暂停一下,增加阅读沉浸感
def 还能再战(本座):
return 本座.内力 > 0
def 紫禁之巅决斗():
输出("="*30)
输出(" 🌙 决战紫禁之巅 🌙")
输出("="*30)
等待(1)
# 实例化对象
剑神 = 侠客(尊姓大名="西门吹雪", 初始内力=100, 独门绝技="一剑西来")
剑圣 = 侠客(尊姓大名="叶孤城", 初始内力=100, 独门绝技="天外飞仙")
剑神.展示名帖()
剑圣.展示名帖()
输出("-" * 30)
输出("决斗开始!")
输出("-" * 30)
等待(1)
回合数 = 1
# 只要两人都活着,就继续打
while 剑神.还能再战() and 剑圣.还能再战():
输出(f"\n--- 第 {回合数} 回合 ---")
# 双方轮流出招
if 剑神.还能再战():
剑神.出招(对手=剑圣)
if 剑圣.还能再战():
剑圣.出招(对手=剑神)
回合数 += 1
等待(1.5)
输出("\n" + "="*30)
if 剑神.还能再战():
输出(f"🏆 胜者:{剑神.名号}!江湖留下了他的传说。")
else:
输出(f"🏆 胜者:{剑圣.名号}!这才是真正的剑道巅峰。")
输出("="*30)
# 程序入口
if __name__ == "__main__":
紫禁之巅决斗()
如果运行这段程序,控制台会输出类似下面的内容:
==============================
🌙 决战紫禁之 巅 🌙
==============================
【西门吹雪】 踏入了江湖,内力深厚:100
【叶孤城】 踏入了江湖,内力深厚:100
------------------------------
决斗开始!
------------------------------
--- 第 1 回合 ---
⚡ 西门吹雪 怒吼一声,使出了毕生绝学「一剑西来」!
天崩地裂!对 叶孤城 造成了 33 点暴击伤害!
叶孤城 剩余内力:67
⚔️ 叶孤城 使出一招「黑虎掏心」,击中了 西门吹雪。
造成了 19 点伤害。
西门吹雪 剩余内力:81
--- 第 2 回合 ---
⚡ 西门吹雪 怒吼一声,使出了毕生绝学「一剑西来」!
天崩地裂!对 叶孤城 造成了 37 点暴击伤害!
叶孤城 剩余内力:30
⚔️ 叶孤城 使出一招「黑虎掏心」,击中了 西门吹雪。
造成了 10 点伤害。
西门吹雪 剩余内力:71
--- 第 3 回合 ---
⚔️ 西门吹雪 使出一招「太祖长拳」,击中了 叶孤城。
造成了 17 点伤害。
叶孤城 剩余内力:13
⚔️ 叶孤城 使出一招「扫堂腿」,击中了 西门吹雪。
造成了 13 点伤害。
西门吹雪 剩余内力:58
--- 第 4 回合 ---
⚔️ 西门吹雪 使出一招「太祖长拳」,击中了 叶孤城。
造成了 14 点伤害。
aaa 叶孤城 吐出一口鲜血,支撑不住了!
==============================
🏆 胜者:西门吹雪!江湖留下了他的传说。
==============================
打印自身的程序
Quine 算法
如果程序保存在文件中,最简单的方式是让程序读取自己所在的文件,然后把它打印出来:
print(open(__file__).read())
如果程序只在内存中,或者不可以调用文件读写函数,那么可以采用 Quine 算法,也叫“自产生程序”。它是以美国哲学家奎恩(Willard Van Orman Quine)命名的算法。它的工作原理大致如下:
- 把程序划分成两个主要部分: A 和 B
- 我们先定义一个函数 Q,对于字符串 A,Q(A) 在执行后会变成字符串 B。
- A 部分是用字符串表示的 B 部分的代码
- B 部分的代码可以接收一段字符串 A,然后调用函数 Q 计算出 Q(A),然后打印出 A 和 Q(A)
repr() 函数
在编写 Python 代码之前,先要介绍一下 Python 自带的 repr() 函数。repr() 函数运行后返回一个输入对象的“官方”字符串表示,这个字符串通常可以用来重新创建该对象。其主要目的是调试和开发。
repr() 的输出主要是给开发者看的,其目的是明确无误地表达对象的 类型和(最关键的)特征。不同于 str() 函数,str() 更注重于可读性,而 repr() 更注重于明确性和一致性。如果输入的对象是 Python 内置类型,这个字符串可以直接用 Python 表达式来计算得到相应的对象。
比如运行下面的程序,可以看出 repr() 的特点:
x = "abc"
print(str(x)) # 输出是没有引号的,这就是字符串的打印结果: abc
print(repr(x)) # 输出是带有引号的,表示如果的对象是一个字符串: 'abc'
对于我们自己定义的对象,可以通过在类中定义 __repr__() 方法来为自定义对象实现 repr() 函数的效果。当 repr(obj) 被调用时,Python 会寻找 obj 的类定义中的 __repr__() 方法,并执行它。比如:
class Test:
def __init__(self, value):
self.value = value
def __repr__(self):
return f'Test({self.value!r})'
# 创建 Test 对象
obj = Test('hello world')
# 使用 repr() 函数
print(repr(obj)) # 输出:Test('hello world')
# 内置类型的例子
print(repr(123)) # 输出:'123'
print(repr([1, 2, 3])) # 输出:'[1, 2, 3]'
在这个例子中,Test 类定义了 __repr__() 方法,该方法返回一个格式化字符串,展示了如何创建一个与当前对象具有相同值的新对象。这种做法提高了代码的可读性和可维护性,尤其是在调试时。