Python 面向对象编程

2021-02-14 09:19

阅读:384

标签:src   灵活   UNC   是什么   简单   程序   行操作   模块   sorted   

目录
  • 面向对象程序设计
    • 结构化程序设计的缺点
    • 面向对象程序设计
      • 实例:Dog 类
  • Python 面向对象编程
  • 对象与方法
    • 引用方法
  • 类的定义与调用
    • class
    • 定义类
      • 初始化类
        • init()
        • self
    • 调用类
    • 实例:Force 类
  • Special method
    • 特殊方法
    • 构造与解构
    • 实例 1 :Force 类
    • 实例 2 :Student 类
      • 列表排序。
        • sort()
        • sorted()
      • it 方法
      • 自定义对象的排序
  • inheritance
    • 类的继承
    • 方法重写
    • 实例:Car 类和 ElentricCar 类
  • 参考资料

面向对象程序设计

结构化程序设计的缺点

我们为什么要有面向对象程序设计呢?我们使用 C 语言只能实现结构化程序设计,所谓结构化程序设计就是“程序 = 数据结构 + 算法”,而在程序中会有很多可以相互调用的函数和全局变量。
技术图片
但是我们可以显然地看出,这种编程风格存在不少缺点。首先由于函数之间可以相互调用,任何函数都可以修改全局变量,这就导致了函数、数据结构之间的关系一段乱麻,尤其是当代码量很长的时候,代码的理解也变得极其困难。

  • 这个函数是用来操作哪个还是哪些数据数据结构?
  • 这个数据结构可以被哪些函数操作,代表什么含义?
  • 不同的函数能够相互调用吗?关系是什么?

对于变量来说,有的变量可能是只能被一些函数修改,而不能被某些函数操作,但是由于你不能给变量“上锁”,因此这个变量会很轻松地被修改。当然你可以说可以搞成常量,那我如果要修改呢?搞成常引用?算了吧,这样变量间的关系就跟复杂了。而且,某个数据结构会被多个函数调用,而如果出现了错误,是哪个函数出错了呢?是函数一、函数二、函数 N,还是都有错?除了调试好像还真没啥好办法。
作为一个懒人,如果我的一个程序的某个功能我曾经写过,那么我就很喜欢去把以前的代码搞来用。可是往往这会是一件困难的事情,因为这段代码的源程序的变量和函数间本身就有复杂的逻辑关系,接口可能完全不一样,最后你发现还不如重写一遍。
说了这么多,总之结构化程序设计就是有很多缺点啦!
技术图片

面向对象程序设计

我们喜欢的程序是,代码的思路清晰、健壮性好利于维护和添加功能、移植性强,这个时候就要请出面向对象程序设计啦。

面向对象程序设计(Object Oriented Programming)作为一种新方法,其本质是以建立模型体现出来的抽象思维过程和面向对象的方法。模型是用来反映现实世界中事物特征的。任何一个模型都不可能反映客观事物的一切具体特征,只能对事物特征和变化规律的一种抽象,且在它所涉及的范围内更普遍、更集中、更深刻地描述客体的特征。通过建立模型而达到的抽象是人们对客体认识的深化。——百度百科

简单地说,面向对象程序设计就是把某个客观事物的共同特点归纳出来,形成一个数据结构对象既表示客观世界问题空间中的某个具体事物,有表示软件系统解空间中的基本元素。
对象 = 属性 + 方法”,对象以 id 为标识,既包含属性(数据),也包含方法(代码),是某一类具体事物的特殊实例。我们怎么来理解呢?

实例:Dog 类

技术图片
狗狗是我们的好朋友啦,那么对于一只狗它会有什么行为呢?它应该会叫、会坐、会跑,那么我们就来用 python 封装一个 Dog 类。直接扔一段代码:

class Dog():
    def __init__(self,name,breed):
        #初始化一个 Dog 对象,属性有 name 和 breed
        self.name = name
        self.breed = breed

    def sit(self):
        #狗狗蹲下
        print(self.name.title() + " is now sitting.")

    def roll_over(self):
        #狗狗打滚
        print(self.name.title() + " rolled over!")

然后拿去交互式解释器运行下,创建一个 Dog 对象,查看它的属性,并指挥它蹲下和打滚。
技术图片

Python 面向对象编程

Python是完全面向对象的语言。函数、模块、数字、字符串都是对象。并且完全支持继承、重载、派生、多继承,有益于增强源代码的复用性。Python支持重载运算符和动态类型。相对于Lisp这种传统的函数式编程语言,Python对函数式设计只提供了有限的支持。有两个标准库(functools, itertools)提供了Haskell和Standard ML中久经考验的函数式程序设计工具。——百度百科

技术图片
python 绝对是个面向对象的编程语言啦,因为 python 中从数值类型到代码模块都是以对象的形式存在的,我们来举 3 个例子,打开交互式解释器。
对于 int 类型,我们查看 “1” 的 id、type、和 dir(可操作性 int 的方法):
技术图片
接下来是字符类型,查看 “a” 的 id、type、和 dir:
技术图片
接下来我们看个不一样的,在函数不被调用时,就可以认为是一个对象,也会有一些方法可以操作函数,例如查看 “abs()” 函数的 id、type、和 dir:
技术图片

对象与方法

所谓“对象”,它实现了属性和方法的封装,这是一种数据抽象的机制,这种方式提高了程序的重用性、灵活性、扩展性。
我们需要怎么创建一个对象呢?例如上文的 Dog 类,那么创建一个 Dog 对象的代码为:

a_dog = Dog("bilibili·狗·德川家康·薛定谔·保留","Husky")

应该不难理解,首先需要制定是什么类,然后传入需要的属性进去,例如 Dog 类需要 2 个属性。

引用方法

类中的函数被称为方法,引用的代码格式为:

.

例如我们要让一个 Dog 对象完成 sit 动作,其代码为:

a_dog.sit()
  • Python 是一门动态的编程语言,因此对象可以随时增加或删除属性或方法

类的定义与调用

class

要创建一个对象,这个对象的类已经被定义时必要条件,所谓“类(class)” 就是用来描述相同的属性和方法的集合,定义了该集合中每个对象共有的属性和方法,而对象则是类的实例。需要注意的是,对于同一个类,类的对象将会具有相同的属性和方法,但是属性的数据和 id 是不同的
和函数或者 C 语言的结构体有类似之处,类是一系列代码的封装,在 Python 中我们约定俗成,类名需要以大写字母为开头,函数则以小写字母开头,方便我们进行区分。

定义类

定义类我们需要使用 class 语句:

class 
    

初始化类

直接看代码:

class
    def __init__(self,):
    def 方法名(self,):

init()

"init" 是一个特殊的方法,每当你需要根据类创建对象时,Python 会自动运行并对对象进行初始化,第一个参数必须是 self。

self

对于一个类,所有的方法中第一个参数一般都是 self,在类的内部,实例化时传入的参数都会直接赋给这个变量。

调用类

当我们调用一个类时,就会创建一个对象,代码:

obj = ()

实例:Force 类

为了方便理解,我们来写一个 “Force” 类。力是矢量,假设现在讨论的力都是二维空间中的力,那么这个力就需要用 x 和 y 两个分量来描述,同时我们还想实现力的合成操作。
技术图片
类的封装如下:

class Force:
    def __init__(self,x,y):
        # x 和 y 为力在两个坐标轴的分量
        self.fx,self.fy = x,y

    def show(self):
        #展示力的信息
        print("Force"%(self.fx,self.fy))

    def add(self,force2):
        #力的合成操作
        x = self.fx + force2.fx
        y = self.fy + force2.fy
        return Force(x,y)

让我们来创建几个对象试试,打开交互式解释器:
技术图片

Special method

特殊方法

特殊方法,也可以称之为魔术方法(Magic merhod),这是类的定义中已经实现了的方法,使用这些方法我们可以轻松地调用 python 的内置操作。所有特殊方法的名称都是以两个下划线“__”开始和结束
这里罗列一些常用的特殊方法:

特殊方法 操作
init 构造函数,在生成对象时调用
del 析构函数,释放对象时使用
repr 打印,转换
setitem 按照索引赋值
getitem 按照索引获取值
len 获得长度
cmp 比较运算
call 函数调用
add 加运算
sub 减运算
mul 乘运算
truediv 除运算
mod 求余运算
pow 乘方

构造与解构

这里需要强调一下“init”方法和“del”,前者是对象的构造器,用于实例化对象时被自动调用,后者是析构器,用于销毁对象。
这里还是用 Dog 类来理解一下这两个方法的作用:

class Dog():
    def __init__(self,name,breed):
        #初始化一个 Dog 对象,属性有 name 和 breed
        self.name = name
        self.breed = breed

    def __del__(self):
        #调用这个方法时,对象会被销毁
        del self

实例 1 :Force 类

这次我们使用特殊方法来实现 Force 类:

class Force:
    def __init__(self,x,y):
        # x 和 y 为力在两个坐标轴的分量
        self.fx,self.fy = x,y

    def __add__(self,force2):
    #力的合成操作
        x = self.fx + force2.fx
        y = self.fy + force2.fy
        return Force(x,y)

    def __str__(self):
        #展示力的信息
        return "Force"%(self.fx,self.fy)

    def __mul__(self,n):
        #力扩大 n 倍
        x,y = self.fx * n,self.fy * n
        return Force(x,y)

    def __eq__(self,force2):
        #判读力是否相等
        return (self.fx == force2.fx) and (self.fy == force2.fy)

测试一下看看,启动交互式解释器:
技术图片
与上文不同的是,现在我们的 Force 类可以使用诸如 “+”和 “ == ” 运算符来实现一些操作了。这是因为 “add” 方法能够让我们可以使用 “+” 运算符来操作 Force 对象, “str” 方法能够让我们可以将 Force 对象的一些信息转换为字符串, “mul” 方法能够让我们可以使用 “*” 运算符来操作 Force 对象, “eq” 方法能够让我们可以使用 “ == ” 运算符来对 Force 对象进行相等的判断。

实例 2 :Student 类

列表排序。

sort()

使用 sort() 方法,该方法用于对原列表进行排序,没有返回值,如果指定参数,则使用比较函数指定的比较函数,语法为:

list.sort( key = None, reverse = False)
参数 说明
list 需要操作的列表
key 进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序
reverse 排序规则,reverse = True 降序, reverse = False 升序(默认)

sorted()

使用 sorted() 函数,该函数可对所有可迭代的对象进行排序操作,返回值为重新排序的列表,该函数不影响列表元素在列表中的原始排列顺序,语法为:

sorted(iterable, cmp=None, key=None, reverse=False)
参数 说明
iterable 可迭代对象
cmp 比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0
key 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序
reverse 排序规则,reverse = True 降序 , reverse = False 升序(默认)
  • sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。list 的 sort 方法返回的是对已经存在的列表进行操作,无返回值,而内建函数 sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作。
  • sort 与 sorted 内部是用Timsort算法实现的,Timsort是结合了合并排序(merge sort)和插入排序(insertion sort)而得出的排序算法,它在现实中有很好的效率。Tim Peters在2002年设计了该算法并在Python中使用(TimSort 是 Python 中 list.sort 的默认实现)。

it 方法

Python 是一门拓展性很强的语言,对于每个类来说,都可以定义特殊方法。定义 “it” 方法之后,任意的自定义类都可以进行比较,例如对于 Int 类型就进行数值的比较,string 类型就按照字典序来比较。定义的格式为:

def __init__(self,y)

若方法返回 true,则视为对象比 y 要小,排序的时候就要排在前面,反之排在后面。

自定义对象的排序

现在我们就给出 Student 类的代码,我们需要实现 sort() 方法对 Student 类列表的排序。

class Student:
    def __init__(self,name,grade):
        self.name = name
        self.grade = grade

    def __lt__(self,other):
        #按照成绩由大到小排序
        return self.grade > other.grade

    def __str__(self):
        return "(%s,%d)" % (self.name,self.grade)

    __repr__ = __str__

测试一下,打开交互式解释器:
技术图片

inheritance

类的继承

编写一个类时,不一定需要从头开始,如果你现在想要实现的类中有的部分已经在另一个现有的类实现了,你可以将现成的类继承过来。当一个类继承另一个类时,将自动获得另一个类的所有属性和方法。被继承的类称为父类,新类被称为子类,同时子类还可以定义自己的属性和方法。利用继承衍生出来的新类可以添加或修改一些新的功能。

方法重写

如果从父类继承的方法不满足子类的需求,可以对其进行重写。

实例:Car 类和 ElentricCar 类

首先我们先写一个 Car 类,这个类可以显示一些汽车的基本信息,并且可以查询里程数。

class Car:
    def __init__(self,make,model,year):
        #初始化车的属性
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0    #里程数,初始化为 0

    def get_descriptive_name(self):
        #打印车的相关信息
        print(str(self.year) + ‘ ‘ + self.make + ‘ ‘ + self.model)

    def read_odometer(self):
        #打印里程信息
        print("This car has " + str(self.odometer_reading) + " miles on it.")

    def updata_odometer(self,mileage):
        #设置里程数,并禁止回调
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can‘t roll back an odometer!")

测试一下,打开交互式解析器。
技术图片
很成功,接下来我们写一个 ElentricCar 类,由于 ElentricCar 和 Car 有很多相似之处,因此可以继承。同时 ElentricCar 具有一些 Car 不具有的特性,例如我要加一个电池电量,要多描述一些信息,这时就可以进行方法重写。

class Car:
    def __init__(self,make,model,year):
        #初始化车的属性
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0    #里程数,初始化为 0

    def get_descriptive_name(self):
        #打印车的相关信息
        print(str(self.year) + ‘ ‘ + self.make + ‘ ‘ + self.model)

    def read_odometer(self):
        #打印里程信息
        print("This car has " + str(self.odometer_reading) + " miles on it.")

    def updata_odometer(self,mileage):
        #设置里程数,并禁止回调
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can‘t roll back an odometer!")

class ElentricCar(Car):
    #继承 Car 类
    def __init__(self,make,model,year):
        #初始化电瓶车的属性
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0    #里程数,初始化为 0
        self.battery_size = 100    #电池电量初始化为 100

    def describe_battery(self):
        #打印电量
        print("This car has a " + str(self.battery_size) + "-KWH battery.")

测试一下,打开交互式解析器。
技术图片
我们可以看到,ElentricCar 类不仅继承了 Car 类的全套代码,而且还能够拥有自己的一些特性!

参考资料

Python 百度百科
《新标准 C++ 程序设计》郭炜 编著,高等教育出版社
《Python语言基础与应用》 陈斌
《Python编程从入门到实践》————[美]Eric Matthes 著,袁国忠 译,人民邮电出版社
菜鸟教程

Python 面向对象编程

标签:src   灵活   UNC   是什么   简单   程序   行操作   模块   sorted   

原文地址:https://www.cnblogs.com/linfangnan/p/12720191.html


评论


亲,登录后才可以留言!