面向对象
面向对象三大特点
封装:既是对数据封装,又是对处理数据的方法的封装
继承:强调的是父子类之间的关系
多态:不同的对象调用相同的方法,有不同的响应。
类的继承
相关概念
继承:父类的属性和方法,子类直接拥有,称为继承。
派生:子类在父类的基础上衍生出新的特征(属性和行为)
总结:其实他们是一回事,只是描述问题的侧重点不同(继承侧重相同点,派生侧重不同点)
可以简单理解 儿子 相对于父亲 可以对父亲的家产创新
也可以变卖 可以取其精华取其糟粕 可以青出于蓝而胜于蓝
QAQ
继承语法
# class Animal:
# 当没有写父类时,默认继承自object
# 定义一个动物类
class Animal(object):
def __init__(self, name):
self.name = name
def run(self):
print('小动物们一天到晚到处乱跑')
# 狗 继承自 动物 狗也是动物
class Dog(Animal):
def eat(self):
print('小狗喜欢啃骨头')
# 创建一个狗 对象
d = Dog('旺财')
# 继承的属性
print(d.name)
# 继承的方法
d.run()
# 添加新的属性
d.age = 2
# 添加的方法
d.eat()
方法重写
当对于父类的方法不满意的时候 可以进行重写
重写之后 父类的方法就会失效 自己重写的方法生效
class Aniaml:
def eat(self):
print('小动物都喜欢吃东西')
def run(self):
print('小动物喜欢跑个不停')
class Cat(Aniaml):
# 完全不合适,覆盖重写
def run(self):
print('猫喜欢走猫步')
# 不完全合适,需要修改完善
def eat(self):
# 调用父类的方法
# Aniaml.eat(self) # 不建议使用
# super(Cat, self).eat() # 老的写法
super().eat() # 新的写法,推荐
print('猫喜欢吃鱼')
c = Cat()
c.eat()
c.run()
多继承
一个类可以有多个父类,即可以拥有多个类的特征
class A:
def eat(self):
print('eat func in class A')
class B:
def run(self):
print('run func in class B')
def eat(self):
print('eat func in class B')
class C(A, B):
def eat(self):
# 这样写会按照默认顺序查找父类的方法
# super().eat()
# 可以明确指定调用哪个父类的方法
B.eat(self)
c = C()
c.eat()
c.run()
继承链
class A(object):
def foo(self):
print('A foo')
class B(object):
def foo(self):
print('B foo')
def bar(self):
print('B bar')
class C1(A, B):
pass
class C2(A, B):
def bar(self):
print('C2-bar')
class D(C1, C2):
pass
d = D()
d.foo()
d.bar()
# __mro__类属性,记录了继承链的查找顺序
# 一旦找到,立即停止并返回
# 按照广度优先的原则进行查找
for i in D.__mro__:
print(i)
访问权限
class Person:
def __init__(self, name, age):
self.name = name
# 定义私有属性
self.__age = age
p = Person('王大花', 18)
# 公有属性:可以在类外使用
print(p.name)
# 私有属性:不能再类外使用
# print(p.__age)
# 实现原理:私有属性默认会在前面加 '_类名' 前缀
# 可以通过下面的方式访问私有属性,但是强烈不建议
# print(p._Person__age)
print(p.__dict__)
class Man(Person):
def introduce(self):
# 可以在子类中使用
print(self.name)
# 也不能在子类中使用
# print(self.__age)
m = Man('二狗', 20)
m.introduce()
总结
公有属性:在类的内部、外部、子类中都可以使用
私有属性:只能在类的内部使用,类外及子类中都不能使用
实现原理:默认在’_'开头的属性前添加’类名’的前缀
类属性
class Person:
# 类属性
nation = 'china'
# 限制对象可以使用的属性,可以提升访问效率
# 只可以使用这么多
__slots__ = ('name', 'age')
def __init__(self, name):
# 成员属性
self.name = name
xiaoming = Person('小明')
xiaohong = Person('小红')
print(xiaoming.name)
print(xiaohong.name)
# 查看对象的类名
print(xiaoming.__class__)
# 通过类名进行访问
print(Person.nation)
# 查看类的名字
print(Person.__name__)
# 查看父类元组
print(Person.__bases__)
# 类相关的信息
print(Person.__dict__)
# 查看继承链顺序
print(Person.__mro__)
xiaoming.age = 20
# 不能添加,因为没有在Person.slots类属性中
# xiaoming.height = 180
# 显示对象能够使用的属性
print(Person.__slots__)
类方法
class Person:
# 成员方法:通过对象调用
def eat(self):
print('能吃是福')
# 类方法:通过类名调用
@classmethod
def test(cls):
# cls:表示当前类
print(cls)
# 可以创建对象 或 简单的创建对象
@classmethod
def create(cls):
p = cls()
p.age = 1
return p
p = Person()
p.eat()
Person.test()
p2 = Person.create()
print(p2)
p2.eat()
作用:
可以创建对象 或 简洁的创建对象
可以对外提供简单易用的接口
静态方法
class Person:
# 定义静态方法:也是通过类名调用,但是没有第一个表示当前类的参数
@staticmethod
def test():
print('静态方法 test')
# 可以创建对象
@staticmethod
def create():
return Person()
class Man(Person):
@staticmethod
def test():
# 无法使用super调用父类方法
# 只能通过类名调用
Person.test()
Person.test()
p = Person.create()
print(p)
Man.test()
总结
方式可以静态方法解决的问题都可以使用类方法进行解决
静态方法中无法使用super
静态方法中没有cls参数
多态特性
说明:不同的对象调用相同的方法,有不同的响应
示例:
class Animal:
def run(self):
print('小动物走路姿势各不相同')
class Dog(Animal):
def run(self):
print('狗喜欢撒欢疯跑')
class Cat(Animal):
def run(self):
print('猫走的是猫步')
def func(obj):
# 判断某个对象是否拥有某个属性
if hasattr(obj, 'run'):
obj.run()
else:
print('类型有误')
func(Dog())
func(Cat())
对象支持字典操作
说明:将对象当做字典操作时,会自动触发相关的魔术方法
示例:
class Person:
# 当做字典操作:设置属性时
def __setitem__(self, key, value):
# print(key, value)
self.__dict__[key] = value
# 当做字典操作:获取属性时
def __getitem__(self, item):
# print(item)
return self.__dict__.get(item)
# 当做字典操作:删除属性时
def __delitem__(self, key):
# print(key)
self.__dict__.pop(key)
# del self.__dict__[key]
p = Person()
# p.name = '大花'
p['name'] = '大花'
# print(p.name)
print(p['name'])
# del p.name
del p['name']
print(p.dict)