当前位置: 首页 > news >正文

【卡码网Python基础课 21.图形的面积】

目录

  • 题目描述与分析
  • 一、类
  • 二、封装
  • 三、继承
  • 四、多态
  • 五、代码编写


题目描述与分析

题目描述:
考虑一个简单的图形类层次结构,包括基类 Shape 和两个派生类 Rectangle 和 Circle。每个类都有一个用于计算面积的方法。你的任务是编写一个程序,根据输入数据创建一个图形对象,然后计算并输出其面积。

输入描述:
输入包括多行,每行包含一个图形的描述。 描述的第一个单词是图形类型(“rectangle"或"circle”),然后是与该图形相关的参数。 对于矩形,参数是宽度和高度,对于圆形,参数是半径。输入以单词"end"结束。

输出描述:
对于每个图形描述,输出其类型和面积。使用两位小数点精度输出面积。

输入示例:

rectangle 5 3
circle 2
end

输出示例:

Rectangle area: 15.00
Circle area: 12.56

一、类

在链表章节中,我们学习了类和对象(实例)的定义,现在我们先来回顾一下类的基本写法

class 类名:公共的属性...# 对象的初始化方法,初始化一些属性def __init__(self, ...):# pass# 其他的方法def method_1(self, ...):# pass# 创建类的实例
instance1 = 类名(参数)
# 调用类的方法
instance1.method_1(参数)

在Python中,类是一种结构,它用于将数据(属性)和相关操作(方法)封装到一起。使用类可以创建具有特定行为和属性的对象,这是面向对象编程(OOP)的核心概念之一。

类通过关键字 class 定义。类名通常使用大写字母开头的驼峰命名法。在类中定义的函数称为方法,它们用于定义对象的行为。特殊的 init 方法称为构造器,用于初始化新创建的对象。

class Dog:def __init__(self, name, age):self.name = name  # 实例变量self.age = age    # 实例变量def speak(self):return "Woof!"

在这个例子中,Dog 类有两个实例变量 name 和 age,以及一个方法 speak。

二、封装

封装是面向对象编程(OOP)的三大基本特征之一,另外两个是继承和多态。封装是指将对象的数据(属性)和操作这些数据的方法绑定到一起的做法,并对对象的某些组件进行隐藏,仅暴露出必要的部分给外界使用。
我们假设有一个“圆形”的类Circle,它具有半径radius这个属性。

class Circle:def __init__(self, radius):self.radius = radius

然后我们创建一个圆对象circle

circle = Circle(5) # 创建一个对象,半径为5

但是这样,外部代码可以直接访问和修改半径,甚至将其设置为负数,这样的设计显然是不合理的。

# 外部代码没有经过验证可以直接访问和修改半径
circle.radius = -10

为了防止这些问题的发生,我们可以通过封装隐藏对象中一些不希望被外部所访问到的属性或方法,具体可以分为两步:
1.将对象的属性名,修改为一个外部不知道的名字
2.提供getter和setter来获取和设置对象的属性
一般情况下,对于对象的隐藏属性,使用双下划线开头:__xxx

class Circle:def __int__(self, radius):# 1. 将属性名,修改为一个外部不知道的名字self.__radius = radius # 使用双下划线前缀将属性私有化# 2. 定义get方法,获取属性def get_radius(self):return self.__radius# 2. 定义set方法,设置属性def set_radius(self, radius):self.__radius = radiuscircle = Circle(5) # 创建一个对象,半径为5
# 只有通过对应的方法,才能修改属性
circle.set_radius(10)

使用封装,我们隐藏了类的一些属性,具体的做法是使用getter方法获取属性,使用setter方法设置属性,如果希望属性是只读的,则可以直接去掉setter方法,如果希望属性不能被外部访问,则可以直接去掉getter方法。
此外我们还可以在读取属性和修改属性的同时做一些其他的处理,比如如下的操作:

def set_radius(self, radius):if radius > 0:self.__radius = radius
circle.set_radius(-10) # 不会成功设置radius属性

三、继承

在对象中,总有一些操作是重复的,比如说Person类具有姓名、身高、年龄等特征,并具有一些行走、吃饭、睡觉的方法,而我们要实现一个Teacher类,Teacher首先也是一个人,他也基本人的特征和方法,那我们是不是也应该用代码去实现这些特征和方法呢,这就势必会产生一些重复的代码。

因此,我们可以采用“继承”的方式使得一个类获取到其他类中的属性和方法。在定义类时,可以在类名后的括号指定当前类的父类(超类), 子类可以直接继承父类中的所有属性和方法,从而避免编写重复性的代码,此外我们还可以对子类进行扩展。

继承是面向对象编程(OOP)的一种基本特性,它允许新创建的类(称为子类或派生类)继承另一个类(称为父类或基类)的属性和方法。继承是一种创建新类的方法,新类可以重用、扩展或修改另一个类的行为。

假设,我们有一个图形类Shape, 它具有两个属性和一个方法,属性为颜色和类型,方法为求图形的面积

class Shape:# 包含颜色和类型两个属性def __init__(self, shape_type, color):self.type = shape_typeself.color = color# 计算图形面积的方法def calculate_area(self):# pass表示空语句,不需要执行任何操作pass
shape = Shape('shape', 'white')

我们还需要一个关于圆的类,它继承自Shape类

# 传入Shape, 表示基础自Shape类
class Circle(Shape):def __init__(self, shape_type, color, radius):super().__init__(shape_type, color)self.radius = radius# 计算圆的面积def calculate_area(self):return 3.14 * self.radius * self.radiuscircle = Circle('circle', 'white', 10)
# 计算圆的面积
circle.calculate_area()

在上面的示例代码中,图形类拥有两个属性和一个方法,圆的类在图形类的基础上添加了半径这个属性。

super().__init()

父类和子类中含有一些共同属性,在重写子类时,为了省略重复的代码,可以通过super()动态的获取当前类的父类, 并调用父类的__init__()方法从而初始化父类中定义的属性。

在子类和父类中都有calculate_area这个方法,这被称为方法的重写,子类会调用自己的方法而不是父类的方法。如果子类的对象调用一个方法,发现并没有提供这个方法,就会从当前对象的父类中寻找,如果父类中有则直接调用父类中的方法,如果还没有,就从父类的父类中寻找,就好像,当父亲和儿子都拥有一样东西,会优先使用自己的,如果发现自己没有,才会使用继承的方法。

四、多态

多态常常和继承紧密相连,它允许不同的对象对方法调用做出不同的响应。你可以使用基类定义通用的代码,然后在派生类中提供特定的实现,从而在调用方法时调用不同的方法,比如下面的示例:

class Shape:# 基类的计算面积的方法def calculate_area(self):passclass Circle(Shape):def __init__(self, radius):self.radius = radius# Circle类的计算面积的方法def calculate_area(self):return 3.14 * self.radius * self.radiusclass Rectangle(Shape):def __init__(self, width, height):self.width = widthself.height = height# Rectangle类的计算面积的方法def calculate_area(self):return self.width * self.height# 创建不同类型的图形对象
circle = Circle(2)
rectangle = Rectangle(4, 3)# 存放图形对象的列表
shapes = [circle, rectangle]# 计算面积
for shape in shapes:# 列表中的每个元素都调用计算面积的方法area = shape.calculate_area()# 输出面积print(f"Area: {area:.2f}")

在上面的代码示例中,基类 Shape 实现了calculate_area 方法, 两个派生类 Circle 和 Rectangle则是重写了 calculate_area 方法,它们有着不同的计算逻辑。之后我们创建了一个包含不同类型的图形对象的列表 shapes,然后循环遍历该列表并调用 calculate_area 方法,尽管方法名称相同,但实际调用的方法是根据对象的类型动态确定的,这其实就是多态的概念。

五、代码编写

根据题目要求,Shape类应该具有一个属性type和一个方法calculate_area用了计算面积

class Shape:def __init__(self, shape_type):self.type = shape_typedef calculate_area(self):pass

之后,我们需要实现两个类Rectangle和Circle,它们都继承自类Shape

class Rectangle(Shape):def __init__(self, width, height):super().__init__("Rectangle")self.width = widthself.height = heightdef CalculateArea(self):return self.width * self.heightclass Circle(Shape):def __init__(self, radius):super().__init__("Circle")self.radius = radiusdef CalculateArea(self):return 3.14 * self.radius * self.radius

之后,我们可以定义一个列表,用来放置建立的示例,并处理输入输出

shapes = []while True:data = input().split()# 获取输入的类型shape_type = data[0]

对输入的类型进行判断,如果是"end", 终止程序,如果是图形,则建立对应的实例

# 处理type = "end"的情况
if shape_type == "end":break
# 处理 type = "rectangle"的情况,获取宽和高,并新建实例,append()到列表中
if shape_type == "rectangle":width, height = float(data[1]), float(data[2])shapes.append(Rectangle(width, height))
# 处理 type = "circle"的情况,获取半径,并新建实例,append()到列表中
elif shape_type == "circle":radius = float(data[1])shapes.append(Circle(radius))

最后, 遍历列表,并输出面积即可

for shape in shapes:print(f"{shape.type} area: {shape.calculate_rea():.2f}")

完整的代码如下:

# Shape类
class Shape:def __init__(self, shape_type):self.type = shape_typedef calculate_area(self):pass
#  Rectangle类,包含 width 和 height, 计算面积的方法
class Rectangle(Shape):def __init__(self, width, height):super().__init__("Rectangle")self.width = widthself.height = heightdef calculate_area(self):return self.width * self.height
# Circle类,包含 radius, 计算面积的方法 
class Circle(Shape):def __init__(self, radius):super().__init__("Circle")self.radius = radiusdef calculate_area(self):return 3.14 * self.radius * self.radiusshapes = []while True:data = input().split()shape_type = data[0]# 处理输出if shape_type == "end":breakif shape_type == "rectangle":# 获取输入的width/height, 将之转换成整数width, height = int(data[1]), int(data[2])# 新建一个对象,append到列表中shapes.append(Rectangle(width, height))elif shape_type == "circle":# 获取输入的radius, 将之转换成整数radius = int(data[1])# 新建一个对象,append到列表中shapes.append(Circle(radius))for shape in shapes:# 不同类别的对象调用同一个方法,有不同的处理逻辑print(f"{shape.type} area: {shape.calculate_area():.2f}")

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 高速信号的眼图、加重、均衡
  • Spire.PDF for .NET【文档操作】演示:检测 PDF 文件是否为 Portfolio
  • Airtest 的使用
  • 对比state和props的区别?
  • C语言——操作符详解
  • C++ STL sort_heap 用法
  • XSS---DOM破坏靶场复现
  • mybatisplus多数据源中关于不同类型的(mysql,oracle)数据库分页问题解决
  • 【Angular18】封装自定义组件
  • 二叉树《数据结构》
  • Swift代码审查的艺术:利用工具精炼代码质量
  • TCP详解(二)滑动窗口/流量控制
  • C++函数重载(一)
  • MySQL:information_schema查找某个表的主键是否在数据的其他位置出现之二
  • 三、前后端分离通用权限系统(3)
  • 【comparator, comparable】小总结
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • Centos6.8 使用rpm安装mysql5.7
  • gcc介绍及安装
  • JWT究竟是什么呢?
  • magento2项目上线注意事项
  • MyEclipse 8.0 GA 搭建 Struts2 + Spring2 + Hibernate3 (测试)
  • NSTimer学习笔记
  • Objective-C 中关联引用的概念
  • PaddlePaddle-GitHub的正确打开姿势
  • Redis字符串类型内部编码剖析
  • Storybook 5.0正式发布:有史以来变化最大的版本\n
  • Wamp集成环境 添加PHP的新版本
  • 二维平面内的碰撞检测【一】
  • 通信类
  • 移动端唤起键盘时取消position:fixed定位
  • 赢得Docker挑战最佳实践
  • 用Python写一份独特的元宵节祝福
  • #数据结构 笔记三
  • #我与Java虚拟机的故事#连载01:人在JVM,身不由己
  • #我与Java虚拟机的故事#连载15:完整阅读的第一本技术书籍
  • (06)金属布线——为半导体注入生命的连接
  • (21)起落架/可伸缩相机支架
  • (7)摄像机和云台
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (echarts)echarts使用时重新加载数据之前的数据存留在图上的问题
  • (Redis使用系列) SpirngBoot中关于Redis的值的各种方式的存储与取出 三
  • (不用互三)AI绘画:科技赋能艺术的崭新时代
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (详细版)Vary: Scaling up the Vision Vocabulary for Large Vision-Language Models
  • (续)使用Django搭建一个完整的项目(Centos7+Nginx)
  • (转)C#开发微信门户及应用(1)--开始使用微信接口
  • (转)Google的Objective-C编码规范
  • ***检测工具之RKHunter AIDE
  • .form文件_一篇文章学会文件上传
  • .NET Core 和 .NET Framework 中的 MEF2
  • .NET Core使用NPOI导出复杂,美观的Excel详解
  • .net 发送邮件
  • .NET 应用架构指导 V2 学习笔记(一) 软件架构的关键原则
  • .NET/C# 使窗口永不激活(No Activate 永不获得焦点)