面向对象三大特性:封装、继承、多态
1. 面向对象 VS 面向过程
面向对象是一种抽象化的编程思想
- 面向过程:关注处理过程,代表语言:C
 - 面向对象:关注谁来做,是将编程当成是⼀一个事物,对外界来说,事物是直接使⽤的,不用去管他内部 的情况, 代表语言:Python, Java, C++
 
2. 类 VS 实例(对象)
- 类:具有相同属性/行为的事物的统称;
 - 对象:是类创建出来的真实存在的事物;
 
3. 类的创建
- 经典类 class 类名:
 - 新式类 class 类名(父类1, 父类2 ……)
 
# 经典类
class Cat:
    代码...
# 新式类
class Dog():
    代码...
- 类名遵循标识符规则
    
- 字母/数字/下划线
 - 不以数字开头
 - 不能使用Python关键字
 - 大小写区分
 
 - 命名遵循大驼峰命名方式
 
4. 对象创建
对象名 = 类()
husky = Dog()
print(husky)
husky.wash()
- 判断两个对象是否一样
    
- 使用 is 关键字: dog1 is dog2
 - 直接 打印对象地址比较
 
 - self: 指的是调⽤用该函数的对象。
 
# 1. 定义类 
class Washer():
  def wash(self):
    print('我会洗⾐服')
    # <__main__.Washer object at 0x0000024BA2B34240> 
    print(self)
  
# 2. 创建对象
haier1 = Washer()
# <__main__.Washer object at 0x0000018B7B224240> 
print(haier1)
# haier1对象调⽤用实例方法
haier1.wash()
haier2 = Washer()
# <__main__.Washer object at 0x0000022005857EF0> 
print(haier2)
注意: 打印对象和self得到的结果是⼀致的,都是当前对象的内存中存储地址。
5. 添加/获取对象属性
- 类外⾯添加对象属性
    
haier1.width=500 haier1.height=800 - 类外⾯获取对象属性: 对象名.属性名
 - 类里面获取对象属性: self.属性名
 
# 定义类
class Washer():
  def print_info(self):
    # 类⾥面获取实例例属性 
    print(f'haier1洗衣机的宽度是{self.width}') 
    print(f'haier1洗⾐机的⾼度是{self.height}')
# 创建对象
haier1 = Washer()
# 添加实例例属性 
haier1.width = 500 
haier1.height = 800
haier1.print_info()
6. 魔法方法
- 形如__xxx__形式的方法
 - 魔法方法是python内置方法,不需要主动调用
 - 存在的目的是为了给python的解释器进行调用,几乎每个魔法方法都有一个对应的内置函数,或者运算符,当我们对这个对象使用这些函数或者运算符时就会调用类中的对应魔法方法,可以理解为重写内置函数。
 
class Star():
    # 创建对象
    def __new__(cls, *args, **kwargs):
        return super().__new__(cls)
    # 初始化属性
    def __init__(self, name='', movie=''):
        self.name = name
        self.movie = movie
    # print输出对象时,打印从 在这个⽅方法中 return 的数据
    def __str__(self):
        return f'{self.name}是我的偶像,我非常喜欢他的电影{self.movie}'
    # 删除对象时(严格讲是对象声明周期结束),python解释器器也会默认调⽤用 __del__() ⽅方法。
    def __del__(self):
        print(f'我不再喜欢{self.name}了')
    # 交互式环境或容器中包含对象时,显示对象的描述信息
    def __repr__(self)
      return 'repr'
7. 继承
- 子类继承默认继承父类的属性和方法
 
class Animal():
    def run(self):
        pass
class Horse(Animal):
    def eat(self):
        pass
    def run(self, a):
        print('迈着矫健的步伐跑起来')
- 单继承:一个子类只继承一个父类
 - 多继承:一个子类继承多个父类
 - 子类重写父类的同名方法和属性, 默认优先调用子类的方法
 - super()⽅法快速调用⽗类方法
 
class Master(object):
    def __init__(self):
        self.kongfu = '古法方法'
    def print_info(self):
        print(f'使用{self.kongfu}制作煎饼')
class School(object):
    def __init__(self):
        self.kongfu = '新方法'
    def print_info(self):
        print(f'使用{self.kongfu}制作煎饼')
# 这里继承 Master 和 School 两个父类
class Prentice(Master, School):
    def __init__(self):
        self.kongfu = '自创方法'
        self.__money = 10
    def print_info(self):
        # 如果先调用了父类的方法和属性,父类会覆盖子类属性,所以在调用属性前,先调用自己的子类初始化 
        self.__init__()
        print(f'使用{self.kongfu}制作煎饼')
    def make_master_cake(self):
        # 使用类名的缺陷: 1 代码冗余 2 耦合性高,如果父类名称更改,则这里需要修改
        # Master.__init__(self)
        # Master.print_info(self)
        # 注意:多继承情况下,super() 默认只使用第一顺位的父类 (__mro__()方法第一个父类)
        # super的第一种方式:super(当前类名, self).方法名
        # super(Prentice, self).__init__()
        # super(Prentice, self).print_info()
        # super的第二种使用方式:super().方法名
        super().__init__()
        super().print_info()
    def make_school_cake(self):
        School.__init__(self)
        School.print_info(self)
8. 私有权限
- 私有权限的作用:设置某个属性或方法不继承给子类,也不允许实例直接使用;
 - 设置私有权限的方法:在属性名和方法名前面加上两个下划线’__xxx’
 - 注意:python中的私有权限是伪私有,只是给属性名换了个名字,可以使用 实例._类名__xxx来直接调用;
 - 另外,可以使用get_xx或set_xx来修改私有属性值;
 
def set_money(self, money):
    self.__money = money
    
def get_money(self):
    return self.__money