面对对象编程理解

本文深入探讨了面向对象编程的核心概念,包括类的定义与实例化、封装、继承和多态。通过实例展示了如何定义类、初始化实例、隐藏内部实现细节以及如何利用继承和多态实现代码的扩展性和灵活性。文章还强调了封装在保护数据完整性方面的重要性,并通过实际代码解释了如何实现单继承和多态效果。
摘要由CSDN通过智能技术生成

序言

参考的文章资源是http://www.coolpython.net/python_primary/oop/polymorphism.html
面向对象编程——Object Oriented Programming,简称OOP。与之相对应的另一种程序设计思想是面向过程编程。
OOP是从自然而来的,自然中,我们了解类和实例,比如爬行类、哺乳类、昆虫类等等。在哺乳类下面还有个灵长类。而我们人类属于灵长类。每一个人便是人类的一个实例。

面对对象的最核心的三个特征是:封装+继承+多态

类的定义与实例化

类的定义

因为python也是一种面对对象编程语言。所以也有类的概念。提供了面对对象的所有标准特性。比如允许一个类继承多个基类。 子类可以覆盖父类的方法等等。

使用class来定义一个类

class Stu:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def run(self):
        print("{name} is running".format(name=self.name))

理解:
(1)上面的Stu 是类的名字。你可以使用__name__ 来访问

print(Stu.__name__)
输出:
Stu

(2)在类里面,用def 关键词 来定义函数。但在类中 我们管这种函数为方法。称为实例方法。
(3)__init__是初始化函数。当实例被构造出来以后,使用__init__方法来初始化实例属性。self是实例, name 和 age都是实例的属性。 再看看为什么self是 实例。

s = Stu('小明', 18)
s.run()
输出:<class '__main__.Stu'>
小明 is running

这里我们看到s便是创建出来的实例。也就是之前所设置的self。
由于在初始化函数的时候,有name和age这两个属性。因为我们在创建实例的时候,必须输入这两个参数,在这里是’小明’, 18。
而s.run() 这行代码是在调用实例的run方法。
总结来说,我们上面创立了 实例的两个属性 name和age;也定义了实例的run方法。
所以说实例有相对应的方法和属性。

(4)对对象的属性进行修改

class Stu:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def info(self):
        print("{name}今年{age}岁".format(name=self.name, age=self.age))

    def run(self):
        print("{name} is running".format(name=self.name))

    def print(self):
        print("ok")

s = Stu("小刚", 18)
s.info()

print(s.name)
s.age = 20
s.info()

输出:
小刚今年18岁
小刚
小刚今年20

(5)使用类来组合数据和方法
使用一个例子说明:
一个名为 成绩单 的文件中保存了学生的考试成绩,内容如下

姓名  语文  数学  英语
小红  90   95    90
小刚  91   94    93

编写程序读取该文件,使用合适的数据类型保存这些数据,输出每一个人的各个科目和分数,并计算每个学生的总的分数。

如果是面对对象的编程,则这样子写:

stus = []
with open('成绩单', 'r', encoding='utf-8') as file:
    lines = file.readlines()
    for i in range(1, len(lines)):
        line = lines[i]
        arrs = line.split()
        stus.append(arrs)
for stu in stus:
    msg = "{name}的各科成绩如下: 语文:{yw_score}, " \
          "数学:{sx_score}, 英语:{en_score}".format(name=stu[0],
                                                yw_score=stu[1],
                                                sx_score=stu[2],
                                                en_score = stu[3]
                                                )
    print(msg)
    msg = "{name}的总成绩是{socre}".format(name=stu[0],
                                      socre=int(stu[1])+int(stu[2])+int(stu[3]))

    print(msg)

但如果用面对对象的编程,则写成:

class Stu:
    def __init__(self, name, yw, sx, en):
        self.name = name
        self.yw = yw
        self.sx = sx
        self.en = en

    def score_sum(self):
        return self.yw + self.sx + self.en

    def print_score(self):
        msg = "{name}的各科成绩如下: 语文:{yw_score}, " \
          "数学:{sx_score}, 英语:{en_score}".format(name=self.name,
                                                yw_score = self.yw,
                                                sx_score = self.sx,
                                                en_score = self.en
                                                )
        print(msg)
        msg = "{name}的总成绩是{score}".format(name=self.name, score=self.score_sum())
        print(msg)

stus = []
with open('成绩单', 'r', encoding='utf-8') as file:
    lines = file.readlines()
    for i in range(1, len(lines)):
        line = lines[i]
        arrs = line.split()
        s = Stu(arrs[0], int(arrs[1]), int(arrs[2]), int(arrs[3]))
        stus.append(s)
for stu in stus:
    stu.print_score()

从代码的可阅读性上看,使用类组织数据和方法显然更具有优势,而且,类这种概念,更加符合我们人类的思维。
使用类组织数据和方法,扩展性更好,可以随时添加新的属性和方法,比如,我想输出学生最高的科目分数,那么,我只需要修改类就可以了。
而面对过程的编程则需要大量的修改,可维护性很差。

类的封装

隐藏实现的细节,只对外公开我们想让他们使用的属性和方法,这就叫做封装。
封装的目的在于保护类内部数据结构的完整性, 因为使用类的用户无法直接看到类中的数据结构,只能使用类允许公开的数据,很好地避免了外部对内部数据的影响,提高了程序的可维护性。

(1)私有属性和方法

假设,你和你的同事一起做项目,现在,需要你写一个类让同事使用,这个类,你定义了5个属性,10个方法,但是呢,你的同事其实只会用到其中一个方法,剩下那9个,都是用到的那个方法在执行过程中调用的方法。

那么问题来了,你明确告诉他,你就调用那个A方法就好了,其他方法,你不要使用,不然,可能会影响结果。如果你的同事是个很安分守己的人,他听从了你的建议,老老实实的调用A方法,其他方法,他一概不动,这样就是安全的。

可是过了几天,来了新同事,他偏偏不听话,非得调用剩余的9个方法,它觉得,自己调用那9个方法,可以更好的实现功能,结果呢,出了大问题了,那9个方法,他用的不好,导致程序出错了。

我们写了一个类,有些属性,有些方法,我们不希望被其他人使用,因为那样很容易就产生错误,那么这时,我们就需隐藏实现的细节,只对外公开我们想让他们使用的属性和方法,这就叫做封装。就好比把一些东西用一个盒子封装起来,只留一个口,内部让你看不见

如何才能做到这一点呢?

在python里,如果属性和方法前面是双下划线,那么这个属性和方法就变成了私有的属性。下面是一个例子。

class Animal:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    def __run(self):
        print("run")

a = Animal('猫', 2)
a.__run()
print(a.__name, a.__age)

这样就会发生错误,你没法使用 run的这个方法和name、age这两个属性。
还有一个问题是 如果设置年龄是10000岁呢,这就显然不对。所以在类中也设置这样的方法,避免这种情况。

class Animal:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    def set_age(self, age):
        if age > 100 or age < 1:
            raise Exception("年龄范围错误")
        self.__age = age

    def get_age(self):
        return self.__age

    def __run(self):
        print("run")

a = Animal('猫', 2)
a.set_age(3)
print(a.get_age())

继承

继承是一种创建新类的方式,python中的继承,可以继承一个或者继承多个父类,新建的类被称之为派生类或者子类,被继承的类是父类。

(1)单继承

class Car(object):
	def __init__(self, speed,brand):
		self.speed = speed
		self.brand = brand
	def run(self):
		print("{brand}在行驶".format(brand = self.brand))
# 燃油车
class Gasolinecar(Car):
	def __init__(self,speed,brand,price):
		super().__init__(speed,brand)
		self.price = price

class Audi(Gasolinecar):
	pass

honda = Gasolinecar(130,'本田', 13000)
honda.run()

audi_car = Audi(100,'奥迪',10000)
audi_car.run()

输出:
本田在行驶
奥迪在行驶

继承是指 子类即将拥有父类的方法和属性。同时新增子类的属性和方法。
Gasolinecar类里,我没有写run方法,但是Gasolinecar的父类定义了run方法,因此,Gasolinecar也有这个方法,因此这个类的对象honda可以使用run方法。

Audi类没有定义任何方法,但是它继承了Gasolinecar,因此,Gasolinecar有的属性和方法,它都拥有,这里就包括了__init__方法。

super()可以用来调用父类的方法,Gasolinecar多传了一个price属性,其父类的__init__方法里有两个参数,因此,可以先调用父类的__init__方法初始化speed, brand,然后在初始化price。

多态

(1)重写
多态这个概念依赖于继承,因为继承,使得子类拥有了父类的方法,这里就产生了一个问题,如果子类有一个方法和父类的方法同名,那么子类在调用这个方法时,究竟是调用子类自己的方法,还是父类的方法?

class Base():
    def print(self):
        print("base")


class A(Base):
    def print(self):
        print("A")


a = A()
a.print()
输出:
A

父类和子类都有print方法,那么子类A的对象a调用print方法时,调用的是谁的print方法呢?

答案是子类的print方法,如果A类没有定义print方法,那么a.print()调用的是父类的print方法,但是A类定义了print方法,这种情况称之为重写,A类重写了父类的print方法

(2)多态的表现形式

class Animal:
    def run(self):
        raise NotImplementedError

class People(Animal):
    def run(self):
        print("人在行走")


class Pig(Animal):
    def run(self):
        print("猪在跑")


p1 = People()
p1.run()

p2 = Pig()
p2.run()

输出:
人在行走
猪在跑

People和 Pig 都继承了Animal,都是动物,是同一类事物,他们都有run方法,但是最终的运行结果却不一样,这就是多态,同一类事物有多种形态

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值