(数据结构python版)第2章面向对象编程

本文介绍了Python中的面向对象编程,包括目标、原则和设计模式,软件开发的各个阶段,类的定义、继承、命名空间和面向对象的概念。讨论了类定义中的CreditCard和多维向量类例子,以及迭代器和Range类的实现。此外,还涵盖了深拷贝和浅拷贝的区别。
摘要由CSDN通过智能技术生成

面向对象编程

目标,原则和模式

面向对象中的主体为对象

每个对象都是类的实例

详细定义了 对象包含的实例变量(又称数据成员),还规定了对象可以执行的方法(又称成员函数)

目标

目标:健壮性适应性可重用性

健壮性:将错误修正的能力

适应性:能随着时间不断优化(可进化性)

可重用性:可重用,应该谨慎使用

原则

首要原则:

  • 模块化
  • 抽象化:从一个复杂的系统中提炼最基础的部分
  • 封装:软件系统的不同组件不应显示其各自的实现的内部细节
设计模式

描述“典型”软件设计问题的解决方案。

一种可以应用于不同情况的解决方案,提供了通用模版的模式

模式,包括

  • 一个名称(它表示了该模式)
  • 一个语境(它描述应该该模式的情况)
  • 一个模版(它描述如何应用该模式)
  • 一个结果(它描述和分析该模式会产生什么结果)

软件开发

主要阶段:

  1. 设计
  2. 实现
  3. 测试和调试
设计

经验规则:

  • 责任:把这些工作分为不同的角色,有各自不同的责任。试着用行为动词描述责任。这些角色将形成程序的类
  • 独立:在尽可能独立于其他类的前提下规定每个类的工作。细分各个类的责任
  • 行为:仔细且精细地为每个类定义行为,与其他类交互时,可以更好的理解这个类执行动作的结果

CRC卡,UML图

伪代码

通过一种专门为人准备的方法来描述算法

用于描述隐藏在数据结构和算法实现之后的主要编程思想

编码风格和文档

主要原则:

  • 通常缩进4个空格
  • 标识符命名要有意义
    • 类:首字母大写
    • 函数:包括类的成员函数,小写
    • 标识某个对象,小写
    • 常量:全部大写
  • 添加合适的注释

文档

docstring的机制在源码中直接插入文档提供完整的支持

主体中的第一个语句字符串都认为是docstring,限定在三引号(""")中

docstring作为模块,功能或类的声明的一个域进行存储。可以当做文档用,可用多种方式检索

测试和调试

测试

单元测试自动化,unittest模块

使用回归测试,通过对所有先前测试的重新执行来确保对软件的更改不会引入新的错误

调试

打印语句:最简单

调试器:更好

pdb模块,提供调试支持

类定义

类是面向对象程序设计中抽象的主要方法。

例子:CreditCard类

self标识符

构造函数

__init__方法就是类的构造函数

封装

数据成员前加下划线,比如_balance,表示非公有的

附加方法

错误检查

测试类

将测试封装在if __name__ == '__main__':

运算符重载和python的特殊方法

操作重载

常见的语法特别方法的形式
a+ba.__add__(b)b.__radd__(a)
a-ba.__sub__(b)b.__rsub__(b)
a*ba.__mul__(b)b.__rmul__(a)
a/ba.__truediv__(b)b.__rtruediv__(a)
a//ba.__floordiv__(b)b.__rfloordiv__(a)
a%ba.__mod__(b)b.__rmod__(a)
a**ba.__pow__(b)b.__rpow__(a)
a<<ba.__lshift__(b)b.__rlshift__(a)
a>>ba.__rshift__(b)b.__rrlshift__(a)
a&ba.__and__(b)b.__rand__(a)
a^ba.__xor__(b)b.__rxor__(a)
a|ba.__or__(b)b.__ror__(a)
a+=b
a-=b
a.__iadd__(b)
a.__isub__(b)
+aa.__pos__(b)
-aa.__neg__(b)
~aa.__invert__(b)
abs(a)a.__abs__(b)
a<ba.__lt__(b)
a<=ba.__le__(b)
a>ba.__gt__(b)
a>=ba.__ge__(b)
a==ba.__eq__(b)
a!=ba.__ne__(b)
vin aa.__contains__(v)
a[k]a.__getitem__(k)
a[k]=va.__setitem__(k,v)
del a[k]a.__delitem__(k)
a(arg1,arg2,...)a.__call__(arg1,arg2,...)
len(a)a.__len__()
hash(a)a.__hash__()
iter(a)a.__iter__()
next(a)a.__next__()
bool(a)a.__bool__()
float(a)a.__float__()
int(a)a.__int__()
repr(a)a.__repr__()
reversed(a)a.__reversed__()
str(a)a.__str__()

非运算符重载

iter()对应__iter__

隐式的方法

提供默认功能

例子:多维向量类
迭代器

支持__next__()的特殊方法,如果有下一个元素,返回该元素,否则产生一个StopIteration异常,表示没有下一个元素

例子:Range类
class Range():
    def __init__(self,start,stop=None,step):
        if step==0:
            raise ValueError("step cannot be 0")
        if stop is None:
            start,stop=0,start
        self._length=max(0,(stop-start+step-1)//step)
        self._start=start
        self._step=step
    def __len__(self):
        return self._length
    def __getitem__(self,k):
        if k<0:
            k+=len(self)
        if not 0<=k<self._length:
            raise IndexError('index out of range')
        return self._start+k*self._step

继承

在一个分层的方式中,水平层次上类似的抽象定义组合在一起,使下层的组件更加具体,上层的组件更加通用

模块化和层次化就是继承

python的异常层次结构

数列的层次图

一个通用数字数列类:

class Progression:
    def __init__(self,start=0):
        self._current=start
    def _advance(self):
        self._current+=1
    def __next__(self):
        if self._current is None:
            raise StopIteration()
        else:
            answer=self._current
            self._advance()
            return answer
    def __iter__(self):
        return self
    def print_progression(self,n):
        print(" ".join(str(next(self)) for j in range(n)))

if __name__ == '__main__':
    p=Progression()
    p.print_progression(10)
# 0 1 2 3 4 5 6 7 8 9

一个等差数列类:

from 一个通用数字数列类 import Progression
class ArithmeticProgression(Progression):
    def __init__(self,increment=1,start=0):
        super().__init__(start)
        self._increment=increment
    def _advance(self):
        self._current+=self._increment

if __name__ == '__main__':
    xxx=ArithmeticProgression(2,0)
    xxx.print_progression(20)
# 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38

一个等比数列类:

from 一个通用数字数列类 import Progression
class GeomertricProgression(Progression):
    def __init__(self,base=2,start=1):
        super().__init__(start)
        self._base=base
    def _advance(self):
        self._current*=self._base

if __name__ == '__main__':
    xxx=GeomertricProgression()
    xxx.print_progression(10)
# 1 2 4 8 16 32 64 128 256 512

一个斐波那契数列类:

from 一个通用数字数列类 import Progression
class FibonacciProgression(Progression):
    def __init__(self,first=0,second=1):
        super().__init__(first)
        self._prev=second-first
    def _advance(self):
        self._prev,self._current=self._current,self._prev+self._current

if __name__ == '__main__':
    xxx=FibonacciProgression(2,3)
    xxx.print_progression(10)
# 2 3 5 8 13 21 34 55 89 144
抽象基类

设计一个基类:避免重复代码

命名空间和面向对象

命名空间是一个抽象名词,它管理着特定范围内定义的所有标识符,将每个名称映射到相应的值

实例和类命名空间

每个已定义的类都有一个单独的类命名空间。用于管理一个类中所有实例所共享的成员或没有引用任何特定实例的成员

条目是怎样在命名空间中建立的

成员函数是最典型的在类命名空间居中声明的条目类型

类数据成员

有一些值(常量),被一个类的所有实例共享时,就会存储在父类的命名空间中

嵌套类

class A:
	class B:
		...

B类为嵌套类

优点:

  1. 表明嵌套类的存在需要外部类的支持,有助于潜在的命名冲突(可以在各自的容器类中嵌套各自的节点定义来避免歧义)
  2. 允许更高级的形式继承,使外部类的子类重载嵌套类的定义

字典和__slots__声明

默认情况下,每个命名空间像一个dict类的实例,虽然字典结构支持相对有效的名称查找,但是需要的额外内存使用量超出了他存储原始数据的内存

python,使用流表示一个类的所有实例,类定义必须提供一个名为__slots__的类级别的成员分配给一个固定的字符串序列,来服务于变量

可以使用__slots__来简化类的声明,但并不会这么做,因为将使用python程序非典型

名称解析和动态调度

名称解析的过程:

  1. 实例命名空间中查找
  2. 实例所属的类命名空间中搜索
  3. 通过继承层次结构向上,检查每一个父类的类命名空间
  4. 没找到,引发一个AttributeError异常

深拷贝和浅拷贝

浅拷贝:简单赋值

深拷贝:

palette=copy.deepcopy(warmtones)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值