【卡码网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 = radius
        
circle = 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_type
        self.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.radius
      
circle = Circle('circle', 'white', 10)
# 计算圆的面积
circle.calculate_area()

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

super().__init()

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

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

四、多态

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

class Shape:
    # 基类的计算面积的方法
    def calculate_area(self):
        pass

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
        # Circle类的计算面积的方法
    def calculate_area(self):
        return 3.14 * self.radius * self.radius

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.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_type
     
    def calculate_area(self):
        pass

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

class Rectangle(Shape):
    def __init__(self, width, height):
        super().__init__("Rectangle")
        self.width = width
        self.height = height
 
    def CalculateArea(self):
        return self.width * self.height
 
class Circle(Shape):
    def __init__(self, radius):
        super().__init__("Circle")
        self.radius = radius
 
    def 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_type
     
    def calculate_area(self):
        pass
#  Rectangle类,包含 width 和 height, 计算面积的方法
class Rectangle(Shape):
    def __init__(self, width, height):
        super().__init__("Rectangle")
        self.width = width
        self.height = height
 
    def calculate_area(self):
        return self.width * self.height
# Circle类,包含 radius, 计算面积的方法 
class Circle(Shape):
    def __init__(self, radius):
        super().__init__("Circle")
        self.radius = radius
 
    def calculate_area(self):
        return 3.14 * self.radius * self.radius
         
shapes = []
 
while True:
    data = input().split()
    shape_type = data[0]
    # 处理输出
    if shape_type == "end":
        break

    if 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}")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值