面向对象三大特性之一----继承
单继承:
子类拥有父类的所有方法和属性(子类只需封装自己特有的方法)
“”"
class Animal:
def eat(self):
print('吃')
def drink(self):
print('喝')
def run(self):
print('跑')
def sleep(self):
print('睡')
class Cat(Animal):
def call(self):
print('喵喵~')
class Hellokitty(Cat):
def speak(self):
print('我可以说日语~')
#创建猫对象
#fentiao = Cat()
#fentiao.eat()
#fentiao.drink()
#fentiao.run()
#fentiao.sleep()
#fentiao.call()
hk = Hellokitty()
hk.speak()
子类可以继承父类的所有属性和方法
hk.call()
继承的传递性,子类拥有父类的父类的属性和方法
hk.eat()
hk.drink()
hk.run()
hk.sleep()
Cat类是Animal类的子类,Animal类是Cat类的父类,Cat从Animal类继承
Cat类是Animal类的派生类,Animal类是Cat类的基类,Cat类从Animal类派生
当父类的方法不能满足子类的需求的时候,可以对父类的方法进行重写
1.覆盖父类方法
2.对父类方法进行扩展
"""
class Animal:
def eat(self):
print('吃')
def drink(self):
print('喝')
def run(self):
print('跑')
def sleep(self):
print('睡')
class Cat(Animal):
def call(self):
print('喵喵~')
class Hellokitty(Cat):
def speak(self):
print('我可以说日语~')
def call(self):
# 调用原本在父类中封装的方法
#Cat.call(self)
super().call() # 只在python3中支持
print('#@!#@!#@!')
hk = Hellokitty()
hk.speak()
hk.call()
"""
多继承
子类拥有一个父类叫做单继承
子类可以拥有多个父类,并且具有所有父类的属性和方法
例如:孩子会继承自己父亲和母亲的特性
"""
class A:
def test(self):
print('test 方法')
class B:
def demo(self):
print('demo 方法')
class D:
def haha(self):
print('!!!!!!!!!!!!')
class C(A,B,D):
"""多继承可以让子类对象,同时具有多个父类的属性和方法"""
pass
#
c = C()
c.test()
c.demo()
c.haha()
"""
多继承的注意事项:
问题的提出:
如果不同的父类中存在同名的方法,子类对象在调用方法时,会调用哪一个父类中的方法呢?
提示:开发时,应尽量避免这种容易产生混淆的情况
如果父类之间存在同名的属性或方法,因该尽量避免使用多继承
"""
class A:
def test(self):
print('A----test 方法')
def demo(self):
print('A----demo 方法')
class B:
def test(self):
print('B----test 方法')
def demo(self):
print('B----demo 方法')
class C(B,A):
pass
c = C()
c.test()
c.demo()
"""
新式类和旧式(经典)类:
object是Python为所有对象提供的基类,提供有一些内置的属性和方法,可以使用dir函数查看
新式类:以object为基类的类,推荐使用
经典类:不以object为基类的类,不推荐使用
在python3.X中定义的类时,如果没有指定父类,会默认使用object作为基类--python3.x中定义的类都是新式类
在python2.x中定义类时,如果没有指定父类,则不会以object作为基类
####推荐使用新式类#############
新式类和旧式类在多继承时---会影响到方法的搜索顺序
为保证编写的代码能够同时在python2.x和python3.x运行
今后在定义类时,如果没有父类,建议统一继承自object
super
class Parent(object):
def __init__(self,name):
print('parent的init开始被调用')
self.name = name
print('parent的init结束被调用')
class Son1(Parent):
def __init__(self,name,age):
print('Son1的init开始被调用')
self.age = age
Parent.__init__(self,name)
print('Son1的init结束被调用')
class Son2(Parent):
def __init__(self,name,gender):
print('Son2的init开始被调用')
self.gender = gender
Parent.__init__(self,name)
print('Son2的init结束被调用')
class Grandson(Son1,Son2):
def __init__(self,name,age,gender):
print('grandson的init开始被调用')
Son1.__init__(self,name,age)
Son2.__init__(self,name,gender)
print('grandson的init结束被调用')
gs = Grandson('grandson',18,'男')
print('姓名:',gs.name)
print('年龄:',gs.age)
print('性别:',gs.gender)
新式类:调用的顺序为广度优先
旧式类:调用顺顺序为深度优先
super()类:不重复的调用父类,解决了钻石继承(多继承)的难题
class Person(object):
def __init__(self):
print('我要好好学习')
def study(self):
print('我要好好学习语言')
class Man(Person):
def __init__(self):
print('我是男的我要好好学习')
def study(self):
print('我要学好数学')
#super().study()
class Womam(Person):
def __init__(self):
print('我是女的我要好好学习')
def study(self):
print('我要学好英语')
super().study()
class Son(Man,Womam):
def __init__(self):
print('我是儿子我要好好学习')
def study(self):
print('我要学好化学和物理')
#Womam.study(self)
#Man.study(self)
super().study()
print(Son.mro())
son1 = Son()
son1.study()
"""
super实现原理:通过c3算法,生成mro(method resolution order)列表,根据列表中元素顺序查询调用
super()不是指父类 而是指以实例化对象为起点的mro序列中的下一个
简洁点的三个原则就是:
子类在父类前,所有类不重复调用,从左到右
"""
class A():
def go(self):
print ("go A go!")
def stop(self):
print ("stop A stop!")
def pause(self):
raise Exception("Not Implemented")
class B(A):
def go(self):
super(B, self).go()
print ("go B go!")
class C(A):
def go(self):
super(C, self).go()
print ("go C go!")
def stop(self):
super(C, self).stop()
print ("stop C stop!")
class D(B,C):
def go(self):
super(D, self).go()
print ("go D go!")
def stop(self):
super(D, self).stop()
print ("stop D stop!")
def pause(self):
print ("wait D wait!")
class E(B,C):
pass
a = A()
b = B()
c = C()
d = D()
e = E()
私有属性和私有方法
应用场景及定义方式
应用场景
在实际开发中,对象的某些属性或方法可能只希望在对象的内部使用,而不希望在外部被访问到
私有属性 就是 对象 不希望公开的 属性
私有方法 就是 方法 不希望公开的 方法
定义方法
在定义属性或方法时,在属性名或者方法名前增加两个下划线,定义的就是私有属性或方法
class Women(object):
def __init__(self,name):
self.name = name
self.__age = 18
def __secret(self):
print('%s 的年龄是 %d' %(self.name,self.__age))
lily = Women('lily')
#print(lily.age)
lily.__secret()
实例
class Date(object):
def __init__(self,year,month,day):
self.year = year
self.month = month
self.day = day
# 实例方法(默认情况下会传递对象给echo方法)
def echo(self):
print('%s %s %s' %(self.year,self.month,self.day))
# 默认传递类本身给这个方法
@classmethod
def as_string(cls,s):
#print(cls)
month,day,year = s.split('/')
d = cls(year,month,day) # d = Date(2018,10,10)
return d
@staticmethod
def is_vaild(s):
# 批量将年月日转换成整型
# month,day,year = s.split('/')
# month,day,year = [int(i) for i in s.split('/')]
month,day,year = map(int,s.split('/'))
return 0<month<=12 and 0<day<=31 and 1<year< 9999
d = Date(2018,10,10)
print(d)
d.echo()
s = '10/10/2018'
print(Date.as_string(s))
print(Date.is_vaild(s))
d = Date(2018,10,10)
print(d.is_vaild('13/10/2019'))
一切皆对象
类也是一个特殊的对象–>类对象
类属性
类方法
“”"
“”"
需求:定义一个工具类
每件工具都有自己额名字
需要知道使用这个类,创建了多少个工具对象
“”"
class Tool(object):
# 1.使用赋值语句定义类属性,记录所有工具的数量
count = 0
def __init__(self,name):
self.name = name
# 让类属性的值 +1
Tool.count += 1
@classmethod
def show_tool_count(cls):
# cls.count 在类方法内部,访问当前的类属性
print('工具对象的数量 %d' %(cls.count))
创建工具对象(对象在创建的时候,会自动调用初始化方法)
#print(Tool.count)
tool1 = Tool('斧头')
#tool2 = Tool('榔头')
tool1.show_tool_count()
输出工具对象的属性
使用 类名.属性名 的方式来获取属性名
#print(Tool.count)
“”"
类是一个特殊的对象
Python中一切皆对象
class AAA: 定义的类属性属于类对象
obj1 =AAA: 属于实例对象
在运行程序时,类 同样会被加载到内存
在python中,类 是一个特殊的对象–类对象
在程序运行时,类对象(模板) 在内存中之有一份,使用一个类(模板)可以创建出很多个对象实例
除了封装 实例 的属性和方法外,类对象还可以有自己的属性和方法
1.类属性
2.类方法
通过 类名. 的方式可以直接访问类的属性或者调用类的方法
类方法需要用修饰器@classmethod来标示,告诉解释器这是一个类方法
类方法的第一个参数应该是cls
由哪一个类调用的方法,方法内的cls就是哪一个类的引用
这个参数和实例方法的第一个参数是self类似(哪一个对象调用的方法,self就是哪一个对象的引用)
通过类名调用类方法,调用方法时,不需要传递cls参数
在方法内部
也可以通过cls.访问类的属性
也可以通过cls.调用其他的类方法
静态方法
class Cat(object):
@staticmethod
def call():
print('喵~')
不需要创建对象,直接就可以使用
Cat.call()