面向对象(OOP)
面向对象的基本概念
面向过程和面向对象是两种不同的变成方式,对比面向过程的特点,可以更好地了解什么是面向对象
过程和函数
过程是早期的一个编程概念,类似于函数,只能执行,但是没有返回值,不仅能执行,还可以返回结果
面向过程
把某一个需求的所有步骤从头到尾逐步实现,根据开发需求,将某些功能独立的代码封装成一个又一个函数,最后完成的代码,就是顺序的调用不同的函数
特点
1.注重步骤与过程,不注重职责分工
2.如果需求复杂,代码会变得很复杂
3.开发复杂项目,没有固定的套路,开发难度很大
面向对象
相比较函数,面向对象是更大的封装,根据职责在一个对象中封装多个方法
在完成某一个需求前,首先确定职责,根据职责确定不同的对象,在对象内部封装不同的方法
特点
1.注重对象和职责,不同的对象承担不同的职责
2.更加适合应对复杂的需求变化,是专门应对负责项目开发,提供的固定套路
类和对象的概念
类和对象的是面向对象编程中的两个核心概念
类
类是对一群具有相同特征或者行为的事物的一个统称,是抽象的,不能直接使用
特征是属性
行为是方法
对象
对象是由类创建出来的一个具体存在,可以直接使用
由那个类创建出来的对象,就拥有那个类中定义的属性和方法
程序开发中,应该先有类,再有对象
类和对象的关系
类是模板,对象是根据类这个模板创建出来,应该先有类,再有对象
类只有一个,而对象可以有很多个,不同的对象之间属性可能会各不相同
类中定义了什么属性和方法,对象中就有什么属性和方法,不可能多,也不可能少
类的设计
设计类的三要素
1.类名这类事物的名字,满足大驼峰命名法
2.属性这类事物具有什么样的特征
3.方法这类事物具有什么样的行为
属性和方法的确定
对对象的特征描述,通常可以定义成属性
对象具有的行为,通常可以定义成方法
提示:需求中没有涉及的属性或者方法在设计类时,不需要考虑
面向对象基础语法
dir内置函数
在Python中对象几乎是无所不在的,之前学习的变量、数据、函数都是对象
使用内置函数dir传入标识符/数据,可以查看对象内的所有属性及方法
提示:__方法名__格式的方法是Python提供的内置方法/属性

定义类
面向对象是更大的封装,在一个类中封装多个方法,这个通过这个类创建出来的对象,就可以直接调用这些方法
格式如下:
class 类名: def 方法1(self,参数列表): pass def 方法2(self,参数列表): pass
方法的定义格式和之前学习过的函数几乎一样,区别在于第一个参数必须是self
创建对象
当一个类定义完成之后,要使用这个类创建对象,语法如下:
对象变量 = 类名()
在Python中,要给对象设置属性,非常的容易,但是不推荐使用,因为,对象的属性应该封装在类的内部
类外属性赋值的格式:
对象名.属性名 = “值”
由哪个对象吊桶的方法,方法内的self就是那个对象的引用
在类封装的方法内部,self就表示当前调用发的对象自己
调用方式时,程序员不需要传递self参数。
在方法内部
。可以通过self.访问对象的属性
。可以通过self.调用其他的对象方法
在类的外部,通过变量名.访问对象的属性和方法
在类封装的方法中,通过self.访问对象的属性和方法
初始化方法
。当使用类名()创建对象是,会自动执行一下操作
1.未对象在内存中分配空间——创建对象
2.为对象的属性设置初始值——初始化方法(init)
。这个初始化方法就是__init__ 方法,__init__ 是对象的内置方法
init方法是专门用来定义类具有哪些属性的方法
在初始化方法内部定义属性
。在init方法内部使用self.属性名 = 属性的初始值就可以定义属性
。定义属性之后,在使用类创建的对象,都会拥有该属性
在开发中,如果希望在创建对象的同时,就设置对象的属性,可以对init方法改造
格式如下:
class 类: def __init__(self, name): print("初始化方法 %s" % name) self.name = name
Python中,当一个对象被从内存中销毁前,会自动调用del方法
__str__方法
在Python中,使用print输出对象变量,默认情况下,会输出这个变量引用的对象,是由哪个类创建的对象,以及在内存中的地址
如果在开发中希望,使用print输出对象变量时,能够打印自定义的内容,就可以利用__str__这个内置方法
注意:__str__方法必须返回一个字符串
私有属性和私有方法
在实际开发中,对象的某些属性或方法可能只希望对象的内部使用,不希望在外部被访问到
定义方式
。在定义属性或方法时,在属性名或者方法名前,增加两个下划线,定义的就是私有属性或者方法
面向对象的三大特征
1.封装根据职责将属性和方法封装到一个抽象的类中
2.继承实现代码的重用,相同的代码不需要重复的编写
3.多态不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度
继承的概念
子类拥有父类的所有方法和属性
继承的语法
class 类名(父类名): pass
子类继承自父类,可以直接享受父类中已经封装好的方法,不需要再次开发
子类中应该根据职责,封装子类特有的属性和方法
继承的传递性
C类从B类继承,B类又从A类继承,那么C类就具有B类和A类的所有属性和方法
子类拥有父类以及父类的父类中封装的所有属性和方法
方法的重写
子类拥有父类的所有方法和属性
子类继承支付类,可以直接享受父类中已经封装好的方法,不需要再次开发
应用场景
当父类的方法无法实现子类需求时,可以对方法进行重写(override)
重写父类方法的两种情况:
1.覆盖父类的方法
2.对父类方法进行扩展
覆盖父类的方法
具体的实现方式,就相当于在子类中定义了一个和父类同名的方法并且实现
对父类方法进行扩展
。如果在开发中,子类方法实现中包含父类的方法实现,父类原本封装的方法实现是子类方法的一部分
。就可以使用扩展的访视
1.在子类中重写父类的方法
2.在需要的位置使用super().父类方法来嗲用父类方法的执行
3.代码其他的位置针对子类的需求,编写子类特有的代码实现
关于super
。在Python中super是一个特殊的类
。super()就是使用super类创建出来的对象
。最常使用的场景就是重写父类方式,调用在父类中封装的方法实现
父类的私有属性和私有方法
子类对象不能再自己的方法内部,直接访问父类的私有属性或私有方法
子类对象可以通过父类的共有方法间接访问到私有属性或私有方法
私有属性、方法是对象的隐私,不对外公开,外界以及子类都不能直接访问
私有属性、方法通常用于做一些内部的事情
多继承
概念
子类可以拥有多个父类,并且具有所有父类的属性和方法
语法:
class 子类名(父类名1, 父类名2): pass
提示:父类之间存在同名的属性或者方法,应该尽量避免使用多继承
新式类与旧式类
object是Python未所有对象提供的基类,提供有一些内置的属性和方法,可以使用dir函数查看
以object未基类的类是新式类
建议:如果没有父类,统一继承自object
class 类名(object): pass
多态
面对对象三大特征
1.封装:根据职责将属性和方法封装到一个抽象的类中,是定义类的准则
2.继承:实现代码的重用,相同的代码不需要重复的编写,是设计类的技巧
3.多态:不同的子类对象调用相同的父类方法,产生不同的执行结果,可以增加代码的灵活度
多态是以继承和重写父类方法为前提,是调用方法的技巧,不会影响到类的内部设计
类的结构
1.使用面向对象开发,第一步是设计类
2.使用类名()创建对象,创建对象的动作有两步,在内存中未对象分配空间,为对象初始化
3.对象创建后,内存中就有了一个对象的实实在在的存在——实例
因此,通常也会把:
1.创建出来的对象叫做类的实例
2.创建对象的动作叫做实例化
3.对象的属性叫做实例属性
在程序执行时:
1.对象各自拥有自己的实例属性
2.调用对象方法,可以通过self. 访问自己的属性,调用自己的属性
结论
每个对象都有自己独立的内存空间,保存各自不同的属性
多个对象的方法,在内存中只有一份,在调用方法是,需要把对象的引用传递到方法内部
类是一个特殊的对象
Python中一切皆对象:
class AAA:定义的类属于类对象
obj1 = AAA(): 属于实例对象
。在程序运行时,类同样会被加载到内存
。在Python中,类是一个特殊的对象——类对象
。在程序运行时,类对象在内存中只有一份,使用一个类可以创建出很多个对象实例
。除了封装实例的属性和方法外,类对象还可以拥有自己的属性和方法:类属性和方法
。通过类名.的方式可以访问类的属性或者调用类的方法

类属性和实例属性
类属性就是类对象中定义的属性,通常记录与这个类相关的特征
实例:
class Tool(object): # 使用赋值语句定义类属性 count = 0 def __init__(self, name): self.name = name Tool.count += 1 # 创建工具对象 tool = Tool("斧头") # 输出工具对象的总数 print(Tool.count)
属性的获取机制
。在Python中属性的获取存在一个向上查找机制

因此,要访问类属性有两种方式:
1.类名.类属性
2.对象.类属性(不推荐)
注意:
如果使用 对象.类属性 = 值 赋值语句,只会给对象添加一个属性,而不会影响到类属性值
类方法和静态方法
类方法
。类方法就是针对类对象定义的方法,在类方法内部可以直接访问类属性或者调用其他的类方法
语法如下
@classmethod def 类方法名(cls): pass
类方法需要用修饰器@classmethod来标识,第一个参数应该是cls
。由哪一个类调用的方法,方法内的cls就是哪一个类的引用
。这个参数和实例方法的第一个参数是self类似
通过类名,调用类方法,调用方法时,不需要传递cls参数
在方法内部
。可以通过cls.访问类的属性
。也可以通过cls.调用其他的类方法
示例:
class Tool(object): # 使用赋值语句定义类属性 count = 0 @classmethod def show_count(cls): print("工具的数量:%s" % cls.count) def __init__(self, name): self.name = name Tool.count += 1 # 创建工具对象 tool = Tool("斧头") tool2 = Tool("斧头") tool3 = Tool("斧头") # 调用类方法 Tool.show_count()
静态方法
。在开发时,如果需要在类中定义一个既不需要访问实例属性、方法,也不需要访问类属性、方法的方法,可以把这个方法封装成一个静态方法
语法如下:
@staticmethod def 静态方法名(): pass
。静态方法需要修饰器@staticmethod来标识,告诉解释器这是一个静态方法
。通过类名.调用静态方法
示例:
class Person(object): @staticmethod def run(): print("跑跑跑.....") # 通过类名.调用静态方法 Person.run()
单例
单例设计模式
设计模式是前人工作的总结和提炼,通常,被人们广泛流传的设计模式都是针对某一特定问题的成熟解决方法,使用设计模式是为了可重用代码,让代码更容易被他人理解、保证代码可靠性
单例设计模式
目的——让类创建的对象,在系统中只有唯一的一个实例,每次执行类名()返回的对象,内存地址是相同的
__new__方法
。使用类名()创建对象时,Python的解释器首先会调用new方法为对象分配空间
。__new__是一个有object基类提供的内置的静态方法,主要作用有两个:
在内存中为对象分配空间,返回对象的引用
Python的解释器获得对象的引用后,将引用作为第一个参数,传递给init方法
重写new方法的代码非常固定
。重写new方法一定要 return super.__new__(cls)
。否则Python的解释器得不到分配了空间的对象引用,就不会调用对象的初始化方法
。注意:new是一个静态方法,在调用时需要主动传递cls参数
new方法重写示例:
class Person(object): def __new__(cls, *args, **kwargs): # 1.创建对象时,new方法会被自动调用 print("创建对象,分配空间") # 2.为对象分配空间 instance = super().__new__(cls) # 3.返回对象的引用 return instance def __init__(self): print("初始化方法") # 创建对象 p = Person() print(p)
Python中的单例
单例——让类创建的对象,在系统中只有唯一的一个实例
1.定义一个类属性,初始值是None,用于记录单例对象的引用
2.重写__new__方法
3.如果类属性is None,调用父类方法分配空间,并在类属性中记录结果
4.返回类属性中记录的对象引用

示例:
class Person(object): #定义第一个被对象创建对象的引用 instance = None def __new__(cls, *args, **kwargs): # 1.判断类属性时候是空 if cls.instance is None: # 2.调用父类的方法,为第一个对象分配空间 cls.instance = super().__new__(cls) # 3.返回类属性保存的对象引用 return cls.instance # 创建对象 p1 = Person() p2 = Person() print(p1) print(p2) # 输出结果 <__main__.Person object at 0x004508F0> <__main__.Person object at 0x004508F0>
只执行一次初始化工作
在每次使用类名创建对象时,Python解释器都会自动调用init方法
想让初始化动作只被执行一次
办法:
1.定义一个类属性,记录是否执行过初始化动作,初始值为False
2.在init方法中,判断类属性,如果False就执行初始化动作
3.然后将类属性设置为True
示例:
class Person(object): # 定义类属性 flag = False def __init__(self): # 1.判断类属性是否执行过初始化动作 if Person.flag: return # 2.如果没有执行 print("初始化") # 3.修改类属性 Person.flag = True # 创建对象 p1 = Person() p2 = Person() # 输出 初始化
浙公网安备 33010602011771号