python面向对象
1.面向过程与面向对象
面向过程就是先分析出解决问题的步骤,再把步骤拆分成一个个方法,是没有对象去调用的,通过一个个方法的执行解决问题
面向对象就是将编程当成是一个事务(对象),对外界来说,事务是直接使用的,不用去管内部的情况,而编程就是设置事物能做什么事情。
面向对象三大特性:封装,继承,多态
2.类和对象
类:对一系列具有相同属性和行为的事务的统称,是一个抽象的概念,并不是真实存在的事物。
对象是类的具体实现,是创建出来的真实存在的事物,面对对象思想的核心。
在开发中,先有类,再有对象。
2.1类的三要素
1.类名
2.属性:对象的特征描述,用来说明是什么样子的
3.方法:对象具有的功能(行为),用来说明能够做什么
2.2定义类
基本格式:
class 类名:代码块
注意:类名要符合标识符规定,同时遵循大驼峰命名法,见名知意。
查看类属性:类名.属性名
新增类属性:类名.属性名 = 值
class Washer:height = 800 #类属性print(Washer.height)
Washer.width = 450
print(Washer.width)
2.3创建对象
创建对象的过程也叫做实例化对象
一个类可以实例化多个对象。
实例化对象基本格式:对象名 = 类名()
class Washer:height = 800 #类属性print(Washer.height)
Washer.width = 450
print(Washer.width)wa1 = Washer()
print(wa1) #<__main__.Washer object at 0x0000029698DC0B48>显示的对象内存中的地址
wa2 = Washer()
print(wa2) #<__main__.Washer object at 0x0000022494490C48>显示地址不同
2.4实例方法和实例属性
2.4.1实例方法
由于对象调用,至少有一个self参数,执行实例方法的时候,自动将调用该方法的对象赋值给self
self就是实例化出来的使用该方法的对象,当对象调用实例化方法时,python会自动将对象本身的引用作为参数,传递到实例化方法的第一个参数self里面
class Washer:height = 800 #类属性def wash(self): #self参数是类中的实例方法必需具备的print("洗衣服")print("self",self) #<__main__.Washer object at 0x0000018536A60DC8>
#实例化对象
wa1 = Washer()
wa1.wash()
print(wa1) #<__main__.Washer object at 0x0000018536A60DC8>wa2 = Washer()
wa2.wash()
2.4.2实例属性
格式:self.属性名
实例属性和类属性的区别:类属性属于类,是公共的,大家都能访问到,实例属性是属于对象的,是私有的,只能由对象名访问到,不能由类名访问。
class Person:name = 'panda' #类属性def introduce(self): #实例方法print("我是实例方法")print(f"{Person.name}的年龄是:{self.age}") #self.age实例属性
pe = Person()
pe.age = 5 #对实例属性进行传值
pe.introduce() #panda的年龄是:5
pe.sex = '女' #实例属性
print(pe.sex)
#print(Person.sex)
print(pe.age)
#print(Person.age)
实例属性,每实例化一次就需要添加一次,效率不高,就引入构造函数
3.构造函数 __init__()
作用:通常用来做属性初始化或者赋值操作
注意:在实例化对象的时候会被自动调用(所以传参的时候在实例化对象的时候进行传参)
class Person:def __init__(self,name,age,height):self.name = nameself.age = ageself.height = heightdef play(self):print(f"{self.name}正在学python")def introduce(self):print(f"{self.name}的年龄是{self.age}岁,身高是{self.height}cm")#实例化对象
pe1 = Person('panda',5,67)
pe1.introduce()
pe1.play()pe1 = Person('monkey',9,53)
pe1.introduce()
pe1.play()
4.析构函数__del__()
删除对象的时候,解释器会默认调用__del__()方法
class Person:def __init__(self):print("我是构造函数")def __del__(self):print("创建的对象被销毁")p = Person()
print("这是最后一行代码")
在代码执行完之后对象被销毁
也可以提前自己销毁del p 被执行时,内存会立即回收,会调用对象本身
class Person:def __init__(self):print("我是构造函数")def __del__(self):print("创建的对象被销毁")p = Person()
del p
print("这是最后一行代码")
注意:正常执行时不会调用__del__(),对象执行结束后,系统会自动调用__del__()方法
__del__()主要是表示该程序块或者函数已经全部执行结束。
5.封装
面向对象三大特性:封装,继承,多态
5.1封装:指的是隐藏对象中一些不希望被外部所访问到的属性或者方法
5.2隐藏属性(私有权限):只允许在类的内部使用,无法通过对象访问
格式:在属性名或者方法名前面加上两个下划线__
两种查看隐藏属性的方法:
1.隐藏属性实际上时将名字修改为:_类名__属性名
可以通过这种形式进行查看或者修改
2.在类的内部访问(在实例方法中访问隐藏属性,通过查看实例方法查看隐藏属性)--正规手段,推荐使用
class Person:name = 'panda' #类属性__age = 5 #隐藏属性def introduce(self):print(f"{Person.name}的年龄是{Person.__age}") #在实例方法中访问类属性和隐藏属性pe = Person()
print(pe.name)
print(pe._Person__age)pe.introduce()
5.3私有属性
1.xxx:普通属性/方法,如果是类中定义的可以在任意地方使用
2._xxx:单下划线开头,声明私有属性/方法,如果定义在类中,外部可以使用,子类也可以继承,但是在另一py文件中通过from xxx import*导入时,无法导入
一般是为了避免与python关键字冲突而采用的命名方法
3.__xxx:双下划线开头,隐藏属性,如果定义在类中,外部无法直接访问,子类不会继承,要访问只能通过间接方式,另一个py文件中通过from xxx import*导入时,无法导入
这种命名一般是python中的魔术方法或属性,都是有特殊含义或者功能的,自己不要轻易定义
class Person:name = 'panda'__age = 18_sex = '女'p = Person()
print(p._sex)
5.4隐藏方法
也有两种查看方式
class Person:name = 'panda'__age = 18_sex = '女'def __play(self):print("学python")def funa(self):print("普通实例方法")Person.__play(self) #在实例方法中调用私有方法 --不推荐self.__play() #--推荐p = Person()
p.funa()
5.5私有方法
class Person():def _buy(self):print("买买买")p = Person()
p._buy()
6.继承
6.1继承:就是让类和类之间转变为父子关系,子类默认继承父类的属性和方法
继承分为单继承和多继承
6.2语法:
class 类名(父类名):代码块
class Person:def eat(self):print("会吃饭")def sing(self):print("会唱歌")class Girl(Person):pass #占位符 代码里面不写任何东西会自动跳过
girl = Girl()
girl.sing()
girl.eat()
总结:子类可以继承父类的属性或方法,就算子类没有也可以继承父类的
6.3继承的传递(多重继承)
子类拥有父类的父类的属性或方法
A/B/C C(子类)继承B(父类),B(子类)继承A(父类),C具有A/B的属性和方法
class Father:def eat(self):print("吃饭")def sleep(self):print("睡觉")
class Son(Father):pass
class Grandson(Son):pass
grandson = Grandson()
grandson.eat()
grandson.sleep()
6.4.方法的重写
含义:如果父类继承的方法不能满足子类的需求,可以在子类中重写父类方法,这个过程称为方法的覆盖,也称为方法的重写
class Father:def money(self):print("100万需要被继承")
class Son:def money(self):print("自己赚一千万")son = Son()
son.money()
实现对父类方法进行扩展的三种形式:
1.父类名.方法名(self)
2.super().方法名() --推荐
3.super(子类名,self).方法名()
super在python中是一个特殊的类,super()是使用super类创建出来的对象,可以调用父类中的方法
class Father:def money(self):print("100万需要被继承")
class Son(Father):def money(self):#Father.money(self)#super(Son,self).money()super().money()print("自己赚一千万")son = Son()
son.money()
6.5新式类写法:
6.5.1class A: 经典类写法,不由任何内置类型派生出来的类
派生类:有不同于父类的属性或方法
6.5.2class A()
6.5.3class A(object):新式类,继承了object类或者该类的子类都是新式类 --推荐
object--对象,python为所有对象提供的基类(顶级父类),提供了一些内置的属性或方法,可以使用dir()查看
python3中如果一个类没有继承任何类,就默认继承object类,因此python3都是新式类
6.5多继承:
子类可以同时拥有多个父类,并且具有所有父类的属性和方法
class Father:def money(self):print("100w")
class Mother:def money(self):print("1000w")def appearance(self):print("美貌")
class Son(Father,Mother):pass
son = Son()
son.money() #100w
son.appearance() #美貌
6.5.1不同父类存在同名:开发时要尽量避免这种情况,要是有多个父类的属性和方法重名时,调用就近原则,括号离哪个近,就优先调用哪一个
6.5.2方法的搜索顺序
python中内置的属性__mro__可以查看方法的搜索顺序
搜索方法时,会先按照__mro__输出的结果,从左往右顺序查找,如果在当前类中找到了方法,就直接执行,不搜索,如果找到最后一个类还没找到就会报错
多继承的弊端:容易引发冲突,会导致代码设计的复杂度增加
7.多态
7.1多态:指同一种行为duotaide具有不同的表现形式
7.2多态的前提:继承,重写
7.3多态的特点:
1.不关注对象的类型,关注对象的行为,也就是对象的实例方法是否同名
2.多态的好处可以增加代码的外部调用灵活度,让代码更加通用,兼容性比较强
3.不同的子类对象,调用相同的父类方法,会产生不同的执行结果
class Animal(object):"""父类:动物类"""def shout(self):print("动物会叫")class Cat(Animal):"""子类:猫类"""def shout(self):print("喵喵喵")class Dog(Animal):"""子类:狗类"""def shout(self):print("汪汪汪")cat = Cat()
cat.shout()
dog = Dog()
dog.shout()
7.4多态性:一种调用方法,不同的执行结果
class Animal(object):"""父类:动物类"""def shout(self):print("动物会叫")class Cat(Animal):"""子类:猫类"""def shout(self):print("喵喵喵")class Dog(Animal):"""子类:狗类"""def shout(self):print("汪汪汪")def test(obj):obj.shout()animal = Animal()
cat = Cat()
dog = Dog()
test(animal)
test(cat)
test(dog)
多态性:定义一个统一的接口,一个接口多种实现
test传入不同的对象,执行不同对象的eat方法
8.静态方法
使用@staticmethod来进行修饰,静态方法没有self,cls参数的限制,静态方法与类无关,可以转换成函数使用
定义格式:
class 类名:
@staticmethod
def 方法名(形参)
方法体
调用格式:
类名.方法名(形参)
对象名.方法名(形参)
(静态方法既可以使用对象访问,也可以使用类访问)
class Person:@staticmethod #静态方法def study():print("人会学习")Person.study()
pe = Person()
pe.study()
调用对象时传入参数:
class Person:@staticmethod #静态方法def study(name):print(f"{name}会学习")Person.study('panda')
pe = Person()
pe.study('panda')
取消不必要的参数传递,有利于减少不必要的内存占用和性能消耗
9.类方法
使用装饰器@classmethod来标识为类的方法,第一个参数必须是类对象,一般为cls
cls代表类对象本身,类本质上就是一个对象
格式:
class 类名:
@classmethod
def 方法名(形参)
方法体
class Person(object):name = 'panda'@classmethoddef sleep(cls):print(cls) #<class '__main__.Person'>print("人在睡觉")print(Person.name)print(cls.name)
print(Person) #<class '__main__.Person'>
Person.sleep()
类方法内部可以访问类属性或者调用其他的类方法
当方法中需要使用到类对象(如访问私有类属性等),定义类方法
类方法一般配合类属性使用
总结:1.实例方法:方法内部访问实例属性,方法内部可以通过类名.类属性名来访问类属性
2.静态方法@staticmethod:方法内部,不需要访问实例属性和类属性
如果要访问类属性,通过类名.类属性名访问(但没有意义),不能访问实例属性
3.类方法(针对类存在的方法)@classmethod:方法内部只需要访问类属性,可以通过cls.类属性名访问类属性,不能访问实例属性
类属性是公共的,所有方法内部都能访问得到,静态方法不需要访问类属性,因为静态方法和类,对象没有关联。实例属性是私有的,只有实例方法内部能访问得到