Python学习的第十八天:面向对象的程序设计
对面向对象编程的基础理解
-
指令式编程 —> 面向过程(函数)编程 —> 程序比较简单的时候没有任何毛病
-
编程范式(程序设计的方法论):面向对象编程 / 函数式编程
-
对象:对象是可以接收消息的实体,面向对象编程就是通过给对象发消息达到解决问题的目标。
-
对象 = 数据 + 函数(方法)—> 对象将数据和操作数据的函数从逻辑上变成了一个整体。
- 一切皆为对象
- 对象都有属性和行为
- 每个对象都是独一无二的
- 对象一定属于某个类
-
类:将有共同特征(静态特征和动态特征)的对象的共同特征抽取出来之后得到的一个抽象概念。
-
简单的说,类是对象的蓝图(模板),有了类才能够创建出这种类型的对象。
-
面向对象编程:
-
定义类 —> 类的命名使用驼峰命名法(每个单词首字母大写)
- 数据抽象:找到和对象相关的静态特征(属性)—> 找名词
- 行为抽象:找到和对象相关的动态特征(方法)—> 找动词
-
造对象
-
发消息
-
例子1:面向对象编程的构建方法
# 第一步:定义类
class Student:
"""学生"""
# 数据抽象(属性)
def __init__(self, name, age):
self.name = name
self.age = age
# 行为抽象(方法)
def eat(self):
"""吃饭"""
print(f'{self.name}正在吃饭.')
def study(self, course_name):
"""学习"""
print(f'{self.name}正在学习{course_name}.')
def play(self, game_name):
"""玩"""
print(f'{self.name}正在玩{game_name}.')
def daily(self):
"""日常"""
if self.age < 22:
print(f'{self.name}正在上学')
else:
print(f'{self.name}正在工作')
# 第二步:创建对象 ---> 构造器语法 ---> 类名(..., ...)
stu1 = Student('小明', 15)
stu2 = Student('小红', 41)
# 第三步:给对象发消息(调用对象的方法)
stu1.study('Python程序设计')
stu1.eat()
stu1.daily()
stu2.play('斗地主')
stu2.daily()
# 可以直接更改数据
stu1.age = 23
stu1.daily()
例子2:电子表的运作
import os
import time
class Clock:
"""时钟"""
def __init__(self, hour=0, minute=0, second=0):
self.hour = hour
self.minute = minute
self.second = second
def show(self):
"""显示时间"""
return f'{self.hour:0>2d}:{self.minute:0>2d}:{self.second:0>2d}'
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
if __name__ == '__main__':
clock = Clock(23, 59, 58)
while True:
os.system('clear')
print(clock.show())
time.sleep(1)
clock.run()
特殊技巧
-
我们在类里面写的函数,通常称之为方法,它们基本上都是发给对象的消息。但是有的时候,我们的消息并不想发给对象,而是希望发给这个类(类本身也是一个对象),这个时候,我们可以使用静态方法或类方法:
静态方法 - 发给类的消息 —> @staticmethod —> 装饰器
类方法 - 发给类的消息 —> @classmethod —> 装饰器 —> 第一个参数(cls)是接收消息的类例子:定义描述三角形的类,提供计算周长和面积的方法
class Triangle: """三角形""" def __init__(self, a, b, c): self.a = a self.b = b self.c = c # @classmethod # def is_valid(cls, a, b, c): # return a + b > c and b + c > a and a + c > b @staticmethod def is_valid(a, b, c): return a + b > c and b + c > a and a + c > b def perimeter(self): return self.a + self.b + self.c def area(self): half = self.perimeter() / 2 return (half * (half - self.a) * (half - self.b) * (half - self.c)) ** 0.5 if __name__ == '__main__': # 调用静态方法,判断三条边能否构成三角形 if Triangle.is_valid(3, 4, 5): t = Triangle(3, 4, 5) print(t.perimeter()) print(t.area()) else: print('无效的边长,无法构造三角形对象')
-
-
魔术方法(魔法方法)—> 有特殊用途和意义的方法
- init —> 初始化方法,在调用构造器语法创建对象的时候会被自动调用
- str —> 获得对象的字符串表示,在调用print函数输出对象时会被自动调用
-
repr —> 获得对象的字符串表示,把对象放到容器中调用print输出时会自动调用
—> representation - lt —> 在使用 < 运算符比较两个对象大小时会自动调用
- 如果一个变量的取值只有有限个选项,可以考虑使用枚举类型。
Python中没有定义枚举类型的语法,但是可以通过继承Enum类来实现枚举类型。
结论1:枚举类型是定义符号常量的最佳选择
结论2:符号常量(有意义的名字)总是优于字面常量
例子:扑克游戏,四个玩家参与,先洗牌,再把牌发到四个玩家的手上。
from enum import Enum
import random
# 枚举类型
class Suite(Enum):
SPADE, HEART, CLUB, DIAMOND = range(4)
class Card:
"""牌"""
def __init__(self, suite, face):
self.suite = suite
self.face = face
def __str__(self):
return self.show()
def __repr__(self):
return self.show()
def __lt__(self, other):
if self.suite == other.suite:
return self.face < other.face
return self.suite.value < other.suite.value
def show(self):
"""显示"""
suites = ['♠️', '❤️', '♣️', '♦️']
faces = ['', 'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
return f'{suites[self.suite.value]}{faces[self.face]}'
class Poker:
"""扑克"""
def __init__(self):
self.cards = [Card(suite, face)
for suite in Suite
for face in range(1, 14)]
self.counter = 0
def shuffle(self):
"""洗牌"""
self.counter = 0
random.shuffle(self.cards)
def deal(self) -> Card:
"""发牌"""
card = self.cards[self.counter]
self.counter += 1
return card
def has_more(self) -> bool:
"""是否还有牌"""
return self.counter < len(self.cards)
class Player:
"""玩家"""
def __init__(self, nickname):
self.nickname = nickname
self.cards = []
def get_one_card(self, card):
"""摸一张牌"""
self.cards.append(card)
def arrange(self):
"""整理手上的牌"""
self.cards.sort()
def show(self):
"""显示玩家手上的牌"""
print(self.nickname, end=': ')
for card in self.cards:
print(card, end=' ')
print()
def main():
nicknames = ('小明', '小红', '小亮', '小李')
players = [Player(nickname) for nickname in nicknames]
poker = Poker()
poker.shuffle()
# 将牌发到四个玩家的手上
for _ in range(13):
for player in players:
card = poker.deal()
player.get_one_card(card)
# 显示四个玩家手上的牌
for player in players:
player.arrange()
player.show()
if __name__ == '__main__':
main()
)]