北理工嵩天Python面向对象程序设计笔记



前言

1.北理工 嵩天/黄天宇/礼欣 Python面向程序设计
2.面向有编程基础、支撑就业需求的python语言入门到精通系列课程
3.正确理解python面向对象编程理念与方法
4.掌握python面向对象程序设计的具体方法
5.能独立完成带有面向对象风格的python程序编写
6.实践、实践、再实践
7.本课程分两周


提示:以下是本篇文章正文内容,下面案例可供参考

一、任务分析

在这里插入图片描述

第一周:python面向对象基础
第二周:python面向对象进阶

二、第一周

2.1.面向对象编程模式

课程之前:

  • 掌握python基础语法,能够开展过程式编程
  • 已经编写过20-30个python小程序
  • 熟练使用IDLE或pycharm开发工具
  • 完整学习过"python基础语法精讲"课程

单元开篇:

1. 万物皆对象
2. 面向对象编程思想
3. 面向对象的三个特征
4. Python面向对象术语概述
5. Python面向对象实例入门

万物皆对象
对象:独立的存在或作为目标的事物

  • 独立性:对象都存在清晰的边界,重点在于划分边界
  • 功能性:对象都能表现出一些功能、操作或行为
  • 交互性:对象之间存在交互,如:运算和继承

python语言的“万物皆对象”

  • python语言中所有数据类型都是对象、函数是对象、模块是对象
  • python所有类都继承于最基础类object
  • python语言中数据类型的操作功能都是类方法的体现

OOP:objec-oriente programmi

  • OOP:面向对象编程,一种编程思想,重点在于高抽象的复用代码
  • OOP把对象当作程序的基本单元,对象包含数据和操作数据的函数
  • OOP本质是把问题解决抽象作为以对象为中心的计算机程序
  • OOP在较大规模或复杂项目中十分有用,OOP可以提高写作产量
  • OOP最主要价值在于代码复用
  • OOP只是一种编程方式,并非解决问题的高级方法

面向过程VS.面向对象

  • 面向过程:以解决问题的过程步骤为核心编写程序的方式
  • 面向对象:以问题对象构建和应用为核心编程程序的方式
  • 所有OOP能解决的问题,面向过程都能解决

面向对象编程概念实列

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
OOP三个重要特征

  • 封装:属性和方法的抽象,用 数据和操作数据的方法来形成对象逻辑
  • 继承:代码复用的高级抽象,用对象之间的继承关系来形成代码复用
  • 多态:方法灵活行的抽象,让对象的操作更加灵活、更多复用代码

封装Encapsulation:属性和方法的抽象

  • 属性的抽象:对类的属性(变量)进行定义、隔离及保护
  • 方法的抽象:对类的方法(函数)进行定义、隔离及保护
  • 目标是形成一个类对外可操作属性和方法的接口

继承Inheritance:代码复用的高级抽象

  • 继承是面向对象程序设计的精髓之一
  • 实现了以类为单位的高抽象级别代码复用
  • 继承是新定义类能够几乎完全使用原有类与方法的过程

多态Polymorphism:仅针对方法,方法灵活性的抽象

  • 参数类型的多态:一个方法能够处理多个类型的能力
  • 参数形式的多态:一个方法能够接受多个参数的能力
  • 多态是OOP的一个传统概念,pytho天然支持多态,不需要特殊语法

类class和对象object

  • 类:逻辑抽象和产生对象的模板,一组变量和函数的特定编排
  • 对象:具体表达数据及操作的实体,相当于程序中的”变量“
  • 实例化:从类到对象的过程,所有”对象“都源于某个”类“

面向对象术语概述

  • 对象:类对象、实例对象
  • 属性:存储数据的”变量“,包括:类属性、实例属性
  • 方法:操作数据的“函数”
    包括:类方法、实例方法、自由方法、静态方法、保留方法

类对象VS.实例对象

  • 类对象:class object,维护每个python类基本信息的数据结构
  • 实例对象:instance object,python类实例后产生的对象,简称:对象
  • 这是一组概念,类对象全局只有一个,实例对象可以生成多个

面向对象术语概述

  • 三个特征:封装、继承、多态
  • 继承:基类、派生类、子类、父类、超类、重载
  • 命名空间:程序元素作用域的表达
  • 构造和析构:生成对象和删除对象的过程
    在这里插入图片描述
    python OOP实列
class Product():
    def __init__(self,name):
        self.neme=name
        self.label_price=0
        self.real_price=0 
c=Product("电脑")
d=Product("打印机")
e=Product("投影仪")
c.label_price,c.real_price=10000,8000 
d.label_price,d.real_price=2000,1000
e.label_price,e.real_price=1500,900 
s1,s2=0,0
for i in [c,d,e]:
    s1+=i.label_price
    s2+=i.real_price print(s1,s2)
print(s1,s2)    

2.2python类的构建

单元开篇

  1. 类的基本构建
  2. 类的析构函数
  3. 类的属性
  4. 类的方法
  5. 类的析构函数

类的基本构建方法

                      使用class保留字定义类
class <类名>:
         [类描述:"documentation string"]
         <语句块>
**类定义不限位置,可以包含在分支或其他从属语句块中,执行时存在即可**
                       使用class保留字定义类

 - 类的名字:可以是任何有效标识符,建议采用大写单词的组合
                     如:ClassName,BasicAuto,BasicCreature
 - 类描述:在类定义后首行,以独立字符串形式定义
                     定义后通过<类名>._doc_属性来访问

class DemoClass:
    "This is a demo for Python class"
    pass
print(DemoClass.__doc__)

*类对象:class object

  • 类定义完成后,默认生成一个类对象
  • 每个类唯一对应一个类对象,用于存储这个类的基本信息
  • 类对象是type类的实例,表达为type类型
 class DemoClass:
    "This is a demo for Python class"
    print("Hello Demo Class")
print(DemoClass.__doc__)
print(type(DemoClass))

>>>Hello Demo Class
>>>This is a demo for Python class
>>><class 'type'>
**类对象内直接包含的语句会被执行,因此,一般不在类定义中直接包含语句**

类的使用方法

          通过创建实例对象(instance object)使用类的功能
          
                    <对象名>=<类名>([<参数>])
         进一步采用<对象名>.<属性名><对象名>.<方法名>()体现类的功能
         class DemoClass:
               "This is a demo for Python class"
               print("Hello Demo Class")
         print(type(DemoClass))
         cn=DemoClass()
         print(type(cn))
         
         >>>Hello Demo Class
         >>>class 'type'>
         >>><class '__main__.DemoClass'>
         **实列对象和类对象的类型是不同的**

类的构造函数

了解python类的构造函数

  • 类的构造函数用于从类创建实例对象的过程
  • 类的构造函数为实例对象创建提供了参数输入方式
  • 类的构造函数为实例属性的定义和复制提供了支持

类的属性和方法
了解python类的属性和方法

  • 类的属性:类中定义的变量,用来描述类的一些特性参数
  • 类的方法:类中定义且与类相关的函数,用来给出类的操作功能
  • 属性和方法是类对外交互所提供的两种接口方式

类的构造函数

          python使用预定义的_init_()作为构造函数
               class <类名>:
                     def _init_(self,<参数列表>)
                        <语句块>
                          ......
        **类实例化时所使用的函数,可以接受参数并完成初始操作**
        class DemoClass:
              def __init__(self,name):
                print(name)
        dc1=DemoClass("老王")
        dc2=DemoClass("老李")
        >>>老王
        >>>老李

_ init _()使用说明

  • 参数:第一个参数约定是self,表示类实例自身,其他参数是实例参数
  • 函数名:python解释器内部定义,由下划线(_)开始和结束
  • 返回值:构造函数没有返回值,或返回None,否则产生TypeError异常

self在类定义内部代表类的实例

  • self是python面向对象中约定的一个类参数
  • self代表类的实例,在类内部,self用于组合访问实例相关的属性和方法
  • 相比,类名代表类对象本身

类的属性

  • 类属性:类对象的属性,由所有实例对象所共享
    访问:<类名>.<类属性> 或<对象名>.<类属性>

  • 实例属性:实例对象的属性,由各实例对象所有独享
    访问:<对象名>.<实例属性>
    属性是类内部定义的变量

    class <类名>:
    <类属性名>=<类属性初值>
    def init(self,<参数列表>)
    self.<实例属性名>=<实例属性初值>

       class DemoClass:
           count=0
           def __init__(self,name,age):
               self.name=name
               self.age=age
               DemoClass.count+=1
dc1=DemoClass("老王",45)
dc2=DemoClass("老李",51)
print("总数:",DemoClass.count)
print(dc1.name,dc2.name)
>>>总数:2
>>>老王 老李

类的方法
方法是类内部定义的函数

  • 实例方法;实例对象的方法,由各实例对象独享
  • 类方法:类对象的方法,由所有实例对象共享
  • 自由方法:类中的一个普通函数,由类所在命名空间管理,类对象独享
  • 静态方法:类中的要给普通函数,由类对象和实例对象共享
  • 保留方法:由双下划线开始和结束的方法,保留使用,如_len_()

类的实例方法

  • 实例方法是类内部定义的函数,与实例对象相关
class <类名>:
      def <方法名>(self,<参数列表>):
         ....

实例方法采用<对象名>.<方法名>(<参数列表>)方式使用

class DemoClass:
    def __init__(self,name):
        self.name=name
    def lucky(self):
        s=0
        for c in self.name:
            s+=ord(c) %100
        return s
dc1=DemoClass("老王")
dc2=DemoClass("老李")
print(dc1.name,"的幸运数字是:",dc1.lucky())
print(dc2.name,"的幸运数字是:",dc2.lucky())

>>>老王 的幸运数字是: 148
>>>老李 的幸运数字是: 115
**实例方法的定义第一个参数是self**

类的类方法

  • 类方法至少包含一个参数,表示类对象,建议用cls
  • 类方法是与类对象相关的函数,由所有实例对象共享
  • @classmethod是装饰器,类方式定义所必须
  • 类方式只能操作类属性和其他类方法,不能操作实例属性和实例方法
class <类名>:
          @classmethod
          def <方法名>(cls,<参数列表>):
          .....

类方法采用<类名>.<方法名>(<参数列表>)<对象名>.<方法名>(<参数列表>)方法使用

class DemoClass:
    count=0
    def __init__(self,name):
        self.name=name
        DemoClass.count+=1
    @classmethod
    def getChrCount(cls):
        s="零一二三四五六七八九十多"
        return s[DemoClass.count]
dc1=DemoClass("老王")
dc2=DemoClass("老李")
print(dc1.getChrCount())
print(DemoClass.getChrCount())
**类方法调用可以用类名或对象名**

类的自由方法

  • 自由方法不需要self或cls这类参数,可以没有参数
  • 自由方法只能操作类属性和(其他)类方法,不能操作实例属性和实例方法
  • 自由方法的使用只能使用<类名>
  • 自由方法是定义在类命名空间中的普通函数
class <类名>:
          def <方法名>(<参数列表>):
          .....

自由方法采用<类名>.<方法名>(<参数列表>)方式使用,<类名>表示命名空间

class DemoClass:
    count=0
    def __init__(self,name):
        self.name=name
        DemoClass.count+=1
    def foo():
       DemoClass.count *=100
       return DemoClass.count
dc1=DemoClass("老王")
print(DemoClass.foo())
**自由方法就是类中普通函数
理解为:
定义在类命名空间中的函数也可以定义在类外,习惯不同**

类的静态方法
静态方法是定义在类中的普通函数,能够被所有实例对象共享

  • 静态方法可以没有参数,可以理解为定义在类中的普通函数
  • @staticmethod是装饰器,静态方法定义所必须
  • 静态方法只能操作类属性和其他类方法,不能操作实例属性和实例方法
  • 相比于自由方法,静态方法能够使用<类名>和<对象名>两种方式使用
class <类名>:
          @staticmethod
          def <方法名>(<参数列表>):
          ......

静态方法采用 <类名>.<方法名>(<参数列表>)<对象名>.<方法名>(<参数列表>)方式使用
class DemoClass:
    count=0
    def __init__(self,name):
        self.name=name
        DemoClass.count+=1
    @staticmethod
    def foo():
       DemoClass.count *=100
       return DemoClass.count
dc1=DemoClass("老王")
dc2=DemoClass("老李")
print(dc2.foo())
print(dc1.foo())
**静态方法就是类中普通函数
  但:
  这类方法能够被类和对象调用**

类的保留方法

保留方法由双下划线开始和结束发的方法,保留使用
class <类名>def <保留方法名>(<参数列表>)
               .......

保留方法一般都对应类的某种操作,但操作产生时调用

class DemoClass:
    count=0
    def __init__(self,name):
        self.name=name
        DemoClass.count+=1
    def __len__(self):
        return len(self.name)
dc1=DemoClass("老王")
dc2=DemoClass("小诸葛")
print(type(dc2))
print(len(dc1))
print(len(dc2))
**_len_()方法对应len()函数操作
   理解为:
   这是python解释器保留方法
   已对应,只需要编写代码即可**

类的析构函数
del()的使用说明

  • 函数名和参数:python解释器内部约定,保留方法
  • 调用条件:当实例对象被真实删除时,才调用改函数内语句
  • 真实删除:当前对象的引用数为0或当前程序退出(垃圾回收)
python使用预定义的_del_()作为析构函数
    class <类名>:
             def  _del_(self):
                    <语句块>
              .....

析构函数在真实删除实例对象时被调用

class DemoClass:
    def __init__(self,name):
        self.name=name
    def __del__(self):
        print("再见",self.name)
dc1=DemoClass("老王")
del dc1
>>>再见 老王
**使用del删除对象且对象被真实删除时调用析构函数_del_()**

在这里插入图片描述
在这里插入图片描述
sys.getrefcount(<对象名>)获得对象的引用次数

  • 返回对象引用次数的方法,辅助删除对象时的分析
  • sys.getrefcount()函数返回值为被引用值+1
  • 非特定目的,不建议自己撰写析构函数,利用pytho垃圾回收机制

2.3实列1:银行ATM等待时间

import random


class ATM():
    def __init__(self,maxtime=5):
        self.t_max=maxtime
    def getServCompleteTime(self,start=0): # 获得每次ATM服务完成的时间
        return start+random.randint(1,self.t_max)
class Customers():
    def __init__(self,n):
        self.count=n
        self.left=n
    def getNextArrvTime(self,start=0,arrvtime=10): #返回下个客户到达的时间
        if self.left!=0:
            self.left-=1
            return start+random.randint(1,arrvtime)
        else:
            return 0
    def isOver(self): #判断客户库存是否清零
        return True if self.left==0 else False
c=Customers(100)
a=ATM()
wait_list=[] #每次等待队列
wait_time=0 #队列中总等待时间
cur_time=0 #当前时间
cur_time+=c.getNextArrvTime() #用户每次到达时间
wait_list.append(cur_time)
while len(wait_list)!=0 or not c.isOver():
    if wait_list[0] <= cur_time:
        next_time=a.getServCompleteTime(cur_time) #下次时间
        del wait_list[0]
    else:
        next_time=cur_time+1 #下次时间
    if not c.isOver() and len(wait_list) ==0:
        next_arrv=c.getNextArrvTime(cur_time)
        wait_list.append(next_arrv)
    if not c.isOver() and wait_list[-1] <next_time:
        next_arrv=c.getNextArrvTime(wait_list[-1])
        wait_list.append(next_arrv)
        while next_arrv<next_time and not c.isOver():
            next_arrv=c.getNextArrvTime(next_arrv)
            wait_list.append(next_arrv)
    for i in wait_list:
        if i <=cur_time:
            wait_time+=next_time-cur_time
        elif cur_time<i<next_time:
            wait_time+=next_time-i
        else:
            pass
    cur_time=next_time
print(wait_time/c.count)

提示:没看懂得可以去看看这位博主写的
Python 实例详解:银行 ATM 等待时间分析

2.4python类的封装

在这里插入图片描述

在这里插入图片描述
封装Encapsulation:属性和方法的抽象

  • 属性的抽象:可以选择公开或隐藏属性,隐藏属性的内在机理
  • 方法的抽象:可以选择公开或隐藏方法,隐藏方法的内部逻辑
  • 封装:让数据和代码成为类的过程,表达为:类-属性-方法

在这里插入图片描述

**公开类属性:即类属性**
class <类名>:
         <类属性名>=<类属性初值>
         def _init_(self,<参数列表>)
                self.<实例属性名>=<实例属性初值>
        ....
**私有类属性:仅供当前类访问的类属性,子类亦不能访问**
class <类名>:
         <私有类属性名>=<类睡醒初值>
         def _init_(self,<参数列表>)
        ....
     **区别:私有类属性名开始需要有两个下划线(_),如__count**
     **私有类属性可以通过类方法来获取值**
**公开实例属性:即实例属性**
class <类名>:
         <类属性名>=<类属性初值>
         def _init_(self,<参数列表>)
              self.<实例属性名>=<实例属性初值>
            ....  
**私有实例属性:仅供当前类内部访问的实例属性,子类亦不能访问**
class <类名>:
		def _init_(self,<参数列表>)
              self.<实例属性名>=<实例属性初值>
            ....  
            **区别:私有实例属性名开始需要有两个下划线(_),如__name**

私有实例属性:仅供当前类内部访问的实例属性,子类亦不能访问

  • 只能在类的内部被方法所访问
  • 不能通过<类名>.<属性名>或<对象名>.<属性名>方式访问
  • 有效保证了属性维护的可控性

私有属性
python没有真正意义上的私有属性,可以都过实实例名._类名__私有属性名来直接访问

**私有方法是类内部定义并使用的函数**
class <类名>:
         def <方法名>(self,<参数列表>)
       ....
       私有方法名开始需要有两个下划线(__),如__getCount() 

私有方法是类内部定义并使用的函数

  • 各类方法都可以通过增加双下划线变为私有方法
  • 私有方法从形式上保护了python类内部使用的函数逻辑
  • 私有与公开是程序员逻辑,不是安全逻辑,重视约定

私有方法
python没有真正意义上的私有方法,可以都过实例名._类名__私有方法名来直接访问

python解释器预留的类属性,以双下划线开头和结尾

  • 也叫:特殊属性,Special Attributes
  • 特点:双下划线开头和结尾
  • 作用:为理解python类提供了统一的属性接口
  • 属性值:具有特定含义,类定义后直接使用

仅用<类名>访问的保留属性

  • __ name __ 类的名称
  • _ qualname __ 以.分隔从模块全局命名空间开始的类名称
  • __ bases __ 类所继承的基类名称

保留属性 :类和对象都可以使用
<类>.dict 包含类成员信息的字典,key是属性和方法的名称,value是地址
<对象>.__dict __包含对象属性信息的字典,key是属性名称,value是值
__ class __ 对象所对应的类信息,即type信息
__ doc __ 类描述,写在类定义下的首行字符串,不能继承
__ module __ 类所在模块的名称(返回元组类型) 我测试时是字符串类型

python解释器预留的类方法,以双下划线开头和结尾

  • 也叫:特殊方法,Special Methods
  • 特点:双下划线开头和结尾
  • 作用:为操作python类提供了统一的方法接口
  • 方法逻辑:具有特定含义,一般与操作符关联,类定义需要重载

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.5python类的继承

在这里插入图片描述

继承Inheritance:代码复用的高级抽象

  • 继承是面向对象程序设计的我精髓之一
  • 实现了以类为单位的高抽象级别代码复用
  • 继承是新定义类能几乎完全使用原有类属性与方法的过程

在这里插入图片描述

在这里插入图片描述在这里插入图片描述

**在定义类时声明继承关系**
class <类名>(<基类名>):
         def __init__(self,<参数列表>)
              <语句块>
        .......
基类名可以带有路径:ModultName.BaseClassName

派生类可以直接使用基类的属性和方法

  • 基类的属性基本等同于定义在派生类中
  • 派生类可以直接使用基类的类属性、实例属性
  • 派生类可以直接使用基类的各种方法
  • 使用基类的类方法和类属性时,要用基类的类名调用

在这里插入图片描述

派生类的约束

  • 派生类只能继承基类的公开属性和方法
  • 派生类不能继承基类的私有属性和私有方法

object类是python所有类的基类

  • object是python最基础类的名字,不建议翻译理解
  • 所有类定义时默认继承object类
  • 保留属性和保留方法本质上是object类的属性和方法

python对象的三个要素:标识、类型和值

  • 标识identity:对象一旦构建不会改变,用id()获得,一般是内存地址
  • 类型type:对象的类型,用type()获得
  • 值value:分为可变mutable与不可变immutable两种

2个与基础类有关的python内置功能
在这里插入图片描述

重载:派生类对基类属性或方法的再定义

  • 属性重载:派生类定义并使用了与基类相同名称的属性
  • 方法重载:派生类定义并使用了与基类相同名称的方法

类的属性重载
最近的覆盖原则:重载无需特殊标记

  • 步骤1:优先使用派生类重定义的属性和方法
  • 步骤2:然后寻找基类的属性和方法
  • 步骤3:再寻找超类的属性和方法

方法重载:派生类对基类方法的再定义

  • 完全重载:派生类完全重定义与基类相同名称的方法,直接在派生类中定义同名方法即可
  • 增量重载:派生类扩展定义与基类相同名称的方法
**增量重载:使用super()方法**
calss <派生类名>(<基类名>):
         def <方法名>(self,<参数列表>)
               super().<基类方法名>(<参数列表>)

class DemoClass:
    count=0
    def __init__(self,name):
        self.name=name
        DemoClass.count+=1
    def printCount(self):
        return str(DemoClass.count)+self.name

class HumanNameClass(DemoClass):
    count = 2
    def __init__(self,name):
        self.name=name
    def printCount(self):
        return super().printCount()+"同志"
dc2=DemoClass("老李")
dc1=HumanNameClass("老王")
print(dc2.printCount())
print(dc1.printCount())
print(dc2.name)
               .......
<<<1老李
<<<1老王同志
<<<老李

三、第二周

3.1python类的运算

在这里插入图片描述

运算Operatioin:操作逻辑的抽象
在这里插入图片描述

  • 运算体现一种操作逻辑,广义角度,任何程序都被认为是运算
  • python解释器通过保留方法预留了一批运算的接口,需要重载
  • 保留方法一般对应运算符,python中运算体现为运算符的重载

运算重载的限制

  • 不能重载python语言内置类型的运算符
  • 不能新建运算符,只能通过重载完成
  • is and not or不能被重载

算术运算的种类:
在这里插入图片描述

算术运算符的重载:一元算术运算符
在这里插入图片描述

算术运算符的重载:二元算术运算符
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

比较运算的种类
在这里插入图片描述
在这里插入图片描述
成员运算的种类
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

其他运算的种类
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
提示:Python中__repr__和__str__区别

所有的数据类型都自带布尔值,数据只有在0,None和空的时候为False。

3.2python类的多态

在这里插入图片描述

多态Polymorphism:仅针对方法,方法林灵活性得抽象

  • 参数类型的多态:一个方法能够处理多个类型的能力
  • 参数形式的多态:一个方法能够接受多个参数的能力
  • 多态是OOP的一个传统概念,python天然支持多态,不需要特殊语法

天然支持:python方法无类型申明限制

  • python的函数/方法没有类型申明限制,天然支持参数类型的多态性
  • python编程理念在于:文档约束,而非语法约束
  • 对不同参数类型的区分及功能,需要由程序员完成

参数类型的多态:

class DemoClass:
    def __init__(self,name):
        self.name=name

    def __id__(self):
        return len(self.name)

    def lucky(self,salt):
        s=0
        for c in self.name:
            s+=(ord(c)+id(salt))%100
        return s

dc1=DemoClass("老王")
dc2=DemoClass("老李")
print(dc1.lucky(10))
print(dc1.lucky("10"))
print(dc1.lucky(dc2))

天然支持:pytho方法/函数支持多种函数形式

  • python的函数/方法可以支持可变参数,支持参数形式的多态性
  • python的类方法也是函数,函数的各种定义方式均有效
  • 对不同参数个数及默认值的确定,需要由程序员完成

参数形式的多态:

class DemoClass:
    def __init__(self,name):
        self.name=name

    def __id__(self):
        return len(self.name)

    def lucky(self,salt=0,more=9):
        s=0
        for c in self.name:
            s+=(ord(c)+id(salt)+more)%100
        return s

dc1=DemoClass("老王")
print(dc1.lucky())
print(dc1.lucky(10))
print(dc1.lucky(10,100))

3.3实列2:图像的四则运算

图像之间进行四则运算:加减乘除

  • 加减法:两个图像相加减
  • 乘除法:一个图像与一个数字之间的乘除法
  • 通过面向对象程序设计方法,简化程序表达
  • 让图像处理变得更加有趣、更加人性化
  • 图像变换的抽象层次更加高级(抽象是追求的目标)

numpy库和PIL库

  • PIL库是一个能够简单读写图像文件的库
  • numpy库是一个矩阵表示的数学库
  • 图像可以理解为何一个三维数据,像素是(r,g,b),长宽是2个维度
import numpy as np
from PIL import Image

class ImageObject:
    def __init__(self,path=""):
        self.path=path
        try:
            self.data=np.array(Image.open(path))
        except:
            self.data=None

    def __add__(self, other):
        image=ImageObject()
        try:
            image.data=np.mod(self.data+other.data,255)
        except:
            image.data=self.data
        return image

    def __sub__(self, other):
        image=ImageObject()
        try:
            image.data=np.mod(self.data-other.data,255)
        except:
            image.data=self.data
        return image

    def __mul__(self, factor):
        image=ImageObject()
        try:
            image.data=np.mod(self.data*factor,255)
        except:
            image.data=self.data
        return image

    def __truediv__(self, factor):
        image=ImageObject()
        try:
            image.data=np.mod(self.data//factor,255)
        except:
            image.data=self.data
        return image

    def saveImage(self,path):
        try:
            im=Image.fromarray(self.data)
            im.save(path)
            return True
        except:
            return False

a=ImageObject(r"D:\PycharmProjects\Image\earth.jpg")
b=ImageObject(r"D:\PycharmProjects\Image\gray.jpg")
(a+b).saveImage((r"D:\PycharmProjects\Image\result_add.jpg"))
(a-b).saveImage((r"D:\PycharmProjects\Image\result_sub.jpg"))
(a*b).saveImage((r"D:\PycharmProjects\Image\result_mul.jpg"))
(a/b).saveImage((r"D:\PycharmProjects\Image\result_div.jpg"))

3.4python对象的引用

在这里插入图片描述

引用Reference:对象的指针

  • 引用是内存中真实对象的指针,表示为变量名或内存地址
  • 每个对象存在至少1个引用,id()函数用于获得引用
  • 在传递参数和赋值时,python传递对象的引用,而不是复制对象

在这里插入图片描述

python内部机制对引用的处理

  • 不可变对象:immutable解释器为相同值维护尽量少的内存区域
  • 可变对象:mutable解释器为每个对象维护不同内存区域

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
导致引用+1的情况

  • 对象被创建:d=DemoClass()
  • 对象被引用:a=d
  • 对象被作为函数或方法的参数:sys.getrefcount(d)
  • 对象被作为一个容器中的元素:ls=[d]

我的理解:sys.getrefcount()方法运行时就调用了一次对象,多以加1,同理,ls赋值时也是如此

导致引用-1的情况

  • 对象被删除:del d
  • 对象的名字被赋予新的对象:d=123
  • 对象离开作用域:foo()函数的局部变量count
  • 对象所在容器被删除:del ls

浅拷贝和深拷贝

  • 拷贝:复制一个对象为新的对象,内存空间有“变化”
  • 浅拷贝:仅复制最顶层对象的拷贝方式,默认拷贝方式
  • 深拷贝:迭代复制所有对象的拷贝方式

完全拷贝对象内容

  • 采用copy库的deepcopy()方法
  • 迭代拷贝对象内各层次对象,完全新开辟内存建立对象
  • 深拷贝仅针对可变类型,不可变类型无需创建新对象

提示:浅拷贝和深拷贝可以看看这位up主的讲解,简单易懂十分钟!彻底弄懂Python深拷贝与浅拷贝机制

类的实例方法

  • 定义方式:def <实例方法名>(self,<参数列表>)
  • 实例方法名也是一种引用,即对方法本身的引用
  • 当方法被引用时,方法(即函数)将产生一个对象:方法对象

在这里插入图片描述
在这里插入图片描述

3.5python类的高级话题

在这里插入图片描述

命名空间Namespace:从名字到对象的一种映射

  • 作用域:全局变量名在模块命名空间,局部变量名在函数命名空间
  • 属性和方法在类命名空间,名字全称:<命名空间>.<变量/函数名>
  • 命名空间底层由一个dict实现,变量名是键,变量引用的对象是值
  • 复数z,z.real和z.imag是对象z命名空间的两个属性
  • 对象d,d.name和d.printName()是对象d命名空间的属性和方法
  • global和nonlocal是两个声明命名空间的保留字
    提示:可以看看这两个博主写的很清楚nonlocal关键字使用场景及与global关键字的区别深入了解Python中什么是闭包函数

@property:类的特征装饰器

  • 使用@property把类中的方法变成对外可见的“属性"
  • 类内部:表现为方法
  • 类外部:表现为属性

在这里插入图片描述

异常Exception也是一种python类

  • try-except捕捉自定义的异常
  • 继承Exception,可以给出自定义的异常类
  • 自定义异常类是类继承的正常应用过程

在这里插入图片描述
在这里插入图片描述

名称修饰:Name Mangling:类中名称的变换约定

  • python通过名称修饰完成一些重要功能
  • 采用下划线(_)惊醒名称修饰,分为5中情况
  • _ x、 x_、__ x 、__ x __、 _

_x:单下划线开头的名称修饰

  • 单下划线开头属性或方法为类内部使用 PEP8
  • 只是约定,仍然可以通过(对象名).<属性名>方式访问
  • 功能:from xx import*时不会导入单下划线开头的属性或方法

x_:单下划线结尾的名称修饰

  • 单下划线结尾属性或方法为避免与保留字或已有命名冲突 PEP8
  • 只是约定,无语任何功能性对应

__x:双下划线开头的名称修饰

  • 双下划线开头属性或方法将被解释器修改名称,避免命名冲突
  • 不是约定,而是功能性,实现私有属性、私有方法
  • __x会被修改为:_<类名>__x

__ x __:双下划线开头和结尾的名称修饰

  • 双下划线开头和结尾的属性或方法无任何特殊功能,名字不被修改
  • 部分名称时保留属性或保留方法

_:单下划线

  • 单下划线是一个无关紧要的名字,无特殊功能

python:最小空类

  • 类是一个命名空间,最小空类可以当作命名空间使用
  • 最小空类可以辅助数据存储和使用
  • 动态增加属性是python类的一个特点

在这里插入图片描述

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值