[python基础] 面向对象——封装,继承

面向对象

  • 一、面向对象的基础知识
  • 二、类和面向对象
  • 三、封装
  • 四、继承
    • (1)、基本使用方法
    • (2)、链表相加
    • (3)、多继承
    • (4)、私有属性与私有方法

一、面向对象的基础知识

1、面向对象
定义:面向对象是人们按照客观世界的系统思维,把构成问题的事物分解成各个对象,建立对象的可以更好的描述某个事物在整个解决问题的步骤中的行为。
特点:抽象 封装 集成 多态
优点:易维护,易服用,易扩展。可以设计出低耦合的系统,使系统更加灵活,更加容易维护
缺点:性能比面向过程低

2、类(Class)
类是显示或者思维世界中的实体在计算机中的反映,它将数据以及这些数据上的操作封装在一起。

3、对象(Object)
对象是具有类类型的变量,类和对象是面向对象编程技术中的最基本的概念
类和对象是类似与鱼和草鱼的关系。

二、类和面向对象

类和对象的使用

# 类(Class)
class Cat:
    # 属性:一般是名词,eg: name, age, gender.....
    name = 'name'
    kind = 'kind'

    # 方法: 一般情况是动词, eg: create, delete, eating, run......
    def eat(self):
        print('cat like eating fish.....')

# 对象(Object):对类的实例化(具体化)
fentiao = Cat()

print(Cat)  # 
print(fentiao) # <__main__.Cat object at 0x00E9FD70>


三、封装

1、基本使用方法

class Cat:
    def __init__(self, name, kind):  # 形参
        """
        1. 构造方法,实例化对象时自动执行的方法
        2. self是什么? self实质上是实例化的对象
        3. 类方法中, python解释器会自动把对象作为参数传给self
        """
        print('正在执行__init__构造方法')
        print('self:', self)

        # 属性:一般是名词,eg: name, age, gender.....
        # 封装: self.name将对象和name属性封装/绑定
        self.name = name
        self.kind = kind

    # 方法: 一般情况是动词, eg: create, delete, eating, run......
    def eat(self):
        print(f'cat {self.name} like eating fish.....' )


# 对象(Object):对类的实例化(具体化)
fentiao = Cat("粉条", "美短虎斑")
print(fentiao.name)
print(fentiao.kind)
fentiao.eat()

#结果
正在执行__init__构造方法
self: <__main__.Cat object at 0x000001B916A623B0>
粉条
美短虎斑
cat 粉条 like eating fish.....
cat 粉条 like eating fish.....

2、练习
要求:
创建一个类people
拥有的数学为姓名,性别和年龄
拥有的方法为购物,学习,玩游戏

实例化对象,执行对应的方法

显示如下:
小明,18岁,男,去赛格广场购物。
小王,22岁,男,去赛格广场购物
小红,10岁,女,在西部开源学习

代码如下:

class people:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    def shopping(self):
        print(f'{self.name},{self.age}岁,{self.gender},去西安赛格广场购物')

    def learning(self):
        print(f'{self.name},{self.age}岁,{self.gender},在学习')


p1 = people('小明', '18', '男')
p2 = people('小王', '18', '男')
p3 = people('小红', '10', '女')

p1.shopping()
p2.shopping()
p3.learning()

四、继承

(1)、基本使用方法

父类又称基类
子类又称扩展类
1、继承的使用方法
当子类没有时找父类的执行方法

class Student:
    """父类Student"""
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def learning(self):
        print(f'{self.name}正在学习')

class MathStudent(Student):
    """MathStudent的父类是Student"""
    pass


# 实例化
m1 = MathStudent("粉条博士", 8)
print(m1.name)
print(m1.age)
m1.learning()           # 不报错,子类里没有,但父类有该方法
# m1.choice_course()    # 报错, 子类里没有,父类也没有的方法

2、继承的使用方法扩展
当子类和父类都有对应的执行方法时,会执行子类的执行方法。
如果需要先执行父类的执行方法,再执行子类的执行方法,则用在子类函数里面添加super函数。

class Student:
    """父类Student"""
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def learning(self):
        print(f'{self.name}正在学习')

    def choice_course(self):
        print('正在选课中'.center(50, '*'))

class MathStudent(Student):
    """MathStudent的父类是Student"""
    def choice_course(self):
        # 需求: 先执行父类的choice_course方法, 在个性化执行自己的方法。
        # Student.choice_course(self)  # 解决方法1: 直接执行父类的方法,但不建议
        # 解决方法2: 通过super找到父类,再执行方法(建议且生产环境代码常用的方式)
        super(MathStudent, self).choice_course()
        info = """
                    课程表
            1. 高等数学
            2. 线性代数
            3. 概率论
        """
        print(info)

# 实例化
m1 = MathStudent("粉条博士", 8)
m1.choice_course()

s1 = Student("粉条博士", 8)
s1.choice_course()

#结果
**********************正在选课中***********************

                    课程表
            1. 高等数学
            2. 线性代数
            3. 概率论
        
**********************正在选课中***********************

Process finished with exit code 0

(2)、链表相加

参考链接 https://www.cnblogs.com/klyjb/p/11237361.html

数组: 需要连续的内存空间
链表: 不需要连续的内存空间

不同的数据结果对应的时间复杂度不同,数据和链表的复杂度如下:

                数组              链表
增加元素        O(n)                O(1)
删除元素        O(n)                O(1)
修改元素        O(1)                O(n)
查看元素        O(1)                O(n)

[python基础] 面向对象——封装,继承_第1张图片
[python基础] 面向对象——封装,继承_第2张图片

# 封装节点类

class ListNode:
    # 首先封装传值
    def __init__(self, val=0, next=None):            #指针类型为空
        self.val = val
        self.next = next

     # 定义链表寻值方式
    def travel(self, head):
        """遍历链表里面的每一个元素"""
        while head:
            print(head.val, end=',')
            head = head.next

#创建第一个链表
def create_l1():
    # l1 = 2,4,3
    # l2 = 5, 6, 4
    l1 = ListNode()
    node1 = ListNode(val=2)
    node2 = ListNode(val=4)
    node3 = ListNode(val=3)
    l1.next = node1
    node1.next = node2
    node2.next = node3
    return  l1.next

#创建第二个链表
def create_l2():
    # l1 = 2,4,3
    # l2 = 5, 6, 4
    l2 = ListNode()
    node1 = ListNode(val=5)
    node2 = ListNode(val=6)
    node3 = ListNode(val=4)
    l2.next = node1
    node1.next = node2
    node2.next = node3
    return  l2.next

def addTwoNumbers(l1: ListNode, l2: ListNode) -> ListNode:
    res = 0
    l3 = ListNode()
    cur = l3
    while(l1 or l2):
        if(l1):
            res += l1.val  # res=2
            l1 = l1.next
        if(l2):
            res += l2.val # res=2+5=7
            l2 = l2.next
        # res=10, val=0, res=>val val=res%10
        # res=14, val=4, 14%10=4
        l3.next = ListNode(res%10)
        l3 = l3.next
        # res=10, 进位为1, 10//10=1
        # res=14, 进位为1, 14//10=1
        res  //= 10
    if res == 1:
        l3.next = ListNode(1)
    return cur.next

#直接执行这个模块时会运行以下的代码
if __name__ == '__main__':
    l1 = create_l1()
    l2 = create_l2()
    l3 = addTwoNumbers(l1, l2)
    l3.travel(l3)

(3)、多继承

多继承
python3:新式类(广度优先),多继承时搜索同级优先
python2:经典类(深度优先),多继承时搜索父级优先

(4)、私有属性与私有方法

 私有属性,以双下划线开头。
 工作机制: 类的外部(包括子类)不能访问和操作,类的内部可以访问和操作。
 
 私有方法是以双下划线开头的方法,
 工作机制: 类的外部(包括子类)不能访问和操作,类的内部可以访问和操作。
class Student:
    """父类Student"""
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        # 私有属性,以双下划线开头。
        # 工作机制: 类的外部(包括子类)不能访问和操作,类的内部可以访问和操作。
        self.__score = score

    def learning(self):
        print(f'{self.name}正在学习')

    def get_score(self):
        self.__modify_score()                 #内部使用,调用私有方法
        return  self.__score                  #内部调用,可以使用私有属性

    # 私有方法是以双下划线开头的方法,
    #工作机制: 类的外部(包括子类)不能访问和操作,类的内部可以访问和操作。
    def __modify_score(self):                 #定义私有方法
        self.__score += 20

s1 = Student('ck',18,425)
score = s1.get_score()
print(score)
#结果
445

注意:子类无法调用父类的私有方法和属性

class Student:
    """父类Student"""
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        # 私有属性,以双下划线开头。
        # 工作机制: 类的外部(包括子类)不能访问和操作,类的内部可以访问和操作。
        self.__score = score

    def learning(self):
        print(f'{self.name}正在学习')

    def get_score(self):
        self.__modify_score()                 #内部使用,调用私有方法
        return  self.__score                  #内部调用,可以使用私有属性

    # 私有方法是以双下划线开头的方法,
    #工作机制: 类的外部(包括子类)不能访问和操作,类的内部可以访问和操作。
    def __modify_score(self):                 #定义私有方法
        self.__score += 20


class MathStudent(Student):
    """MathStudent的父类是Student"""
    def get_score(self):
        self.__modify_score()
        return  self.__score

# 报错原因: 子类无法继承父类的私有属性和私有方法。
s1 = MathStudent('张三', 18, 100)
score = s1.get_score()
print(score)
# 结果
AttributeError: 'MathStudent' object has no attribute '_MathStudent__modify_score'. Did you mean: '_Student__modify_score'?

补充练习题
给定一个整型数组nums,和一个整数的目标值target,请找出数组中两个数相加为target的两个整数,并返还器数组下标。
例:
输入nums[2,7,11,15],target=9
输出[0,1]
解释:因为nums[0]+nums[1]=9

class solution:
    def twosum(self,nums:list[int],target:int) -> list[int]:
        #用哈希表(python里面是字典)时间复杂度更快
        hashes = {}
        n = len(nums)
        for i in range(n):
       		hashes[nums[i]] = i     #对字典每个值进行赋值,赋的值为索引
            if target - nums[i] in hashes:
                return hashes[target-nums[i]],i
            

你可能感兴趣的:(python基础,python,java,开发语言)