当前位置: 移动技术网 > IT编程>脚本编程>Python > 记录python面向对象开发笔记

记录python面向对象开发笔记

2020年07月16日  | 移动技术网IT编程  | 我要评论

面向对象(OOP)基本概念

面向对象编程:Object oriented programming 简写OOP

一. 目标

了解面向对象基本概念

1. 面向对象基本概念

之前学习的python变成方式是 面向过程的,而面向过程面向对象,是两种不同的编程方式。

1.1 过程和函数

  • 过程是早期的变成概念

  • 过程类似于函数,只能执行,但是没有返回值

  • 函数不仅能执行,还可以返回结果

1.2 面向过程和面向对象的基本概念

1)面向过程怎么做?

  1. 把完成某一个需求的所有步骤从头至尾逐步骤实现
  2. 根据开发需求,将某些功能独立的代码封装为函数
  3. 最后完成代码,就是顺序的调用不同函数

特点

  1. 注重步骤和过程,不注重职责分工
  2. 如果需求复杂,代码会很复杂
  3. 开发复杂项目,没有固定的套路,开发难度大

2)面向对象

相比函数,面向对象是更大的封装,职责在一个对象中封装多个方法

  1. 在完成某一个需求前,首先确定职责,也就是要做的事情
  2. 根据职责确定不同的对象,在对象内部封装不同的方法
  3. 最后完成的代码,就是顺序的让不同的对象调用不同的方法

特点

  1. 注重对象和职责,不同的对象承担不同的职责
  2. 适合复杂的需求变化,专门应对复杂项目开发,提供固定套路
  3. 需要在面向过程基础上,再学一些面向对象的语法

二. 类和对象

目标

  • 类和对象的概念
  • 类和对象的关系
  • 类的设计

2. 类和对象的概念

对象是面向对象编程的两个核心概念

2.1 类

  • 是对一群有相同特征或者行为的事物的一个统称,是抽象的,不能直接使用
    • 特征被称为属性
    • 行为被称为方法
  • 相当于制造飞机的图纸,是负责创建对象的

一般需要满足以下三个要素:

  1. 类名:这类事物的名字
  2. 属性:这类事物的特征
  3. 方法:这类事物的行为

2.2 对象

  • 对象 是由类创建出来的一个具体存在,可以直接使用
  • 哪一个类创建出来的对象,就拥有在哪一个类中定义的:
    • 属性
    • 方法
  • 对象相当于用图纸制造的飞机
  • 在程序开发中,应该先有,再有对象

3. 面向对象基础语法

面向对象更大封装,在一个类中封装多个方法,这样通过这个类创建出来的对象,就可以直接调用这些方法

3.1 定义一个简单的类

在python中要定义一个只包含方法的类,语法格式如下:

class 类名:
	def 方法1(self, 参数列表):
		pass
	def 方法2(self,参数列表):
		pass
  • 方法的定义格式和之前学习过的函数一样
  • 区别在于第一个参数必须是self

3.2 创建对象

当一个类定义完成之后,要使用这个类来创建对象,语法格式如下:

对象变量 = 类名()

3.3 第一个面向对象程序

需求

  • 小猫爱吃鱼,小猫爱喝水

分析

  1. 定义一个猫类Cat
  2. 定义两个方法eat和drink
  3. 按照需求不需要定义属性
class Cat:
    
    def eat(self):
        print("小猫爱吃鱼")
    
    def drink(self):
        print("小猫爱喝水")

# 创建猫对象
tom = Cat()

tom.drink()
tom.eat()

案例进阶 使用Cat类再创建个对象

# 再创建个猫对象
lazy_cat = Cat()
lazy_cat.drink()
lazy_cat.eat()

其中lazy_cat与tom两个不是一个对象,但属于同一类中

3.4 方法中的self参数

案例改造

  • 在python中,要给对象设置属性,非常的容易,但是不推荐使用
    • 因为:对象属性的封装应该直接在类的内部
  • 只需要在类的外部的代码中直接通过 . 设置一个属性即可
class Cat:
    
    def eat(self):
        print("%s 爱吃鱼" % self.name)
    
    def drink(self):
        print("%s 爱喝水" % self.name)

# 创建猫对象
tom = Cat()
# 访问对象的属性
tom.name = "Tom"
tom.drink()
tom.eat()

# 再创建个猫对象
lazy_cat = Cat()
# 访问对象的属性
lazy_cat.name = "大懒猫"
lazy_cat.drink()
lazy_cat.eat()

3.5 初始化方法

  • 当使用类名()创建对象时,会自动执行以下操作:
  1. 为对象在内存中分配空间:创建对象
  2. 为对象的属性设置初始值:初始化方法
  • 这个**初始化方法就是__init__方法,它时对象的内置方法

__init__方法时专门用来定义一个类具有哪些属性的方法!

Cat中增加__init__方法,验证该方法在创建对象时会被自动调用

class Cat:   
    def __init__(self):
        print("这是一个初始化方法")
# 没有调用对象的属性,但是仍然会输出
tom = Cat()

3.6 在初始化方法内部定义属性

  • __init__方法内部使用self.属性名=属性的初始值就可以定义属性
  • 定义属性之后,再使用Cat类创建的对象都会拥有该属性
class Cat:
    def __init__(self):
        print("这是一个初始化方法")
        
        # self.属性名 = 属性的初始值
        self.name = "Tom"

3.7 改造初始化方法,初始化的同时设置初始值

  • 在开发中,如果希望在创建对象的同时设置对象的属性,可以对__init__方法进行改造
  1. 把希望设置的属性值,定义成__init__方法的参数
  2. 把方法内部使用self.属性=形参接受外部传递的参数
  3. 在创建对象时,使用类名(属性1,属性2,...)调用
class Cat:
    def __init__(self, new_name):
        print("这是一个初始化方法")

        # self.属性名 = 属性的初始值
        self.name = new_name

3.8 内置方法和属性

序号 方法名 类型 作用
01 __del__ 方法 对象从内存中销毁时,自动调用
02 __str__ 方法 返回对象的描述信息,print函数输出使用
  1. __del__方法

    • 在python中
      • 当使用类名()创建对象时,为对象分配完空间后,会自动调用__init__方法
      • 当一个对象从内存中销毁前,会自动调用__del__方法
    • 应用场景
      • __init__改造初始化方法,可以让创建对象更加灵活
      • __del__如果希望在对象被销毁前,再做一些事情,可以考虑一下__del__方法
    • 生命周期
      • 一个对象从调用类名()创建,生命周期开始
      • 一个对象的__del__方法一旦被调用,生命周期结束
      • 再对象的生命周期内,可以访问对象属性,或者让对象调用方法
    class Cat:
        def __init__(self, new_name):
            print("这是一个初始化方法")
            # self.属性名 = 属性的初始值
            self.name = new_name
        def __del__(self):
            print("%s 删了" % self.name)
    tom = Cat("Tom")
    print("-" * 50)
    

    这样tom删了的字样会在打印分割线之下才能输出

    class Cat:
        def __init__(self, new_name):
            print("这是一个初始化方法")
            # self.属性名 = 属性的初始值
            self.name = new_name
        def __del__(self):
            print("%s 删了" % self.name)
    tom = Cat("Tom")
    # 使用del关键字删除一个对象
    del tom
    print("-" * 50)
    

    这样tom删了的字样会在分割线之上就已经输出

  2. __str__方法

    • 在python中,使用print输出对象变量,默认情况下,会输出这个变量引用的对象是由哪一个类创建的对象,以及在内存中的地址
    • 如果在开发中,希望使用pring输出变量对象时,能够打印自定义内容,就可以利用__str__方法
    class Cat:
        def __init__(self, new_name):
            print("这是一个初始化方法")
    
            # self.属性名 = 属性的初始值
            self.name = new_name
    
        def __del__(self):
            print("%s 删了" % self.name)
    
        def __str__(self):
    
            # 必须返回一个字符串
            return "我是小猫 %s" % self.name
    
    # 创建猫对象
    tom = Cat("Tom")
    print(tom)
    
    
  3. 案例

    需求:

    1. 小明体重75公斤
    2. 小明每次跑步会减肥0.5公斤
    3. 小明每次吃东西体重增加1公斤

    封装:

    1. 封装面向对象编程的一大特点
    2. 面向对象编程的第一步将属性和方法封装到一个抽象的类中
    3. 外界使用类创建对象,然后让对象调用方法
    4. 对象方法的细节都被封装在类的内部
    5. 同一个类内,不同对象的属性是不会互相干扰的

    Code:

    class Person():
    
        def __init__(self, name, weight):
            # self.属性 = 形参
            self.name = name
            self.weight = weight
    
        def __str__(self):
            
            return "我的名字叫 %s 我的体重是 % .2f 公斤" % (self.name, self.weight)
        
        def run(self):
            print("%s 爱跑步,跑步锻炼身体" % self.name)
            self.weight -= 0.5
        
        def eat(self):
            print("%s 爱吃,吃完再减肥" % self.name)
            self.weight += 1
    
    xiaoming = Person("小明", 75)
    
    xiaoming.eat()
    xiaoming.run()
    
    print(xiaoming)
    

3.9 私有属性和私有方法

应用场景

  • 在实际开发中,对象的某些属性或方法可能只希望在对象内部被使用,而不希望在外部被访问到
  • 私有属性就是对象不希望公开的属性
  • 私有方法就是对象不希望公开的方法

定义方式

  • 在定义属性或方法时,在属性名或方法名前加两个下划线,定义的就是私有属性或方法
class Women():

    def __init__(self, name, weight):
        # self.属性 = 形参
        self.name = name
        # weight就是表示women类的私有属性,无法被调用输出
        self.__weight = weight

    def secret(self):
        print("%s 的年龄是 %d" % (self.name, self.__weight))
        
    def __msecret(self):
        print("%s 的年龄是 %d" % (self.name, self.__weight)) 

xiaomei = Women("小明", 75)
xiaomei.secret()
# 私有方法,在外界也无法被直接访问
xiaomei.__msecret()
# 私有属性,在外界无法被直接访问
print(xiaomei.__weight)

4 继承

目标

  • 单继承
  • 多继承

面向对象三大特性

  1. 封装根据职责将属性和方法封装到一个抽象的类中
  2. 继承实现代码的重用,相同的代码不需要重复的编写
  3. 多态不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度

4.1 单继承

继承的概念、语法和特点

继承的概念:子类拥有父类的所有方法属性

1. 继承的语法

class 类名(父类名):
	pass
  • 子类 继承自 父类,可以直接享受父类中已经封装好的方法,不需要再次开发
  • 子类 中应该根据职责,封装子类特有的属性和方法

2. 继承的传递性

  • c类从b类继承,b类由从a类继承
  • 那么c类就具有b类和a类的所有属性和方法

子类拥有父类以及父类的父类中封装的所有属性和方法

3.方法的重写

  • 父类的方法实现不能满足子类需求时,可以对方法进行重写*(override)
  • 重写父类方法有两种情况:
  1. 覆盖父类的方法

    • 如果在开发中,父类的方法实现和子类的方法实现,完全不同
    • 可以使用覆盖的方式,在子类中重新编写父类的方法实现

    具体的实现方式,相当于在子类中定义了一个和父类同名的方法并实现,重写之后,在 运行时只会调用子类中重写的方法,而不再调用父类封装的方法

  2. 对父类方法进行扩展

    • 如果在开发中,子类的方法实现中包含父类的方法实现
    • 父类原本封装的方法实现是子类方法的一部分

    可以使用扩展的方式:

    1. 在子类中重写父类的方法

    2. 在需要的位置使用super().父类方法来调用父类方法的执行

    3. 代码其他的位置针对子类的需要,编写子类特有的代码实现

    关于super

    • pythonsuper是一个特殊的类
    • super()就是使用super创建的对象
    • 最常用的使用场景就是在重写父类方法时,调用父类中封装的方法实现

4.父类的私有属性和私有方法

  1. 子类对象不能在自己的方法内部,直接访问父类的私有属性私有方法
  2. 子类对象可以通过父类公有方法间接访问到私有属性私有方法
    • 私有属性、方法是对象的隐私,不对外公开,外界以及子类都不能直接访问
    • 私有属性、方法通常用于做一些内部的事情

4.2 多继承

  1. 概念:

    • 子类可以拥有多个父类,并且具有所有父类的属性和方法
    • 例:孩子会继承自己父亲母亲的特性
  2. 语法:

    clsaa 子类名(父类名1, 父类名2,...)
    	pass
    
  3. 注意事项: 如果不同的父类中存在同名的方法,在开发时,应该尽量避免这种容易混淆的情况

5.多态

面向对象三大特性

  1. 封装根据职责将属性和方法封装到一个抽象的类中

  2. 继承实现代码的重用,相同的代码不需要重复的编写

    • 设计类的技巧
    • 子类针对自己特有的需求,编写特定的代码
  3. 多态不同的子类对象调用相同的父类,产生不同的执行后果

    • 多态可以增加代码的灵活度
    • 继承重写父类方法为前提
    • 是调用方法的技巧,不会影响到类的内部设计
class Dog(object):
	def __init__(self, name):
		self.name = name
	
	def game(self):
		print("%s 蹦蹦跳跳的玩耍..." % self.name)

class XiaoTianDog(Dog):
	def game(self):
		print("%s 飞到天上去玩耍..." % self.name)

class Person(object):
	def __init__(self, name):
		self.name = name
	
	def game_with_dog(self, dog):
		print("%s 和 %s 快乐的玩耍" % (self.name, dog.name))
		dog.game()
		
# 创建一个狗对象
# wangcai = Dog("旺财")			  # 引用的是父类中的方法
wangcai = XiaoTianDog("飞天旺财")	# 引用的Dog子类的方法

# 创建一个小明对象
xiaoming = Person("小明")

# 让小明与狗玩耍
xiaoming.game_with_dog(wangcai)

6. 类方法和静态方法

1 类方法

  • 类属性是针对类对象定义的属性
    • 使用赋值语句class关键字下方可以定义类属性
    • 类属性用于记录这个类相关的特征
  • 类方法就是针对类对象定义的方法
    • 类方法内部可以直接访问类属性或者调用其他的类方法

语法如下

@classmethod
def 类方法名(cls):
	pass
  • 类方法需要修饰器@classmethod来标识,告诉解释器这是一个类方法
  • 类方法的第一个参数应该是cls
    • 由哪一个类调用的方法,方法内的cls就是哪一个类的引用
    • 这个参数和实例方法的第一个参数是self类似
  • 通过类名.调用类方法,调用方法时,不需要传递cls参数
  • 在方法内部
    • 可以通过cls.访问类的属性
    • 也可以通过cls.调用其他的类方法
class Tool(object):
    # 使用赋值语句定义类属性,记录所有工具对象的数量
    count = 0

    @classmethod
    def show_tool_count(cls):
        print("工具对象的数量 %d" % cls.count)
    
    def __init__(self, name):
        self.name = name

        # 让类属性的值+1
        Tool.count += 1

# 创建工具对象
tool1 = Tool("斧头")

# 调用类方法
Tool.show_tool_count()

2. 静态方法

  • 在开发时,如果需要在中封装一个方法,这个方法:
    • 既不需要访问实例属性,或者调用实例方法
    • 也不需要访问类属性或者调用类方法
  • 这个时候,可以把这个方法封装成一个静态方法

语法如下

@staticmethod
def 静态方法名():
	pass
  • 静态方法需要使用修饰器@staticmethod来进行标识,告诉解释器这是一个静态方法
  • 通过类名.调用静态方法
class Dog(object):

    @staticmethod
    def run():
        print("小狗要跑...")

# 通过类名.调用静态方法
Dog.run()

本文地址:https://blog.csdn.net/qq_37000789/article/details/107338048

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网