part5 - 面向对象入门

本周内容:这周就四天,主要介绍面向对象入门。

day1: 面向对象编程基础

1. 面向对象编程介绍: 对象/类

  1. 面向过程
    1. 主要是将程序流程化,流水线,分步骤解决问题。
  2. 面向对象
    1. 对象就是“容器”,整合体,数据+功能。
      1. 学生容器 = 学生数据 + 学生功能
      2. 课程容器 = 课程容器 + 课程功能
    2. 这样扩展功能,直接找到容器即可。
    1. 也是容器,用来存放 数据 + 功能。

2. 面向对象编程

  1. 类的定义与实例化:

    1. 类的定义,可以放任何函数。
    2. 类体的代码在定义的时候就会执行。
    3. 只有函数体代码在调用阶段才会运行。
  2. 属性访问

    1. Student.__dict__

    2. 一个字典,里面是Student类的所有成员和方法。(****)

    3. . 点号访问类的属性
      python的成员、方法都叫属性。都是用点来访问。函数就要记得加括号。

    4. 下面两句等价(*****)

    Student.(stu_1, xxx)
    stu_1(xxx)
    
  3. 类属性与对象属性

    1. 类的__dict__是共有的属性
    2. 对象的__dict__是自己独有的属性。
    3. 都可以用 dict 字典的方式赋值,但是不推荐。
  4. __init__ 方法:

    • 绝对不能有返回值。只能默认返回None。
    • 想要在调用在一开始就执行的代码,都可以放入init。因为只有在调用的时候会执行。
    • 应该存放独有的属性,但是可以存放任何种类代码。
  5. 属性查找顺序与绑定方法

    • 属性查找顺序:先从对象找,再去类找。

    • 类可以访问,一种是变量值,一种是函数地址。

    • (****)如果类的属性改了,所有对象的属性也会改的。

    • 类的属性一变,所有对象都能感知到,比如什么count。

    • 如果这个属性是通过对象改的,其他对象不变。

    • 类中的函数属性:(obj,······)

      • 如果调用对象的函数属性,默认会把自己当作参数传入。
      • 默认写 obj 和 self
    • 在 Python3 中,类就是一种类型。

    • 思考题:如果 Student 本身没有 xxx

Student.xxx = 1
stu_1.xxx = 33333
print(stu_2.xxx)

如果想改一个地方,所有都改,直接改类。

  1. 面向对象与面向过程的优劣分析

    • 面向对象缺点缺点:容易过度设计。
    • 有了对象以后,它会干啥,就可以让它干啥。
  2. 补充:序列号uuid

需求:产生一个随机序列号,这样方便储存。 —> uuid

import uuid
print(uuid.uuid4())

day2: 封装与继承:

封装相关

隐藏属性 | 开放接口 | 隐藏数据 | 函数接口 | property

  1. 隐藏属性

    • 什么是隐藏属性?

      • 属性名之前添加 __ 双下前缀
      • 即私有成员,将封装的属性进行隐藏。
    • 隐藏属性的特点

      • 是变形操作。在属性名之前添加 __ 双下前缀,可以产生隐藏效果。
      • 其实也不等于java的private成员。非要访问还是可以访问的。
      • __x 变形完以后如果要调用
        • _Foo_x
        • self.__x 也是一个道理。
      • 这种隐藏对外不对内。其实和java对private成员的get方法一样。
      • 定义以后再添加 __ 前缀的变量,不会变形。在定义的时候直接变形。
  2. 开放接口

    • 什么是开放接口?
      • 就是set、get方法,主要可以添加严格的限制逻辑。
  3. 隐藏数据

    • 为什么要隐藏属性?
      • 对外,可以加严格的控制逻辑,限制外部对数据的操作。
  4. 函数接口

继承相关(全是重点)

  • 大纲1
    • 继承介绍
    • 抽象
    • 属性查找
    • 继承的实现原理:
  • 大纲2
    • 菱形问题
    • 继承原理
    • 深度优先与广度优先
    • Mixins机制
    • 派生与方法:
  1. @property

    • 是一个装饰器,改变类中定义的函数。(不修改原函数,添加一点新的功能。)
      • 我们只需要知道怎么用,暂时不用了解底层原理。
    • property 是干什么的?
      • 案例1:people类,计算bmi。

        • bmi本身是一个功能,函数,因为每次都得进行一次运算。不加()不能执行。但是听起来就像一个数据。
        • 解决方法
        • 函数前面加一个 @property 可以直接调用 bmi
      • 案例2:
        类中:name = property(get_name, set_name, del_name)

      • 案例3:
        类中定义了一大堆 name 方法,加装饰器
        @property ==》对应 obj.name 操作
        @name.setter ==》对应 obj.name = 'xxx’操作
        @name.deleter ==》对应 del obj.name操作

  2. 继承介绍

    python 支持

    • 继承类(多继承)
    • 子类/派生类
    • 父类/超类
# 单继承:
Class Sub1(Parent1):
	pass
	
# 多继承:
Class Sub1(Parent1, Parent2):
	pass

继承的优点:

  1. 解决类与类之间的代码冗余问题。
  2. 多继承,最大限度地重用代码。

继承的缺点:

  1. 违背人的思维逻辑。
  2. 代码可读性会变差。
  3. 可能引发可恶的菱形问题。

对于继承的建议

  1. 尽量避免多继承。
  2. 如果无法避免,就尽量使用 Mixins 机制,享受多继承的好处,又解决多继承可读性的问题。

新式类与经典类

  1. 新式类

    • 祖宗是Object类 (Python3 中默认都是新式类。)
  2. 经典类

    • 祖宗不是Object类
  3. 一个类是经典类还是新式类?

    • 类名.bases
    • 可以看到所有的父类
  4. 如何找出继承关系?抽象

  5. 属性查找顺序
    类.y
    obj.x

  6. 继承的实现原理

    ······继承实现代码重用······
Class OldBoy:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

Class Student(OldBoy):
    # 与父类构造函数相同,也init可以不写的
    pass  

class Teacher(OldBoy):
    # 与父类构造函数大部分相同,又有需要增加的地方:
    def __init__(self, name, age, gender, level ,salary):
        OldBoy.__init__(self, name, age, gender)
        self.level = level
        self.salary = salary

单继承下的属性查找探讨
··········  
Class Foo:
    def f1(self):
        print('Foo.f1')

    def f2(self):
        print('Foo.f2')
        self.f1

    def f3(self):
        print('Foo.f3')
        Foo.f1(self)  # 自己调用自己,可行。


Class Bar:
    def f1():
        print(''Bar.f1')

# 现场翻车  # ===》因为会找到自己的f1
b = Bar()
b.f2()  # Foo.f2   Bar.f1,

# 如果改成:__f1(self),那就不会和产生命名产生冲突。

多继承下的属性查找探讨(菱形问题与钻石问题)

  1. 菱形问题
    1. 一个子类,继承了多个爹,最后汇聚到一个非Object类上。
  2. 钻石问题
    1. 汇聚到Object类上,叫死亡钻石,不叫菱形继承,不是靠形状判定的。
  3. MRO(方法解析列表)
    1. C3算法,做一个列表。
    2. 只要定义一个类,就会有一个MRO列表。
    3. 类和类的列表都是参照MRO列表。
class D(B, C)::::#查找顺序是 D B C
	print(D.mro())::: # 查找顺序

注意

  1. MRO是固定的,但是经典类和新式类不同,
  2. Python2 和Python3 的结果是不一样的。

新式类中

  1. Python2:第一个分支直接搜索到Object类。
  2. Python3:最后一个分支搜索搜到Object类。

总结

  1. 多继承是需要的,但是要使用 Mixins 机制。

day3

1. Mixins机制:

核心

  1. 提升多继承机制的可读性。

继承中,代码大量重用的问题:

  1. 交通工具类(可以飞),民航客机类/直升机类/汽车类,都继承了交通工具类。
  2. “飞”的功能大量重用,所以放在了交通工具类中。
  3. 所以,按照规则,汽车也能飞。

解决思路:

  1. 专门写一个 FlyableMixin,参杂了fly功能,让客机、直升机多继承继承这个类
  2. Helicopter(FlyableMixin, Vahicle)
  3. 暗示原则:FlyableMixin,本质还是多继承,但是暗示我们功能单一。例如PI = 3.14,虽然本质还是变量,但是通过常量大写原则,暗示我们是常量,

Mixin 类设计原则

  1. 为形容词,Mixin、able、ible结尾,
  2. 功能必须单一,
  3. 一个类,表明身份的爹,只能有一个,Mixin 类可以多个。
  4. 比如我们可以查考socketsever库。

2. 子类重用父类的功能

子类如何重用爹的功能?

  1. 调用某个类下的函数
  2. super()
    • 调用父类提供的方法
    • 注意有括号,没有self

举例

  1. super().init(name, age, sex)
    1. 会得到一个特殊的对象,参照当前类的MRO,去父类中找属性。
    2. 注意是从父类中找属性,直接跳过自己。
      ··········
# ! python3.8
# -*- coding:utf-8 -*-

class OldBoy:
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex


class Teacher(OldBoy):
    def __init__(self, name, age, sex, level, salary):
        # 就是这句,重用父类的构造函数。
        # OldBoy.__init__(self, name, age, sex)  
        # 这句是super()。注意别忘记加括号,没有self
        super().__init__(name, age, sex)
        # 然后记录新的参数
        self.level = level
        self.salary = salary

teacher1 = Teacher('egon', 13, 'male', 'high', 10000)
print(teacher1.name)  # egon

print(OldBoy)  # <class '__main__.OldBoy'>
print(Teacher)  # <class '__main__.Teacher'>
print(teacher1)  # <__main__.Teacher object at 0x7f9b1898b2b0>

print(OldBoy.__dict__)  # {'__module__': '__main__', '__init__': <function OldBoy.__init__ at 0x7f9b189b7670>, '__dict__': <attribute '__dict__' of 'OldBoy' objects>, '__weakref__': <attribute '__weakref__' of 'OldBoy' objects>, '__doc__': None}
print(Teacher.__dict__)  # {'__module__': '__main__', '__init__': <function Teacher.__init__ at 0x7f9b189b7790>, '__doc__': None}
print(teacher1.__dict__)  # {'name': 'egon', 'age': 13, 'sex': 'male', 'level': 'high', 'salary': 10000}

print(OldBoy.__str__)  # <slot wrapper '__str__' of 'object' objects>
print(teacher1.__str__)  # <method-wrapper '__str__' of Teacher object at 0x7ff903a812b0>

总结

  1. Class.__dict__:所有的方法
  2. obj.__dict__:所有的数据
  3. Class.__str__:slot wrapper
  4. obj.__str__:method-wrapper

3. 多态 / 鸭子类型 / import abc(子类都得重写这个方法)

什么是多态?

  1. 同一种事物有多种形态。
  2. 就是一个Animal类,派生了Dog类,Pig类,People类。

为什么要用多态?

怎么用多态?

  1. Dog类,Pig类,People类继承了Animal类,都有say()方法
  2. 可以传入各种对象。只要长得像,都有say就可以。
def animal_say(animal):
  animal.say()

什么是鸭子类型?

  1. 长得像、走路晃、还会游泳,你就是鸭子。
  2. 通过一种规范,把所有类型做得像对象一样。
  3. 所以,Python下一切皆对象

抽象基类 abc

要么子类别用say方法,要用就得重写say方法。

import abc  # 一个模块,抽象基类
 
# 作用:
# 统一所有的子类方法。
# 抽象基类不是为了自己实例化,而是为了统一标准。
def Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod # ##
    def say(self):
        pass

4. 绑定方法:调用者本身作为第一参数传入。

  1. 绑定给类的方法:调用者是类,自动传入的是类。
  2. 绑定给对象的方法:调用者对象,自动传入的是对象
  3. 非绑定方法:没有绑定给任何人,调用者可以是类/对象,没有自动传参的效果,就是个普通函数

5. @classmethod 方法

用装饰器,提供一种新的构造对象的方式
举例:加载配置,生成对象

import settings  # 导入文件,下面用到

class Mysql:
    def __init__(self, ip, port):
        self.ip = ip
        self.port = port

    @classmethod
    def from_conf(cls):
        print(cls)
        return cls(settings.IP, settings.PORT)

obj = Mysql.from_conf()  # 用这种方式替换构造函数

6. staticmethod:静态方法

类体的代码,不需要类,也不需要对象,就可以运行。
比如每造一个对象,自动生成一个id

7. 内置函数(补充)

enumerate:::循环一个容器,变成index和元素的2元元组
obj_1.__dir__():::一个对象,有什么属性?
divmod(10, 3):::求商和余数,返回元组
eval('1 + 2'):::执行字符串中的表达式:

abs():::绝对值:::
all():::容器中,所有元素都真,结果为真;空容器为真:
any():::容器中,只要一个为真,就是真;空容器为假:
???:bool

callable():::是不是函数、方法、类?:
chr():::ascii数字->字符:::范围:0x110000
ord:::字符转为ascii数字,
frozenset:::不可变集合:
isinstance(a, A):::判断对象a是不是类A的实例:

以前用 type(l) is list 判断类型,现在用什么?
pow(10, 2, 3):::102次方,对3取余数:
__repr__():::在交互式环境下,输入一个值,默认调用的方法
slice(1, 4, 2):::切片
zip():::两个同等长度的容器,结合成元组迭代器(留短):
time = __import__('time'):::文件里面存了一堆要导入的模块,读取的时候,怎么导入?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值