面向对象三大特性
封装 继承 多态(面试题)
类(Class)
类就相当于制造飞机时的图纸,用它来进行创建的飞机就相当于对象。 类是对现实生活中一类具有共同特征的事物的抽象。
对象
对象相当于根据图纸造出来的飞机,看得见摸得着的。
类的具体化就是对象,类的实例就是对象。
类与对象之间的关系
例子:类——》一个玩具工厂生产玩具的模具
对象——》跟玩具模具生产出的各式各样的玩具
总结:类就是创建对象的模板
类的构成
类的名称:类名(比如:玩具模具)
类的属性:一些数据(比如:小人模具应该具有一个脑袋、一个身子、一个腿)
类的方法:可以进行的操作或者行为(比如:可以跑、可以发出声音)
设计一个类案例
狗类的设计:
类名(事物名称):狗类(dog)
属性(事物属性):年龄(age)、颜色(colour)
方法(事物行为/功能):跑(run)、跳(jump)
定义一个类
class 类名: 方法列表
注:类名规则通常按照“大驼峰”规则
demo
# 定义类 class Car: # 方法 def getCarInfo(self): print('车轮子个数:%d, 颜色%s'%(self.wheelNum, self.color)) def move(self): print("车正在移动...")
创建对象
对象名 = 类名()
demo
# 定义类 class Car: # 移动 def move(self): print('车在奔跑...') # 鸣笛 def toot(self): print("车在鸣笛...嘟嘟..") # 创建一个对象,并用变量BMW来保存它的引用 BMW = Car() BMW.color = '黑色' BMW.wheelNum = 4 #轮子数量 BMW.move() BMW.toot() print(BMW.color) print(BMW.wheelNum)
注:通常直接打印对象名称会获得对象所在内存地址
__init__()方法
使用方法
def 类名: def __init__(): pass
调用方法
# 定义汽车类 class Car: def __init__(self): self.wheelNum = 4 self.color = '蓝色' def move(self): print('车在跑,目标:夏威夷') # 创建对象 BMW = Car() print('车的颜色为:%s'%BMW.color) print('车轮胎数量为:%d'%BMW.wheelNum)
总结
__init__()在创建一个对象时自动调用,不需要手动进行调用
__init__(self)其中的self参数为默认参数,不需要传递参数,一般理解为,对象自己
__str__()方法
根据上文所述如果直接打印实例对象将获得其所在内存地址,如果其转为str,就需要用到__str__()方法,使用此方法所返回的数据即为打印打印实例对象获得数据。
定义__str__()
class Car: def __init__(self, newWheelNum, newColor): self.wheelNum = newWheelNum self.color = newColor def __str__(self): msg = "嘿。。。我的颜色是" + self.color + "我有" + int(self.wheelNum) + "个轮胎..." return msg def move(self): print('车在跑,目标:夏威夷') BMW = Car(4, "白色") print(BMW)
总结
一般格式为__XXX__()的方法都为魔法方法,基本都具有一些特殊的功能。
如果定义了__str__()方法后,进行打印其实例对象,将会出现__str__()return返回的数据
self
解释self
self我对其的理解就是自己,就是对象本身,当python调用某对象的方法时,python会默认将把对象作为第一个参数传入self,开发者只需要传递后面的参数即可
私有属性
在类内部进行调用self.__name。
私有方法
def __jump()两个下划线开头,生命方法为私有方法,不能在类地外访问或者直接使用
在类内部进行调用self.__jump()
__del__()方法
当创建一个对象时,python解释器会默认调用一个方法__del__()当删除对象时会自动调用
import time class Animal(object): # 初始化方法 # 创建完对象后会自动被调用 def __init__(self, name): print('__init__方法被调用') self.__name = name # 析构方法 # 当对象被删除时,会自动被调用 def __del__(self): print("__del__方法被调用") print("%s对象马上被干掉了..."%self.__name) # 创建对象 dog = Animal("哈皮狗") # 删除对象 del dog cat = Animal("波斯猫") cat2 = cat cat3 = cat print("---马上 删除cat对象") del cat print("---马上 删除cat2对象") del cat2 print("---马上 删除cat3对象") del cat3 print("程序2秒钟后结束") time.sleep(2)
结果
注意
当有1个变量保存了对象的引用时,此对象的引用计数就会加1
当使用del删除变量指向的对象时,如果对象的引用计数不会1,比如3,那么此时只会让这个引用计数减1,即变为2,当再次调用del时,变为1,如果再调用1次del,此时会真的把对象进行删除
继承的概念
注:在程序中,继承描述的是事物之间的所属关系,例如猫和狗都属于动物,程序中便可以描述为猫和狗继承自动物;同理,波斯猫和巴厘猫都继承自猫,而沙皮狗和斑点狗都继承足够,如上所示
简单来说某个类具备另一个的能力(属性和功能)
继承
格式
class 子类名:(父类名)
demo
class Animal: def eat(self): print("-----吃-----") def drink(self): print("-----喝-----") class Dog(Animal): """ def eat(self): print("-----吃-----") def drink(self): print("-----喝-----") """ pass class Cat: pass wang_cai = Dog() wang_cai.eat() wang_cai.drink()
子类新增功能
当子类需要增加新功能时候,且若不想失去父类的的某些功能,只需在定义类的方法时候,选择一个与父类方法名中不同的命名即可,若选择一个与父类方法名相同的命名即取消此父类方法的继承,在子类新增的方法替代其继承方法。
demo
class Animal: def eat(self): print("-----吃-----") def drink(self): print("-----喝-----") class Dog(Animal): def bark(self): print("-----汪汪叫------") class Cat(Animal): def catch(self): print("----捉老鼠----") wang_cai = Dog() wang_cai.eat() wang_cai.drink() wang_cai.bark() jia_fei = Cat() jia_fei.eat() jia_fei.drink() jia_fei.catch()
多层继承
多层继承为 孙类继承子类继承父类乃至更多层的类方法与类属性等demo
class Animal:
def eat(self):
print("-----吃-----")
def drink(self):
print("-----喝-----")
class Dog(Animal):
def bark(self):
print("-----汪汪叫------")
class XTQ(Dog):
"""定义了一个哮天犬 类"""
pass
class Cat(Animal):
def catch(self):
print("----捉老鼠----")
xtq = XTQ()
xtq.eat()
xtq.bark()
重写父类方法 #重点
子类重写了父类方法,子类再调用该方法将不会执行父类的处理
如果想在多继承中调用指定继承父类的中的方法
注:寻找输入参数——》当前类继承链的下一个类的
demo
class Dog(object): def __init__(self): self.clour = '黑色' class BlackDog(Dog): def __init__(self): super().__init__() self.cook = '炒菜' test = BlackDog() print(test.clour)结果
>>黑色
demo
class Animal: def eat(self): print("-----吃-----") def drink(self): print("-----喝-----") class Dog(Animal): def bark(self): print("-----汪汪叫------") class XTQ(Dog): """定义了一个哮天犬 类""" def bark(self): print("----嗷嗷叫-----") class Cat(Animal): def catch(self): print("----捉老鼠----") xtq = XTQ() xtq.eat() xtq.bark()
调用被重写的父类方法
子类重写了父类方法,仍然想执行父类中的方法,则可以在类中使用super()来调用方法
super()会寻找上一级的父类
demo
class People: def __init__(self): self.name = "人" class Student(People): def __init__(self): # 重写了父类的init方法 super().__init__() # 不调用父类的init,父类的name属性就不会被定义 self.age = 10 # self.name = "学生" def stu_info(self): print("%s: %s" % (self.name, self.age)) xiaoming = Student() xiaoming.info() # 打印结果: 人: 10
私有方法、属性,继承问题
class Animal(object): def __init__(self): self.num1 = 1 self.__num2 = 2 def __run(self): print("----跑---") def eat(self): print("-----吃-----") def drink(self): print("-----喝-----") def test(self): print(self.__num2) self.__run() class Dog(Animal): def bark(self): print("-----汪汪叫------") # self.__run() # 父类中的私有方法,没有被子类继承 print(self.num1) # print(self.__num2) # 父类中的私有属性,没有被子类继承 wang_cai = Dog() wang_cai.bark() wang_cai.test()
多继承
从图中能够看出,所谓多继承,即子类有多个父类,并且具有它们的特征
demo
# 定义一个父类 class A: def printA(self): print('----A----') # 定义一个父类 class B: def printB(self): print('----B----') # 定义一个子类,继承自A、B class C(A,B): def printC(self): print('----C----') obj_C = C() obj_C.printA() obj_C.printB()
运行结果
----A---- ----B----
多继承链查询
类名.__mro__用来查看多继承链的组成关系
调用指定类方法
总结
父类中的方法、属性,子类会继承
多态(容易懵逼的位置)
自我理解:
如果不同的子类,同时调用一个相同父类方法,能够产生不同执行结果即为多态
demo:
#父类 class Dog(object): #父类方法 def Activity(self): pass class BlackDog(Dog): #方法1. # def jump(self): # print('----可劲跳----') #方法2 def Activity(self): print('----可劲跳----') class RedDog(Dog): #方法1. # def run(self): # print('----可劲跑----') #方法2 def Activity(self): print('----可劲跑----') dog1 = BlackDog() dog2 = RedDog() def LetGo(dog): ''' 方法2写法相对于方法2更灵活自由,增加代码外部调用的灵活度 方法1.在工程中如果新增一个子类,在Let中进行调用会涉及到增加代码 方法2.多态是利用调用方法,实现代码的更自由,不会影响的内部结构设计 主要核心为继承与重写 ''' #调用方法1. #dog1.jump() #dog2.run() #调用方法2 dog.Activity() LetGo(dog2)
懵逼的理解:
多态:使用父类的地方,可以使用子类对象代替 多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚“鸭子类型”。所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态
Python伪代码实现Java或C#的多态
Python “鸭子类型”
鸭子类型语言中,函数/方法可以接受一个任意类型的对象作为参数/返回值,只要该对象实现了代码后续用到的属性和方法就 不会报错
类属性
特点为节约内存,一般应用于对象属性的某个记录数据始终保持一致的情况下,就会定义类属性。
类属性与实例属性的区别在于,通常每创建一个实例属性的情况下都会开辟一块内存空间来单独存储此实例属性的数据,而类属性为所有实例属性通用,仅占用一块内存空间,更加节省空间。
注意点
避免类属性与对象属性重名,修改类属性只能用类对象进行修改,不能用实例对象进行修改。
实例对象优先访问对象属性,使用实例进行类属性修改无法修改成功并且会新定义一个对象属性
类属性也可以进行私有设置同样也是加入__下划线
demo
class Dog(object): Type = '小狗' # 类属性 def __init__(self): self.name = '旺财' # 对象属性 huahua = Dog() print(huahua.name) print(huahua.Type) Dog.Type = '大狗' # 修改类属性 print(huahua.Type)返回
旺财 小狗 大狗