Python程序设计 实验7:面向对象编程

简介: Python程序设计 实验7:面向对象编程

一、编写类 RegularPolygon,表示正 n 边形。类包括:


私有成员 n,要求为整型,代表正 n 边形边的数量,注意n> 3;

私有成员 side,代表正 n 边形每条边的长度;

私有成员 x,代表正 n 边形中心的坐标在 x 轴上的数值;

私有成员 y,代表正 n 边形中心的坐标在 y 轴上的数值;

构造函数,输入参数为 n(默认为 3),side(默认为 1),x(默认为 0), y(默认为 0);

方法 getPerimeter,返回正 n 边形的周长;

方法 getArea,返回正 n 边形的面积;

方法 distanceToPolygon,输入参数为另外一个正 n 边形,返回两个正 n 边形中心的距离。

自行设计测试函数验证 RegularPolygon 类代码的正确性。


(1)大致思路:


定义一个RegularPolygon类,并定义四个私有变量,并赋初始值。然后定义每个方法,首先,获取周长方法只需直接返回边长与边数的积即可。获取面积方法则利用Python中的math库以及正多边形面积公式直接进行计算即可。获取多边形中心距离方法则直接获取当前中心点坐标以及传入参数的中心点坐标,并利用公式直接计算即可。


(2)编程实现:

# 引入math库进行三角函数计算以获得多边形面积
import math
# 定义RegularPolygon类
class RegularPolygon:
    # 初始化构造函数,并声明各私有变量
    def __init__(self, n=3, side=1, x=0, y=0):
        self._n = n
        self._side = side
        self._x = x
        self._y = y
    # 重载__str__函数便于输出
    def __str__(self):
        return 'This is a regularPolygon:' + '\n' + 'Number of side: ' + str(self._n) + '\n' + 'Length of side: ' + str(
            self._side) + '\n' + 'Position of centre: (' + str(self._x) + ' , ' + str(self._y) + ')' + '\n'
    # 定义获取周长函数
    def getPerimeter(self):
        return self._n * self._side
    # 定义获取面积函数
    def getArea(self):
        return 0.25 * self._n * self._side * self._side / math.tan(math.pi / self._n)
    # 定义计算到另一多边形中心点距离函数
    def distanceToPolygon(self, p):
        return ((self._x - p._x) ** 2 + (self._y - p._y) ** 2) ** 0.5


首先引入math库以便后面调用pai以及三角函数对正多边形面积进行求解。

定义RegularPolygon类,定义四个私有变量,并重载__str__函数从而方便对RegularPolygon进行输出测试。接下来实现几个方法,获取周长方法只需直接返回边长与边数的积即可;获取面积方法则利用Python中的math库以及正多边形面积公式直接进行计算即可;获取多边形中心距离方法则直接获取当前中心点坐标以及传入参数的中心点坐标,并利用公式直接计算即可。


(3)运行并测试:


运行如下代码对程序进行测试:


# 进行测试
# 测试缺省构造函数
polygon1 = RegularPolygon()
print(polygon1)
# 测试含参构造函数
polygon2 = RegularPolygon(4, 2, 1, 1)
print(polygon2)
#测试几个成员函数
print('Perimeter of polygon1: ' + str(polygon1.getPerimeter()))
print('Area of polygon2: ' + str(polygon2.getArea()))
print('Centre Distance : ' + str(polygon1.distanceToPolygon(polygon2)))


在如上的代码中,测试了缺省参数构造函数,含参构造函数,以及对应几个成员函数。运行并输出结果如下:

afa4556c1f7d4b3f9e099b2845e65727.png

通过手动计算,可以验证,各个方法以及类的实现以及输出结果完全正确。


二、自定义数据结构栈。栈是一种后进先出(Last-In-First-Out)的数据结构。编写类 Stack,实现入栈、出栈、判断栈是否为空,是否满栈、以及改变栈容量等操作。


Stack 类包括:


私有成员 content,为一个列表,代表栈里的数据;

私有成员 size,要求为整型,代表栈的容量;

私有成员 current,要求为整型,代表栈当前数据的个数;

方法 isempty,判断栈是否为空,返回 True/False;

方法 empty,置空栈;

方法 setSize,输入参数为新的栈的容量。注意新的栈容量可能小于原有的栈容量,统一将后进的元素删除;

方法 isFull,判断栈是否为满,返回 True/False;

方法 push,入栈,输入参数为新的元素;

方法 pop,出栈;

方法 show,打印当前栈的数据。

自行设计测试函数验证 Stack 类代码的正确性。


(1)大致思路:


对于栈,首先定义栈Stack类。初始化栈时只需初始化栈的大小即可,其他数据不需进行初始化赋值。各个方法具体实现如下:

①栈判空函数:只需比较当前栈中元素数是否为零即可

②栈清空函数:只需清空栈中用来存元素的列表并将栈当前元素个数变量设置为0

③定义栈改变大小函数:首先对输入进来的新大小进行判断,如果大小值小于等于零,即认为是非法输入,给出提示并返回,对于合法输入,修改栈大小后,如果栈的现有元素比栈大小大,则从栈中列表的头部依次删除元素直至栈中元素个数合法

④定义判栈满函数:只需比较栈中元素个数与栈大小是否相等即可

⑤定义压栈函数:首先进行栈满判断,如果栈满,则给出错误提示并返回。如果栈不满,则在列表中加入待压栈元素并将栈中现有元素数加一。

⑥定义弾栈函数:首先进行栈空判断,如果栈空,则给出错误提示并返回。如果栈不空,则进行依次弾栈直至大小合法

⑦定义栈的展示函数:输出当前栈中现有元素个数以及栈的大小。并输出栈中列表的每个元素。


(2)编程实现:

# 定义Stack类
class Stack:
    # 初始化构造函数,并声明各私有变量
    def __init__(self, size):
        self._content = []
        self._size = size
        self._current = 0
    # 定义栈判空函数
    def isEmpty(self):
        return self._current == 0
    # 定义栈清空函数
    def empty(self):
        self._content.clear()
        self._current = 0
    # 定义栈改变大小函数
    def setSize(self, newSize):
        # 对非法数据进行特判
        if newSize <= 0:
            print('Invalid size!')
            return
        # 合法数据正常进行处理
        self._size = newSize
        while self._size < self._current:
            self.pop()
    # 定义栈判满函数
    def isFull(self):
        return self._size == self._current
    # 定义压栈函数
    def push(self, item):
        # 判栈满  如果栈满则无法进栈
        if self.isFull():
            print('Failed! Cannot insert item into a full stack!')
            return
        else:
            self._current += 1
            self._content.append(item)
    # 定义弹栈函数
    def pop(self):
        # 判栈空  如果栈空则无法弹栈
        if self.isEmpty():
            print('Failed! Cannot pop item from an empty stack!')
            return
        else:
            self._current -= 1
            res = self._content[self._current]
            del self._content[self._current]
            return res
    # 定义栈的展示函数
    def show(self):
        print('Stack status:' + str(self._current) + '/' + str(self._size))
        print(self._content)

(3)运行并测试:


①测试压栈,判栈满函数以及展示函数:

将栈的大小设置为5,并压入7个数据,栈将自动压入前5个数据并在栈满时给出错误提示。


93e4a14688d54f9f90ef0dba482cc4df.png

可以看到前五次都顺利压入数据,后两次由于栈已满,无法压入数据并给出错误提示。


②测试压栈,判栈空函数以及展示函数:

在①的基础上进行7次弾栈,栈将自动弹出5个数据并在栈空时给出错误提示。

de7ec2f11f874ca284908ad03276aa3a.png

③测试栈改变大小函数及栈的展示函数:

首先初始化一大小为10的栈并压满数据后,将栈的大小调整至8,输出栈。

e65512320ec34afeb09ac640194ef6e8.png

可以看到,栈成功的调整了大小并丢弃了多余的元素。


④测试清空栈函数及栈的展示函数:

首先初始化一大小为10的栈并压满数据后,清空栈,输出栈。

074b33335b4a4ec89f767b39e9b868b7.png

可以看到,栈中元素成功清空。


三、时间类:设计一个名为 Time 的类。该类包含:


表示时间的私有成员 hour、minute 和 second。

构造 Time 对象的构造函数,使用当前时间 time.time()初始化小时、分钟和秒。

hour、minute 和 second 的 get 方法。

方法 setTime(elapseTime),设置经过了 elapseTime(以秒为单位)后的新时间。

(1)大致思路:

直接调用time.time()函数并直接访问格式化后的元组对各个变量进行赋值初始化即可。对于setTime()方法,首先将秒数加到秒上,分钟进位数则为秒数除以60并取整的值,小时数进位为分钟数除以60并取整的值。进位计算完毕后,分别对时分秒进行对24,60,60的取模运算即为最终结果。


(2)编程实现:


import time
# 定义Time类
class Time:
    # 初始化构造函数,并声明各私有变量
    def __init__(self):
        self._hour = time.localtime(time.time())[3]
        self._minute = time.localtime(time.time())[4]
        self._second = time.localtime(time.time())[4]
    # 重载str函数便于输出
    def __str__(self):
        return str(self._hour) + ':' + str(self._minute) + ':' + str(self._second) + '\n'
    # 定义获取小时函数
    def getHour(self):
        return self._hour
    # 定义获取分钟函数
    def getMinute(self):
        return self._minute
    # 定义获取秒函数
    def getSecond(self):
        return self._second
    # 定义设置秒数函数
    def setTime(self, elapseTime):
        # 首先计算秒数
        self._second += elapseTime
        # 获取分钟与小时数进位数进位
        self._minute += (int)(self._second / 60)
        self._hour += (int)(self._minute / 60)
        # 格式化分钟数和秒数
        self._second %= 60
        self._minute %= 60
        self._hour %= 24

首先调用time对时间进行获取并直接访问格式化后的元组对各个变量进行赋值初始化即可。

对于setTime()方法,首先将秒数加到秒上,分钟进位数则为秒数除以60并取整的值,小时数进位为分钟数除以60并取整的值。进位计算完毕后,分别对时分秒进行对24,60,60的取模运算即为最终结果。


(3)运行并测试:


运行代码计算10s后,100s后,1000s后,10000s后,100000s后的时间:

①10s后

6b8eef28ee2847d1b1ed45c1563fe2f6.png

②100s后

c30157794afe4b52b378ad0851accfe8.png

③1000s后

00052c674f874644874927b8841b9299.png

④10000s后

eaf3056e5d3b459b84be4516eba16b31.png

四、继承 1:补充代码 lab7_4.py,使得代码输出如下。注:不允许在类中添加新的方法。


if name ==' main ':
zhangsan = Person('Zhang San', 19, 'man') 
zhangsan.show()

#Name: Zhang San

#Age: 19

#Sex: man


lisi = Teacher('Li Xi',32, 'man', 'Math') 
lisi.show()
#Name: Li Xi


#Age: 32

#Sex: man

#Department: Math


lisi.setAge(40) 
lisi.setName("Li Si") 
lisi.show()


#Name: Li Si

#Age: 40

#Sex: man

#Department: Math


(1)大致思路:


对于第一个代码块,即使用构造方法对Person进行构造,并使用Show()方法进行输出。只需在代码中补全构造方法并按照输出补全Show()方法即可。

对于第二个代码块,只需补全继承的构造函数中对Department的初始化并按照输出补全Show()方法即可。

对于第三代码块,即使用set函数对类中的变量值进行了修改,因此只需补全set函数即可


(2)编程实现:

class Person(object):
    def __init__(self, name='', age=20, sex='man'):
        self._name = name
        self._age = age
        self._sex = sex
    def setName(self, name):
        self._name = name
    def setAge(self, age):
        self._age = age
    def setSex(self, sex):
        self._sex = sex
    def show(self):
        print('Name: ' + self._name)
        print('Age: ' + str(self._age))
        print('Sex: ' + self._sex)
class Teacher(Person):
    def __init__(self, name='', age=30, sex='man', department='Computer'):
        Person.__init__(self, name, age, sex)
        self.setDepartment(department)
    def setDepartment(self, department):
        self.department = department
    def show(self):
        Person.show(self)
        print('Department: ' + self.department)
if __name__ == '__main__':
    zhangsan = Person('Zhang San', 19, 'man')
    zhangsan.show()
    lisi = Teacher('Li Xi', 32, 'man', 'Math')
    lisi.show()
    lisi.setAge(40)
    lisi.setName("Li Si")
    lisi.show()

对于第一个代码块,即使用构造方法对Person进行构造,并使用Show()方法进行输出。只需在代码中补全构造方法并按照输出补全Show()方法即可。

对于第二个代码块,只需补全继承的构造函数中对Department的初始化并按照输出补全Show()方法即可。

对于第三代码块,即使用set函数对类中的变量值进行了修改,因此只需补全set函数即可


(3)运行并测试:


①代码块一:

4d63f55d711b4e79bc332f126c4f3405.png

②代码块二:

a2a9b5b146994adc8c42389ef927c248.png

③代码块三:

8c80a199a8f449ce89c8ffceafbf855a.png

五、继承 2:研究以下代码,思考代码的输出,并解释。

class China:
    def __init__(self, given, family):
        self.given = given
        self.family = family
    def __str__(self):
        return self.given + ' ' + self.family + '\n' + self.get_description()
    def get_description(self):
        return 'From China'
    def execute(self):
        print(self.family)
class Guangdong(China):
    def __init__(self):
        China.__init__(self, 'Ming', 'Li')
class England(China):
    def __init__(self):
        China.__init__(self, 'David', 'Beckham')
    def get_description(self):
        return 'From England'
def test_person(person):
    print(person)
ming = Guangdong()
ming.execute()
test_person(ming)
test_person(England())

(1)测试并输出:

2fa9ba08e58d427d99421605dd1dac02.png

(2)分析输出结果:


通过代码,可以看到Guangdong和England是继承于China的两个类。主函数中第一行通过构造函数创建Guangdong类,创建类时调用了构造函数并为对应参数分别赋值‘Ming’和‘Li’。函数第二行调用了execute()函数,因此输出了Guangdong类中参数family的内容:Li。

代码第三行使用test_person函数并使用ming作为参数。即调用__str__函数,输出他的名字,姓氏并换行后输出他的国籍。

代码第四行同理第三行输出他的名字,姓氏并换行后输出他的国籍。


实验结论:


通过本次实验,我学会了使用面向对象编程的方式进行编程。学会了使用类,初始化构造函数,方法以及继承完成代码的编写。与C++类似,Python中的面向对象编程也通过各个类进行实现。

此外在编程过程中,我也遇到了一些问题。例如第二题中,在栈进行弾栈与压栈时必须进行判空与判满,否则将造成错误。如果栈空时仍然进行弾栈,将造成栈中元素个数为负值并且将造成列表的下标报错。这些都告诉我们在编程过程中需要对一些特殊情况进行特判考虑。在本题中,重设栈大小时也需要对输入数据进行判断,非法数据将造成错误。


相关文章
|
1月前
|
Java C# Python
Python学习七:面向对象编程(中)
这篇文章是关于Python面向对象编程的中级教程,涵盖了析构函数、对象的三大特征(封装、继承、多态)、类属性与实例属性、以及类方法与静态方法的对比。
23 2
|
1月前
|
设计模式 安全 JavaScript
Python学习八:面向对象编程(下):异常、私有等
这篇文章详细介绍了Python面向对象编程中的私有属性、私有方法、异常处理及动态添加属性和方法等关键概念。
24 1
|
1月前
|
算法 数据可视化 Python
使用 Python 模拟蒙特卡洛实验
使用 Python 模拟蒙特卡洛实验
|
2月前
|
存储 Java 程序员
30天拿下Python之面向对象编程
30天拿下Python之面向对象编程
18 3
|
2月前
|
Java Python
全网最适合入门的面向对象编程教程:50 Python函数方法与接口-接口和抽象基类
【9月更文挑战第18天】在 Python 中,虽无明确的 `interface` 关键字,但可通过约定实现类似功能。接口主要规定了需实现的方法,不提供具体实现。抽象基类(ABC)则通过 `@abstractmethod` 装饰器定义抽象方法,子类必须实现这些方法。使用抽象基类可使继承结构更清晰、规范,并确保子类遵循指定的方法实现。然而,其使用应根据实际需求决定,避免过度设计导致代码复杂。
|
1月前
|
Java Python
Python学习六:面向对象编程(上)
这篇文章是关于Python面向对象编程的基础知识,包括类和对象的概念、实例方法、属性、self关键字以及魔法方法等。
16 0
|
2月前
|
Python
全网最适合入门的面向对象编程教程:Python函数方法与接口-函数与方法的区别和lamda匿名函数
【9月更文挑战第15天】在 Python 中,函数与方法有所区别:函数是独立的代码块,可通过函数名直接调用,不依赖特定类或对象;方法则是与类或对象关联的函数,通常在类内部定义并通过对象调用。Lambda 函数是一种简洁的匿名函数定义方式,常用于简单的操作或作为其他函数的参数。根据需求,可选择使用函数、方法或 lambda 函数来实现代码逻辑。
|
2月前
|
机器学习/深度学习 测试技术 数据处理
KAN专家混合模型在高性能时间序列预测中的应用:RMoK模型架构探析与Python代码实验
Kolmogorov-Arnold网络(KAN)作为一种多层感知器(MLP)的替代方案,为深度学习领域带来新可能。尽管初期测试显示KAN在时间序列预测中的表现不佳,近期提出的可逆KAN混合模型(RMoK)显著提升了其性能。RMoK结合了Wav-KAN、JacobiKAN和TaylorKAN等多种专家层,通过门控网络动态选择最适合的专家层,从而灵活应对各种时间序列模式。实验结果显示,RMoK在多个数据集上表现出色,尤其是在长期预测任务中。未来研究将进一步探索RMoK在不同领域的应用潜力及其与其他先进技术的结合。
97 4
|
3月前
|
Python
Python 中的面向对象编程 (OOP)
【8月更文挑战第29天】
35 7
|
3月前
|
机器学习/深度学习 PHP 开发者
探索PHP中的面向对象编程构建你的首个机器学习模型:以Python和scikit-learn为例
【8月更文挑战第30天】在PHP的世界中,面向对象编程(OOP)是一块基石,它让代码更加模块化、易于管理和维护。本文将深入探讨PHP中面向对象的魔法,从类和对象的定义开始,到继承、多态性、封装等核心概念,再到实战中如何应用这些理念来构建更健壮的应用。我们将通过示例代码,一起见证PHP中OOP的魔力,并理解其背后的设计哲学。
下一篇
无影云桌面