面向对象
一般步骤
Step 1. 定义类
类是对象的蓝图和模板 有了类就可以创建对象
定义类需要做两件事:数据抽象和行为抽象
数据抽象 - 抽取对象共同的静态特征(找名词)- 属性
行为抽象 - 抽取对象共同的动态特征(找动词)- 方法
定义类的关键字 - class - 类名(每个单词首字母大写)
Step 2. 调用构造方法创建学生对象
实际上调用的是Student类中_init_方法
Step 3. 给对象发出消息
通过给对象发消息让对象完成某些工作
解决任何问题都是通过让对象去做事情
实例
步骤
# Step 1. 定义类
# 类是对象的蓝图和模板 有了类就可以创建对象
# 定义类需要做两件事:数据抽象和行为抽象
# 数据抽象 - 抽取对象共同的静态特征(找名词)- 属性
# 行为抽象 - 抽取对象共同的动态特征(找动词)- 方法
# 定义类的关键字 - class - 类名(每个单词首字母大写)
class Student:
# 构造方法(构造器/构造子 - construct)
# 调用该方法时,不是直接使用方法的名字,而是使用类的名字
def __init__(self, name, age):
# 给对象绑定属性
self.__name = name
self.__age = age
# 我们定义一个方法就代表对象可以接收这个消息
# 对象的方法的第一个参数都是统一写成self
# 它代表了接收消息的对象 - 对象.消息(参数)
def study(self, course):
print('%s正在学习%s, 年龄%d' % (self.__name, course, self.__age))
def watch_av(self):
if self.__age >= 18:
print('%s正在看片, 年龄%d' % (self.__name, self.__age))
else:
print('%s我们推荐你看《熊出没》' % self.__name)
def main():
# Step 2. 调用构造方法创建学生对象
# 实际上调用的是Student类中__init__方法
stu1 = Student('cfx', 24)
# Step 3. 给对象发出消息
# 通过给对象发消息让对象完成某些工作
# 解决任何问题都是通过让对象去做事情
stu1.study('python程序设计')
stu2 = Student('王大锤', 5)
stu2.__name = '刘备'
stu2.__age = 20
stu2.study('HTML')
stu2.watch_av()
if __name__ == '__main__':
main()
计算矩形的周长和面积
class Rectangle(object):
def __init__(self, width, hight):
self._width = int(width)
self._hight = int(hight)
def peri(self):
return self._width * 2 + self._hight * 2
def arer(self):
return self._hight * self._width
def main1():
rect1 = Rectangle('10', '5')
print(rect1.peri())
print(rect1.arer())
游泳池圆形过道及围栏花费
from math import pi
# 我们定义一个类实际上是把数据和操作数据的函数绑定到一起
# 形成了一个逻辑上的整体 这个整体就叫对象
# 而且将来任何时候想使用这种对象时直接复用这个类就可以了
class Circle(object):
def __init__(self,radius = 0):
self._radius = radius
def area(self):
return pi * self._radius ** 2
def perimeter(self):
return pi * self._radius * 2
def main():
r = eval(input('请输入游泳池半径:'))
big = Circle(r + 3)
small = Circle(r)
print('围墙的造价为%.2f' % (big.perimeter() * 35.5))
print('过道的造价为%.2f' % ((big.area()-small.area()) * 25))
if __name__ == '__main__':
main()
移动点和计算两点间距离
# 定义一个类 提供下面方法
# 移动点的方法(移动到 and 移动了)
# 计算一个点到另一个点距离的方法
class Dot(object):
def __init__(self, x, y):
self._x = x
self._y = y
def move(self, x, y):
self._x += x
self._y += y
def goto(self, dx, dy):
self._x = dx
self._y = dy
def __str__(self):
return '%s, %s' % (str(self._x), str(self._y))
def distance(self, other):
dx = self._x - other._x # 此处other_x 可以优化
dy = self._y - other._y
return (dx ** 2 + dy ** 2) ** 0.5
class Calc(object): # 和 distance 作用一样
def __init__(self, dot1,dot2):
self._x1 = dot1._x
self._y1 = dot1._y
self._x2 = dot2._x
self._y2 = dot2._y
def __str__(self):
return '%f' % (((self._x2 - self._x1) ** 2 + (self._y2 - self._y1) ** 2) ** 0.5)
def main():
x1 = eval(input('请输入第一个点的x坐标:'))
y1 = eval(input('请输入第一个点的y坐标:'))
x2 = eval(input('请输入第二个点的x坐标:'))
y2 = eval(input('请输入第二个点的y坐标:'))
dot1 = Dot(x1, y1)
dot2 = Dot(x2, y2)
dot1.goto(5, 5)
dot2.move(-1, -1)
print(dot1)
print(dot2)
print(dot1.distance(dot2))
calc1 = Calc(dot1, dot2)
print(calc1)
if __name__ == '__main__':
main()
实时数字时钟
学习time模块
_str变量 --- 在调用print函数时自动执行str里面的语句
import time
class Clock(object):
"""数字时钟"""
def __init__(self, hour=0, minute=0, second=0):
self._hour = hour
self._minute = minute
self._second = second
def run(self):
"""走字"""
self._second += 1
if self._second == 60:
self._second = 0
self._minute += 1
if self._minute == 60:
self._minute = 0
self._hour += 1
if self._hour == 24:
self._hour = 0
# 下面的方法可以获得对象的字符串表示形式
# 当我们用print打印对象时会自动调用该方法
def __str__(self):
"""显示时间"""
return '%02d : %02d : %02d' % \
(self._hour, self._minute, self._second)
def main(h, m, s):
clock = Clock(h, m, s)
while True:
# os.system('cls')
print(clock)
time.sleep(1)
clock.run()
if __name__ == '__main__':
# 开始时自动提取系统时间
for _ in range(1):
times = time.asctime() # time 模块中的asctime不提供参数返回当前时间的字符串
print(times)
h = int(times[11:13])
m = int(times[14:16])
s = int(times[17:19])
main(h, m, s)
判断两条线是否相交
分别判断一条线段的两个点是不是在另一条线段所在直线的两边
class Line(object):
def __init__(self, x1, y1, x2, y2):
self._x1 = x1
self._y1 = y1
self._x2 = x2
self._y2 = y2
def cross(self, other):
a = (self._y2 * 10**3 - self._y1 * 10**3) / (self._x2 * 10**3 - self._x1 * 10**3)
b = (self._y1 *10**9 - int(a *10**6) * self._x1 * 10**3)/10**9
c = (other._y1 * 10 ** 9 - ((a * 10 ** 3) * (other._x1 * 10 ** 3)) * 10 ** 3 - b * 10 ** 9)/10 ** 9
d = (other._y2 * 10 ** 9 - ((a * 10 ** 3) * (other._x2 * 10 ** 3)) * 10 ** 3 - b * 10 ** 9)/10 ** 9
if c <= 0 and d >= 0 or c >= 0 and d <= 0:
return True
else:return False
def __str__(self):
return '点1(%.3f, %.3f);点2(%.3f, %.3f)' % (self._x1, self._y1, self._x2, self._y2)
def main():
x11 = eval(input('请输入第一点x(最大精确到小数点后3位):'))
y11 = eval(input('请输入第一点y(最大精确到小数点后3位):'))
x12 = eval(input('请输入第二点x(最大精确到小数点后3位):'))
y12 = eval(input('请输入第二点y(最大精确到小数点后3位):'))
line1 = Line(x11, y11, x12, y12)
print(line1)
x21 = eval(input('请输入第一点x(最大精确到小数点后3位):'))
y21 = eval(input('请输入第一点y(最大精确到小数点后3位):'))
x22 = eval(input('请输入第二点x(最大精确到小数点后3位):'))
y22 = eval(input('请输入第二点y(最大精确到小数点后3位):'))
line2 = Line(x21, y21, x22, y22)
print(line2)
if line1.cross(line2) and line2.cross(line1):
print('相交')
else:
print('不相交')
if __name__ == '__main__':
main()
奥特曼打怪兽
奥特曼打怪兽原创版
import random, os
class Ultraman(object):
def __init__(self, name, my_bool, strike_one, strike_two, attack_rate):
self.name = name
self.energy = 100
self.my_bool = my_bool
self.strike_one = strike_one
self.strike_two = strike_two
self.attack_rate = attack_rate
def attack(self, other, m_one, two):
if m_one:
if random.randint(1, 100) <= self.attack_rate:
other.m_bool -= self.strike_one
return '奥特曼打中%s' % other.name
else:
return '奥特曼没打中%s' % other.name
elif two and self.energy >= 30:
if random.randint(1, 100) <= self.attack_rate:
other.m_bool -= self.strike_two
self.energy -= 30
return '奥特曼打中%s' % other.name
else:
self.energy -= 30
return '奥特曼没打中%s' % other.name
else:
return '能量不足'
def hava_bool(self):
return self.my_bool > 0
def my_energy(self):
if self.energy < 100:
self.energy += 5
def attacked(self):
return '奥特曼的剩余血量:%d\t奥特曼的剩余能量:%d' % (self.my_bool, self.energy)
def __str__(self):
return '奥特曼的属性:%s\t血量:%d\t普通攻击力:%d\t强攻攻击力:%d\t攻击率:%d\t能量:%d' % \
(self.name, self.my_bool, self.strike_one, self.strike_two, self.attack_rate, self.energy)
class Monster(object):
def __init__(self,name):
self.name = name
self.m_bool = 100
self.strike = random.randint(10,20)
self.attack_rate = random.randint(50,85)
def attack(self, other):
if random.randint(1, 100) <= self.attack_rate:
other.my_bool -= self.strike
return '%s打中奥特曼' % self.name
else:
return '%s没打中奥特曼' % self.name
def hava_bool(self):
if self.m_bool > 0:
return True
else:
return False
def attacked(self):
return '%s剩余血量%d' % (self.name, self.m_bool)
def __str__(self):
return '小怪兽的属性:%s\t血量:%d\t攻击力:%d\t攻击率:%d' % \
(self.name, self.m_bool, self.strike, self.attack_rate)
def main():
a = ['总血量','普通攻击力','强攻攻击力','攻击率(1,100)']
for i in range(4):
a.append(eval(input('请设置奥特曼%s' % a[i])))
automan = Ultraman('automan', a[4], a[5], a[6], a[7])
n = eval(input('你需要设置几个小怪兽:'))
b1 = ['monster' + '%s' % (v + 1) for v in range(n)]
for k in range(n):
b1[k] = Monster(b1[k])
os.system('cls')
print(automan)
for v in range(n):
print(b1[v])
method = input('''
单挑 <--- 1
群挑 <--- 2
请输入进攻方式:''')
if method == '1':
for f in range(n):
kk = 1
os.system('cls')
while automan.hava_bool() and b1[f].hava_bool():
g = input('''第%d回合
请选择进攻方式:
普攻 <--- 1
强攻 <--- 2''' % kk)
one = True
two = True
if g == '1':
two = False
elif g == '2':
one = False
print(automan.attack(b1[f], one, two))
print(b1[f].attack(automan))
if b1[f].hava_bool():
print(b1[f].attacked())
else:
print('%s剩余血量0' % b1[f].name)
if automan.hava_bool():
print(automan.attacked())
else:
print('奥特曼剩余血量0,奥特曼输了')
break
automan.my_energy()
go = input('''是否进入下一回合:
是<---1
否<---2''')
if go == '2':
break
else:
os.system('cls')
kk += 1
if f < n-1 and automan.hava_bool() and go != '2':
print('奥特曼打死了%s,继续攻打下一只小怪兽' % b1[f].name)
elif automan.hava_bool() and go != '2':
print('奥特曼打死了%s,奥特曼赢了,游戏结束' % b1[f].name)
elif method == '2':
go_on = True
kk = 1
os.system('cls')
s = n
while go_on:
g = input('''第%d回合
请选择进攻方式:
普攻 <--- 1
强攻 <--- 2''' % kk)
one = True
two = True
if g == '1':
two = False
elif g == '2':
one = False
for f in range(n):
if automan.hava_bool() and b1[f].hava_bool():
print(automan.attack(b1[f], one, two))
automan.my_energy()
if b1[f].hava_bool():
print(b1[f].attacked())
else:
print('%s剩余血量0,被打死了' % b1[f].name)
s -= 1
if s == 0:
print('所有小怪兽都死了,奥特曼胜利')
go_on = False
for h in range(n):
if b1[h].hava_bool() and automan.hava_bool():
print(b1[h].attack(automan))
if automan.hava_bool():
print(automan.attacked())
else:
print('奥特曼剩余血量0,奥特曼输了')
go_on =False
go = input('''是否进入下一回合:
是<---1
否<---2''')
if go =='2':
break
else:
os.system('cls')
kk += 1
if __name__ == '__main__':
main()
奥特曼打怪兽修改版
通过_slots_魔法限定对象可以绑定的成员变量
_slots_不能继承,如果想子类有此特性,需要在子类重新写
from abc import ABCMeta, abstractmethod
from random import randint, randrange
class Fighter(object, metaclass=ABCMeta):
"""战斗者"""
# 通过__slots__魔法限定对象可以绑定的成员变量
# __slots__不能继承,如果想子类有此特性,需要在子类重新写
__slots__ = ('_name', '_hp')
def __init__(self, name, hp):
"""
初始化方法
:param name: 名字
:param hp: 生命值
"""
self._name = name
self._hp = hp
# 属性访问器
@property
def name(self):
return self._name
# 属性访问器
@property
def hp(self):
return self._hp
# 属性修改器
@hp.setter
def hp(self, hp):
self._hp = hp if hp >= 0 else 0
@property
def alive(self):
return self._hp > 0
@abstractmethod
def attack(self, other):
"""
攻击
:param other: 被攻击的对象
"""
pass
class Ultraman(Fighter):
"""奥特曼"""
__slots__ = ('_name', '_hp', '_mp')
def __init__(self, name, hp, mp):
"""
初始化方法
:param name: 名字
:param hp: 生命值
:param mp: 魔法值
"""
super().__init__(name, hp)
self._mp = mp
def attack(self, other):
other.hp -= randint(15, 25)
def huge_attack(self, other):
"""
究极必杀技(打掉对方至少50点或四分之三的血)
:param other: 被攻击的对象
:return: 使用成功返回True否则返回False
"""
if self._mp >= 50:
self._mp -= 50
injury = other.hp * 3 // 4
injury = injury if injury >= 50 else 50
other.hp -= injury
return True
else:
self.attack(other)
return False
def magic_attack(self, others):
"""
魔法攻击
:param others: 被攻击的群体
:return: 使用魔法成功返回True否则返回False
"""
if self._mp >= 20:
self._mp -= 20
for temp in others:
if temp.alive:
temp.hp -= randint(10, 15)
return True
else:
return False
def resume(self):
"""恢复魔法值"""
incr_point = randint(1, 10)
self._mp += incr_point
return incr_point
def __str__(self):
return '~~~%s奥特曼~~~\n' % self._name + \
'生命值: %d\n' % self._hp + \
'魔法值: %d\n' % self._mp
class Monster(Fighter):
"""小怪兽"""
__slots__ = ('_name', '_hp')
def attack(self, other):
other.hp -= randint(10, 20)
def __str__(self):
return '~~~%s小怪兽~~~\n' % self._name + \
'生命值: %d\n' % self._hp
def is_any_alive(monsters):
"""判断有没有小怪兽是活着的"""
for monster in monsters:
if monster.alive:
return True
return False
def select_alive_one(monsters):
"""选中一只活着的小怪兽"""
monsters_len = len(monsters)
while True:
index = randrange(monsters_len)
monster = monsters[index]
if monster.alive:
return monster
def display_info(ultraman, monsters):
"""显示奥特曼和小怪兽的信息"""
print(ultraman)
for monster in monsters:
print(monster, end='')
def main():
u = Ultraman('骆', 1000, 120)
m1 = Monster('舒', 250)
m2 = Monster('白元芳', 500)
m3 = Monster('王大锤', 750)
ms = [m1, m2, m3]
fight_round = 1
while u.alive and is_any_alive(ms):
print('========第%02d回合========' % fight_round)
m = select_alive_one(ms) # 选中一只小怪兽
skill = randint(1, 10) # 通过随机数选择使用哪种技能
if skill <= 6: # 60%的概率使用普通攻击
print('%s使用普通攻击打了%s.' % (u.name, m.name))
u.attack(m)
print('%s的魔法值恢复了%d点.' % (u.name, u.resume()))
elif skill <= 9: # 30%的概率使用魔法攻击(可能因魔法值不足而失败)
if u.magic_attack(ms):
print('%s使用了魔法攻击.' % u.name)
else:
print('%s使用魔法失败.' % u.name)
else: # 10%的概率使用究极必杀技(如果魔法值不足则使用普通攻击)
if u.huge_attack(m):
print('%s使用究极必杀技虐了%s.' % (u.name, m.name))
else:
print('%s使用普通攻击打了%s.' % (u.name, m.name))
print('%s的魔法值恢复了%d点.' % (u.name, u.resume()))
if m.alive: # 如果选中的小怪兽没有死就回击奥特曼
print('%s回击了%s.' % (m.name, u.name))
m.attack(u)
display_info(u, ms) # 每个回合结束后显示奥特曼和小怪兽的信息
fight_round += 1
print('\n========战斗结束!========\n')
if u.alive > 0:
print('%s奥特曼胜利!' % u.name)
else:
print('小怪兽胜利!')
if __name__ == '__main__':
main()
可变参数、关键字参数、命名关键字参数
- 可变参数 - 元组
同样,如果想把一个元组当作可变参数传入,也需要在参数前加一个* - 关键字参数 - 字典 - 根据参数名来决定如何执行
如果希望把一个字典当作关键词参数传入 需要在参数前放两个* - 命名关键字参数
*号后面的参数必须要写成关键字参数形式,
前面的可以给关键字参数形式也可以给可变参数形式,但关键字参数形式必须在可变参数后
# 关键字参数 - 字典 - 根据参数名来决定如何执行
# 可变参数 - 元组
def say_hello(*args,**kwargs):
print(args)
print(kwargs)
if 'name' in kwargs:
print('你好,%s' % kwargs['name'])
elif 'age' in kwargs:
age = kwargs['age']
if age <= 16:
print('你还是个小屁孩')
else:
print('你是一个成年人')
else:
print('请提供个人信息')
# 命名关键字参数
# *号后面的参数必须要写成关键字参数形式,
# 前面的可以给关键字参数形式也可以给可变参数形式,但关键字参数形式必须在可变参数后面
def foo(a, b, c, *, name, age):
print(a + b + c)
print(name, ':', age)
def main():
say_hello(1,2,'hello',name='cfx',age=24, qq=12345689, gender=True)
param = {'name': '王大锤', 'age': 330, 'qq': 12345689, 'gender': True}
# say_hello(param) # 会报错
# 如果希望把一个字典当作关键词参数传入 需要在参数前放两个*
say_hello(**param)
# 同样,如果想把一个元组当作可变参数传入,也需要在参数前加一个*
tuple1 = (5, 2, 'good')
say_hello(*tuple1,**param)
foo(a=1, b=2, c=3, name='cfx', age=24)
foo(1, 2, 3, name='cfx', age=24)
if __name__ == '__main__':
main()
装饰器
通过装饰器修饰f函数 让f函数在执行过程中可以做更多额外的操作
# 高内聚,低耦合
# 通过向函数中传入函数,可以写出更通用的代码
# calc函数中的第二个参数是另一个函数,它代表了一个二元运算
# 这样calc函数就不需要根某一特定的二元运算耦合在一起,
# 所以calc函数变得通用性更强,可以由传入的第二个参数来决定到底做什么
def calc(my_list, op):
total = my_list[0]
for index in range(1, len(my_list) - 1):
total = op(my_list[index], total)
return total
def add(x, y):
return x + y
def mul(x, y):
return x * y
def record(fn):
def wrapper(*args, **kwargs):
print('准备执行%s函数' % fn.__name__)
print(args)
print(kwargs)
# 此行代码在执行被装饰的函数
# 在这行代码的前后我们可以附加其他的代码
# 这些代码可以让我们在执行函数时做一些额外的工作
val = fn(*args, **kwargs)
print('%s函数执行完成' % fn.__name__)
print('返回了%d' % val)
# 返回被装饰的函数的执行结果
return val
return wrapper
# 通过装饰器修饰f函数 让f函数在执行过程中可以做更多额外的操作
@record
def f(n):
if n == 0 or n == 1:
return 1
else:
return n * f(n-1)
if __name__ == '__main__':
print(f(5))
my_list = [1, 3, 5, 7, 8]
print(calc(my_list, add))
print(calc(my_list, mul))
继承、抽象类、抽象方法
# 线段上有两个点 - has-a - 关联
# 人使用了房子 - use-a - 依赖
# 学生是人 - is-a - 继承
# 继承 - 从已经有的类创建新类的过程
# 提供继承信息的称为父类(超类/基类)
# 得到继承信息的称为子类(派生类/衍生类)
# 通过继承我们可以将子类中的重复代码抽取到父类中
# 子类通过继承并复用这些代码来减少重复代码的编写
# 将来如果要维护子类的公共代码只需要在父类中操作就可以了
# 调用super().__init__(name,age,……)来绑定父类属性到子类
# 方法重写(override)- 覆盖 / 置换
# 子类在继承父类方法后对方法进行了重新实现
# super().watch_av() # 传入父类方法的函数
# 当我们给子类对象发送watch_av消息时执行的是子类重写过的方法
# python没有从语言层面支持抽象的概念
# 我们可以通过abc模块来制造抽象类的效果
# 在定义类的时候通过制定metaclass=ABCMeta可以将类声明为抽象类
# 抽象类是不能创建对象的 抽象类存在的意义是专门拿给其他类继承
# abc模块中还有一个包装器abstractmethod
# 通过这个包装器可以将方法包装为抽象方法 必须要求子类进行重写
from abc import ABCMeta, abstractmethod
class Employee(object, metaclass=ABCMeta):
"""员工"""
def __init__(self, name):
"""初始化方法"""
self._name = name
@property
def name(self):
return self._name
@abstractmethod
def get_salary(self):
"""获得月薪"""
pass
class Manager(Employee,object):
"""部门经理"""
def get_salary(self):
return 15000
class Programmer(Employee):
def __init__(self, name, working_hour = 0):
# 子类重新定义了__init__后系统就会选用子类的__init__
# 如果还需要父类的初始化属性需要添加super().__init__(……)
super().__init__(name)
self._working_hour = working_hour
@property
def working_hour(self):
return self._working_hour
@working_hour.setter
def working_hour(self, working_hour):
self._working_hour = working_hour \
if working_hour > 0 else 0
def get_salary(self):
return self.working_hour * 150
class Salesman(Employee):
def __init__(self, name):
super().__init__(name)
self._sales = 0
@property
def sales(self):
return self._sales
@sales.setter
def sales(self, sales):
self._sales = sales if sales > 0 else 0
def get_salary(self):
return 1200 + self._sales * 0.05
def main():
emps = [
Manager('刘备'), Programmer('诸葛亮'),
Manager('曹操'), Salesman('卢布'),
Programmer('赵云'), Salesman('荀彧')
]
for emp in emps:
if isinstance(emp, Programmer):
emp.working_hour = eval(input('请输入%s本月工作时间:' % emp.name))
elif isinstance(emp, Salesman):
emp.sales = float(input('请输入%s本月销售额:' % emp.name))
# 同样是接收get_salary这个消息,但是不同的员工表现出了不同的行为
# 因为三个子类都重写了get_salary方法,所以这个方法会表现出多态行为
print('%s本月工资为:¥%.2f' % (emp.name, emp.get_salary()))
if __name__ == '__main__':
main()
实例
计算矩形面积和周长
class Rectangle(object):
__slots__ = ('_width', '_hight')
def __init__(self, width, hight):
self._width = eval(width)
self._hight = eval(hight)
@property
def width(self):
return self._width
@width.setter
def width(self, width):
self._width = width if width > 0 else 0
@property
def hight(self):
return self._hight
@width.setter
def width(self, hight):
self._hight = hight if width > 0 else 0
def peri(self):
return self._width * 2 + self._hight * 2
def arer(self):
return self._hight * self._width
if __name__ == '__main__':
rect1 = Rectangle('10', '5')
print(rect1.peri())
print(rect1.arer())
width = 20
hight = 30
print(rect1.peri())
print(rect1.arer())
模拟银行账户功能
class Account(object):
def __init__(self, *, card_no, owner, banlance = 0):
# *号后面的参数必须要写成关键字参数形式,
self._card_no = card_no
self._woner = owner
self._banlance = banlance
@property
def banlance(self):
return self._banlance
def deposit(self, money):
if money > 0:
self._banlance += money
return True
return False
def withdrow(self, money):
if 0 < money <= self._banlance:
self._banlance -= money
return True
return False
def transfer(self, other, money):
if self.withdrow(money):
other.deposit(money)
return True
return False
def main():
account = Account(card_no='12245', owner='王凯')
account1 = Account(card_no='35222', owner='凯fjs')
print(account.banlance)
account.deposit(900)
print(account1.banlance)
print(account.banlance)
if account.transfer(account1,1000):
print(account1.banlance)
print(account.banlance)
else:
print('余额不足')
if account.transfer(account1,200):
print(account1.banlance)
print(account.banlance)
else:
print('余额不足')
if __name__ == '__main__':
main()
定义一副扑克
from random import randrange
class Card(object):
"""一张牌"""
def __init__(self, suite, face):
self._suite = suite
self._face = face
@property
def face(self):
return self._face
@property
def suite(self):
return self._suite
def __str__(self):
if self._face == 14:
face_str = 'A'
elif self._face == 11:
face_str = 'J'
elif self._face == 12:
face_str = 'Q'
elif self._face == 13:
face_str = 'K'
else:
face_str = str(self._face)
return '%s%s' % (self._suite, face_str)
class Poker(object):
"""一副牌"""
def __init__(self):
self._current = 0
self._cards = []
for suite in '♠♥♣♦':
for face in range(2, 15):
card = Card(suite, face)
self._cards.append(card)
@property
def cards(self):
return self._cards
def shuffle(self):
"""洗牌"""
cards_len = len(self._cards)
for index in range(cards_len):
pos = randrange(cards_len)
self._cards[index], self._cards[pos] = \
self._cards[pos], self._cards[index]
@property
def next(self):
"""发牌"""
card = self._cards[self._current]
self._current += 1
return card
@property
def has_next(self):
"""还有没有牌"""
return self._current < len(self.cards)
class Player(object):
def __init__(self, name):
self._name = name
self._cards_on_hand = []
@property
def name(self):
return self._name
@property
def hava(self):
return self._cards_on_hand
def get(self, card):
self._cards_on_hand.append(card)
def arrange(self):
self._cards_on_hand.sort(key=get_key)
def get_key(card):
return card.face
def main():
p = Poker()
p.shuffle()
players = [
Player('东邪'), Player('西毒'),
Player('南帝'), Player('北丐')
]
while p.has_next:
for player in players:
player.get(p.next)
for player in players:
player.arrange()
print(player.name +':', end=' ')
for cards in player.hava:
print(cards, end='\t')
print('')
if __name__ == '__main__':
main()
21点扑克牌游戏(游戏)
需要用到上面定义的扑克牌
from poker import *
def cacl(list1):
list2 = []
for card in list1:
if card.face == 11:
list2.append(10)
elif card.face == 12:
list2.append(10)
elif card.face == 13:
list2.append(10)
elif card.face == 14:
list2.append(11)
if sum(list2) > 21:
list2.pop()
list2.append(1)
else:
list2.append(int(card.face))
if sum(list2) > 21 :
for key in list2:
if key == 11:
list2.append(-10)
return sum(list2)
def display(player):
print('%s: ' % player.name, end='')
for key in player.hava:
print(key, end=' ')
print('点数为:%d' % cacl(player.hava), end=' ')
def winer(player, m_player):
if cacl(m_player.hava) <= 21:
if cacl(m_player.hava) < cacl(player.hava) <=21:
display(player)
print('赢了')
elif cacl(player.hava) > 21:
display(player)
print('爆了')
elif cacl(player.hava) == cacl(m_player.hava):
display(player)
print('平局')
else:
display(player)
print('输了')
else:
if cacl(player.hava) <= 21:
display(player)
print('赢了')
elif cacl(player.hava) > 21:
display(player)
print('平局')
def main():
p = Poker()
p.shuffle()
players = [
Player('庄家'), Player('玩家1'), Player('玩家2'), Player('玩家3')
]
while p.has_next:
for i in range(2):
players[0].get(p.next)
p.cards.remove(players[0].hava[-1])
if i == 0:
print('%s:' % players[0].name, players[0].hava[i], end=' ')
elif i == 1:
print('*')
for player in players[1:]:
for i in range(2):
player.get(p.next)
p.cards.remove(player.hava[-1])
display(player)
print()
for player in players[1:]:
while cacl(player.hava) <= 21:
go_on = input('%s是否继续拿牌?(y/n)' % player.name)
if go_on == 'y':
player.get(p.next)
p.cards.remove(player.hava[-1])
display(player)
print()
elif go_on == 'n':
break
print('\n庄家继续拿牌')
while cacl(players[0].hava) < 17:
players[0].get(p.next)
p.cards.remove(players[0].hava[-1])
print('=================================')
display(players[0])
print()
for player in players[1:]:
winer(player, players[0])
break
if __name__ == '__main__':
main()
实现分数的加减乘除(运算符重载,集联编程)
# 运算符重载(重写)
# 集联编程
from math import gcd
class Fraction(object):
def __init__(self, num, den):
if den == 0:
raise ValueError('分母不能为0')
self._num = num
self._den = den
# self.normalize()
# self.simplify()
@property
def num(self):
return self._num
@property
def den(self):
return self._den
def normalize(self):
"""标准化"""
if self._den < 0:
self._den = -self._den
self._num = -self._num
return self # 返回self后才能集联编程
def simplify(self):
"""化简"""
if self._num != 0 and self._den != 1:
factor = gcd(abs(self._den), abs(self._num))
if factor > 1:
self._num //= factor
self._den //= factor
return self # 返回self后才能集联编程
def add(self, other):
return Fraction(self._num * other.den + self._den * other.num, self._den * other.den).simplify().normalize()
def sub(self, other):
return Fraction(self._num * other.den - self._den * other.num, self._den * other.den).simplify().normalize()
def mul(self, other):
return Fraction(self._num * other.num, self._den * other.den).simplify().normalize()
def div(self, other):
return Fraction(self._num * other.den, self._den * other.num).simplify().normalize()
def __add__(self, other):
return self.add(other)
def __sub__(self, other):
return self.sub(other)
def __mul__(self, other):
return self.mul(other)
def __truediv__(self, other):
return self.div(other)
def __str__(self):
if self._num == 0:
return '0'
elif self._den == 1:
return str(self._num)
else:
return '%d/%d' % (self._num, self._den)
def main():
f1 = Fraction(-7, 25)
f2 = Fraction(-7, 35)
print(f1 + f2)
print(f1 - f2)
print(f1 * f2)
print(f1 / f2)
if __name__ == '__main__':
main()
五子棋(游戏)
import pygame
EMPTY = 0
BLACK = 1
WHITE = 2
black_color = [0, 0, 0]
white_color = [255, 255, 255]
class RenjuBoard(object):
def __init__(self):
self._board = [[0 for _ in range(15)] for __ in range(15)] # 创建15个空列表的列表
self.reset()
def reset(self):
for row in range(len(self._board)):
self._board[row] = [EMPTY] * 15 # 清除棋盘所有棋子
def check(self, row, col): # 判断输赢
q = 1
for i in range(1, 5):
if row + i <= 14 and self._board[row][col] == self._board[row + i][col]:
q += 1
elif row - i >= 0 and self._board[row][col] == self._board[row - i][col]:
q += 1
else:
q = 1
if q >= 5:
return True
for i in range(1, 5):
if col + i <= 14 and self._board[row][col] == self._board[row][col + i]:
q += 1
elif col - i >= 0 and self._board[row][col] == self._board[row][col - i]:
q += 1
else:
q = 1
if q >= 5:
return True
for i in range(1, 5):
if row - i >= 0 and col - i >= 0 and self._board[row][col] == self._board[row - i][col - i]:
q += 1
elif row + i <= 14 and col + i <= 14 and self._board[row][col] == self._board[row + i][col + i]:
q += 1
else:
q = 1
if q >= 5:
return True
for i in range(1, 5):
if row - i >= 0 and col + i <= 14 and self._board[row][col] == self._board[row - i][col + i]:
q += 1
elif row + i <= 14 and col - i >= 0 and self._board[row][col] == self._board[row + i][col - i]:
q += 1
else:
q = 1
if q >= 5:
return True
def move(self, row, col, is_black):
if self._board[row][col] == EMPTY:
self._board[row][col] = BLACK if is_black else WHITE
return True
return False
def draw(self, screen):
for i in range(40, 640, 40):
pygame.draw.line(screen, black_color, [40, i], [600, i], 1)
pygame.draw.line(screen, black_color, [i, 40], [i, 600], 1) # 画线 做棋盘
pygame.draw.rect(screen, black_color, [36, 36, 568, 568], 4) # 画矩形 36,36 表示起点 568 , 568 表示宽高 4 表示宽度
pygame.draw.circle(screen, black_color, [320, 320], 5, 0) # 绘制中心 5 为半径 0 为实心 1 为空心
for i in range(160, 481, 320):
for j in range(160, 481, 320):
pygame.draw.circle(screen, black_color, [i, j], 5, 0) # 绘制其他四个点
for row in range(len(self._board)):
for col in range(len(self._board[row])):
if self._board[row][col] != EMPTY:
ccolor = black_color \
if self._board[row][col] == BLACK else white_color
pos = [40 * (col + 1), 40 * (row + 1)]
pygame.draw.circle(screen, ccolor, pos, 20, 0)
def main():
black_win = pygame.image.load('win.jpg') # 加载图片
white_win = pygame.image.load('fall.jpg')
board = RenjuBoard()
is_black = True
pygame.init() # 初始化
pygame.display.set_caption('五子棋') # 设置标题
screen = pygame.display.set_mode([640, 640]) # 设置屏幕大小
screen.fill([255, 255, 0]) # 设置背景颜色
board.draw(screen) # 绘制棋盘
pygame.display.flip() # 刷新界面显示
running = ok = True
while running:
for event in pygame.event.get(): #捕获所有事件,鼠标|键盘
if event.type == pygame.QUIT: # 捕获点击退出事件
running = False
elif event.type == pygame.KEYDOWN and event.key == pygame.K_q: # 捕获按下键盘q键
board.reset() # 重置棋盘及棋子
is_black = True # 重置棋色
screen.fill([255, 255, 0]) # 重置背景颜色
board.draw(screen) # 绘制棋盘及棋子(开始无棋子)
pygame.display.flip() # 刷新出界面
elif event.type == pygame.MOUSEBUTTONDOWN\
and event.button == 1: # 单机鼠标添加棋子
x, y = event.pos # 获取点击位置
if 40 <= x <= 640 and 40 <= y <= 640: # 判断是点击位置是不是在棋盘上
row = round((y - 40) / 40)
col = round((x - 40) / 40)
if board.move(row, col, is_black):
is_black = not is_black
screen.fill([255, 255, 0])
board.draw(screen)
if board.check(row, col):
if not is_black: # 白棋赢显示的图片
screen.blit(black_win, (0, 20), (20, 0,800,800))
elif is_black: # 黑棋赢显示的图片
screen.blit(white_win, (90, 0), (40, 0,600,600))
if ok:
pygame.display.flip()
pygame.quit()
if __name__ == '__main__':
main()
·
大球吃小球(游戏)
from random import randint
import math
import pygame
class Ball(object):
def __init__(self, center, color, radius, speed):
self._center = center
self._color = color
self._radius = radius
self._speed = speed
@property
def center(self):
return self._center
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, new):
self._radius = new
def cross(self, other): # 判断一个球是否与另一个球重合,如果是,增加大球面积,让小球面积变为零
x, y = self._center[0], self._center[1]
x1, y1 = other.center[0], other.center[1]
if math.sqrt((y1 - y) ** 2 + (x1 - x) ** 2) <= abs(self._radius - other.radius):
if self._radius > other.radius:
self.radius = int(math.sqrt(self._radius ** 2 + other.radius ** 2))
other.radius = 0
else:
other.radius = int(math.sqrt(self._radius ** 2 + other.radius ** 2))
self.radius = 0
def move(self): # 更改每个球的坐标,实现移动,并在边界弹回来
x, y = self._center[0], self._center[1]
sx, sy = self._speed[0], self._speed[1]
self._center = x, y = x + sx, y + sy
if x + self._radius >= 800:
self._speed = -abs(sx), sy
elif x - self._radius <= 0:
self._speed = abs(sx), sy
if y + self._radius >= 600:
self._speed = sx,-abs(sy)
elif y - self._radius <= 0:
self._speed = sx,abs(sy)
def draw(self, screen): # 画出球
pygame.draw.circle(screen, self._color, self._center,
self._radius, 0)
def main():
balls = []
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption('大球吃小球')
clock = pygame.time.Clock() # 设置一个计时器
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN \
and event.button == 1:
color = random_color()
radius = randint(10, 100) # 球的半径
speed = randint(-10, 10), randint(-10, 10) # 球x,y方向的移动速度及方向
ball = Ball(event.pos, color, radius, speed)
balls.append(ball)
refresh(screen, balls)
clock.tick(24) # 一秒刷新24次
for ball in balls:
ball.move() # 每个球开始移动
if len(balls) >= 2:
for num in range(len(balls)):
for num1 in range(num + 1, len(balls)):
balls[num].cross(balls[num1]) #判断两个球是否重合,重合就吃掉小球,打球面积增加
pygame.quit()
def refresh(screen, balls): # 刷新窗口界面
bg_color = (240, 255, 240)
screen.fill(bg_color)
for ball in balls:
ball.draw(screen)
pygame.display.flip()
def random_color(): # 随机产生颜色
red = randint(0, 255)
green = randint(0, 255)
blue = randint(0, 255)
return red, green, blue
if __name__ == '__main__':
main()
贪吃蛇(游戏)
from abc import ABCMeta, abstractmethod
from random import randint
import pygame
FOOD_COLOR = (51, 221, 43)
WALL_COLOR = (255, 0, 0)
GREEN_COLOR = (0, 255, 0)
UP = 0
RIGHT = 1
DOWN = 2
LEFE = 3
class GameObject(object, metaclass=ABCMeta):
# 抽象类
def __init__(self, x, y, color):
self._color = color
self._x = x
self._y = y
@abstractmethod # 抽象方法,子类必须拥有此方法
def draw(self, screen):
pass
@property
def x(self):
return self._x
@property
def y(self):
return self._y
class Wall(GameObject):
def __init__(self, x, y, width, height, color=WALL_COLOR):
super().__init__(x, y, color)
self._width = width
self._height = height
@property
def width(self):
return self._width
@property
def height(self):
return self._height
def draw(self, screen): # 画出边框 也就是墙
pygame.draw.rect(screen, self._color, (self._x, self._y, self._width, self._height), 5)
# (屏幕,颜色,(起点x坐标,起点y坐标,宽度,高度),线宽)
class Food(GameObject):
def __init__(self, x, y, size, color=FOOD_COLOR):
super(Food, self).__init__(x, y, color)
self._size = size
self._show = True
def new_dot(self):
dot = [x for x in range(10, 610, 20)]
self._x = dot[randint(0, len(dot) - 1)]
self._y = dot[randint(0, len(dot) - 1)]
def draw(self, screen): # 画食物,食物的坐标点是其左上角的点
if self._show:
pygame.draw.circle(screen, self._color,
(self._x + self._size // 2, self._y + self._size // 2), self._size // 2, 0)
# (屏幕,颜色,(圆点x坐标,圆点y坐标),半径,实心0 or 空心1)
self._show = not self._show
class SnakeNode(GameObject):
# x, y 必须为基数(左上角坐标点),因为蛇移动的窗口的左上角坐标为(0,0)
def __init__(self, x, y, size, color=GREEN_COLOR):
super().__init__(x, y, color)
self._size = size
@property
def size(self):
return self._size
def draw(self, screen): # 绘制蛇的节点和每个节点的边框
pygame.draw.rect(screen, self._color, (self._x, self._y, self._size, self._size), 0)
pygame.draw.rect(screen, (230, 255, 230), (self._x, self._y, self._size, self._size), 1)
class Snake(object): # 不能继承蛇的节点SnakeNode,蛇上有蛇的节点 是has a 关联关系 非继承关系
def __init__(self):
"""
定义蛇默认移动方向和长度
"""
self._dir = LEFE
self._nodes = []
# 装蛇的每个节点,利用append向后依次装载
for index in range(10):
node = SnakeNode(290 + index * 20, 250, 20)
self._nodes.append(node)
@property
def dir(self):
return self._dir
def change_dir(self, new_dir):
"""
改变蛇的方向
:param new_dir: 新的方向
:return: 返回新的方向,如果新方向是原来方向或者原来方向的反方向则不返回
"""
if (self._dir + new_dir) % 2 != 0:
self._dir = new_dir
def move(self):
head = self._nodes[0]
snake_dir = self._dir
x, y, size = head.x, head.y, head.size
if snake_dir == UP:
y -= size
elif snake_dir == RIGHT:
x += size
elif snake_dir == DOWN:
y += size
else:
x -= size
new_head = SnakeNode(x, y, size)
self._nodes.insert(0, new_head)
# 每次移动时在列表前面加一个节点,并删除最后一个节点
self._nodes.pop()
def collide(self, wall):
"""
判断是否撞墙
:param wall: 墙
:return: 撞到返回True 否则返回False
"""
head = self._nodes[0]
x, y, size = head.x, head.y, head.size
return x < wall.x or x > (wall.x + wall.width - size) or y < wall.y or y > (wall.y + wall.width - size)
def eat_food(self, food):
"""
判断是否吃到食物
:param food: 食物对象
:return: 吃到返回True,并记下最后一个节点属性,并加到最后。
(由于蛇每次移动都会删掉最后一节尾巴并增加新的头,所以相当于此次没有删除蛇尾)
"""
head = self._nodes[0]
x, y, size = head.x, head.y, head.size
if x == food.x and y == food.y:
tail = self._nodes[-1]
self._nodes.append(tail)
return True
def eat_me(self):
"""
判断蛇是否吃到自己
:return: 吃到返回True
"""
head = self._nodes[0]
x, y, size = head.x, head.y, head.size
for a_node in self._nodes[4:]:
ax, ay = a_node.x, a_node.y
if abs(ax - x) < 20 and ay == y:
return True
if abs(ay - y) < 20 and ax == x:
return True
# 此处不能用elif,因为蛇在移动时不光检测两个方向,而是四个方向
def draw(self, screen):
"""
画出每个列表中每个节点
:param screen: 画节点的屏幕
:return: 可视化图形
"""
for node in self._nodes:
node.draw(screen)
def main():
def handle_key_event(key_event):
"""
处理按键事件
:param key_event: 捕获的键盘事件
:return: 新的方向
"""
key = key_event.key
if key == pygame.K_UP or key == pygame.K_w:
new_dir = UP
elif key == pygame.K_RIGHT or key == pygame.K_d:
new_dir = RIGHT
elif key == pygame.K_DOWN or key == pygame.K_s:
new_dir = DOWN
elif key == pygame.K_LEFT or key == pygame.K_a:
new_dir = LEFE
elif key == pygame.K_q:
reset_game()
return # 加上return 让代码执行到此处后 后面的代码不在执行
else:
return
if new_dir != snake.dir:
snake.change_dir(new_dir)
def reset_game():
"""
重置游戏
:return: 最初游戏状态
(重新对蛇和食物赋值,并清空键盘事件(方向))
"""
nonlocal snake, food
snake = Snake()
food = Food(190, 190, 20)
pygame.event.clear()
def refresh():
"""刷新游戏窗口"""
food.draw(screen)
wall.draw(screen)
pygame.display.flip()
def display_die():# 死亡后显示Game Over!
font = pygame.font.SysFont('arial', 32)
text = font.render('Game Over!', True, (255, 0, 0))
screen.blit(text, (250, 260))
def display_str(x):# 显示吃到食物数量
font = pygame.font.SysFont('arial', 32)
text = font.render('%s' % x, True, (255, 0, 0))
screen.blit(text, (550, 20))
snake = Snake()
food = Food(190, 190, 20)
wall = Wall(10, 10, 600, 600)
pygame.init()
screen = pygame.display.set_mode((620, 620))
pygame.display.set_caption('贪吃蛇')
screen.fill([244, 244, 244])
pygame.display.flip()
clock = pygame.time.Clock()
running = True
i = 0
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
handle_key_event(event)
clock.tick(3)
if not snake.collide(wall) and not snake.eat_me():
snake.draw(screen)
refresh()
snake.move()
# move 和 refresh的位置不能改变,否则蛇死亡时会停在撞到的下一步
else:
display_die() # 此处没让蛇重新画,目的是当显示Game Over时蛇不会停在撞墙的下一步
refresh()
if snake.eat_food(food):
i += 1
food.new_dot()
screen.fill([244, 244, 244])
display_str(i)
pygame.quit()
if __name__ == '__main__':
main()