python零基础入门(三):面向对象


前言

该笔记为python自学笔记,基于pycharm的python入门笔记
推荐b站上的一个入门教程链接:【花了2万多买的Python教程全套,现在分享给大家,入门到精通(Python全栈开发教程)-哔哩哔哩】 https://b23.tv/pTSkZdu
笔记中看不懂的地方可以找到b站上相应的内容学习。


面向对象

什么是面向对象

举个栗子
比如你想吃番茄炒蛋,你有两个选择:

  1. 自己做:买材料→洗菜→切菜→炒菜
  2. 点外卖:用点餐软件选择商家下单。

其中选择1 就可以理解为面向过程,自己按照流程来做。
选择2就是面向过程,只需要找到这件事的参与者(你,商家),至于这个菜怎么做是商家的事,商家再按步骤做,也就是宏观上找到事物之间的关系(找参与者),参与者从细节上去操作,按照面向过程的方式做完他的事情。

面向对象和面向过程
在这里插入图片描述

  1. 面向过程
  • 面向过程就是具体化、流程化地去解决一个问题,需要一步步分析,一步步实现;
  1. 面向对象
  • 面向对象(Object Oriented Programming),简称OOP,是一种编程思想。
  • 对象是指在现实生活中能够看得见摸得着的具体事物
  • 面向对象就是把现实中的事物都抽象成为程序设计中的“对象”,其基本思想是一切皆对象,是一种自下而上的设计语言,先设计组件,再完成拼装。
  • 面向对象是模型化的,你只需抽象出一个类,这是一个封闭的盒子,里面有数据也有解决问题的方法。需要什么功能直接使用就可以了,不必去一步一步的实现,至于这个功能是如何实现的,不管,会用就行了。
  • 面向对象的底层其实还是面向过程,把面向过程抽象成类,然后封装,方便我们使用的就是面向对象了。

相关概念

类是描述具有相同属性和方法的集合。类就是一组相似事物的统称,(注意:一组而不是一个,相似而不是相同,统称而不是名称。)
2. 对象:类的实例。(比如,类:人类; 你就是一个类的实例,即对象。)对象的属性是静态的,对象的方法是动态的。
3. 方法:类中用def定义。(注意:类之内用def定义的是方法,类之外是函数。)
4. 类变量:定义在类中且在函数之外的变量,在所有实例化对象中公用。

在这里插入图片描述

先看个例子

class Student:  # Student是类名
    ''' 学生类 '''
    # 类属性,直接写在类里的变量称为类属性
    native_place = '天津'

    # 初始化方法
    def __init__(self, name, age, gender):  # name,age,gender为实例属性,是所创建的对象都有的
        self.name = name  # self.name是实体属性,将局部变量的name的值赋值给实体属性
        self.age = age
        self.gender = gender


    # 实例方法(具体的个体)
    def info(self):  # self一般要写
        print('我的名字是', self.name, '年龄是', self.age, '性别是', self.gender)


    # 静态方法
    @staticmethod
    def sm():  # 静态方法里面不允许写self
        print('这是静态方法')


    # 类方法
    @classmethod
    def cm(cls):  # 类方法中要求传一个cls
        print('这是类方法')


# 对象的创建(类的实例化)
# 创建学生对象
stu1 = Student('张三', 20, '男')
stu2 = Student('李四', 19, '男')
print(type(stu1))
print(stu1)
print(stu1.name)   # 实例属性
stu1.info()  # 对象名.方法名
Student.info(stu1)  # 类名.方法名   (与上一行功能相同,都是调用Student中的info方法)


# 类属性的使用方法
print(Student.native_place)
print(stu1.native_place)

# 修改类属性
Student.native_place = '北京'

# 类方法的使用
Student.cm()  # 调用的时候不需要传入cls

# 静态方法的使用
Student.sm()

# 动态绑定,为stu1动态绑定年级属性
stu1.grade = '大二'
print(stu1.name, '所在年级为', stu1.grade)


# 动态绑定方法
def eat():  # 在类之外定义的,是函数
    print('学生在吃...')

stu1.eat = eat # 绑定了对象之后,就是方法
stu1.eat()

类的定义和使用

# 类的定义
# 语法:
class ClassName:
    '''类的帮助信息'''
    statement # 包括属性和方法

类的组成与使用

类的组成用法
类属性写在类中并且方法体外,可以在所有类的实例之间共享值
实例方法实例方法是类的实例对象能调用的方法,self
静态方法没有默认参数,不能使用类的任何属性或方法,用装饰器 @staticmethod 修饰,使用类名直接访问的方法。
类方法默认参数cls,能使用类的任何属性或方法,用装饰器 @classmethod修饰,使用类名直接访问的方法。
  • 初始化方法:
    我们可以通过初始化方法来创建实例对象,每个class只能有一个初始化方法。在创建对象的时候,会自动调用初始化方法进行创建,不需要手动调用。

  • 类属性:类属性可以通过两种方式进行调用:

方式注意
类名.类属性使用该方式对类属性进行修改,无论之后用哪种方式再次调用该类属性,类属性的值都是修改后的值。
对象名.类属性使用该方式对类属性进行修改,只有该对象再次调用的时候类属性的值是修改后的值,其他对象不变。

在这里插入图片描述

对象的创建

概念

  • 对象的创建又称为类的实例化
  • 有了实例就可以调用类中的内容
  • 语法: 实例名=类名()
stu1 = Student('张三', 20, '男')

动态绑定属性和方法

  • python是动态语言,在创建对象后可以动态地绑定属性和方法。
# 动态绑定方法
def eat():  # 在类之外定义的,是函数
    print('学生在吃...')

stu1.eat = eat # 绑定了对象之后,就是方法
stu1.eat()

小结一下

在这里插入图片描述

面向对象三大特性 : 封装、继承、多态

封装

  • 提高程序的安全性
  • 将数据(属性)和行为(方法)包装到类对象中。在方法内部对属性进行操作,在
    类对象的外部调用方法。
  • 隐藏对象的属性和实现细节,仅对外提供公共访问方式(类比:提款机)。这样,无需关心方法内部的具体实现细节,从而隔离了复杂度。
  • 在Python中没有专门的修饰符用于属性的私有,如果该属性不希望在类对象外部被访问,前边使用两个下划线“_”
# 封装
class Student:   
    def __init__(self, name, age):  # 定义构造方法
        self.name = name
        self.__age = age     # age不希望在类外部被使用,所以加两下划线

    def show(self):
        print(self.name, '的年龄是', self.__age)  # 在类内部可以使用age


stu = Student('张三', 20)
stu.show()

# 在类外部使用name和age
print(stu.name)
# print(stu.__age)  # 会报错,因为不能直接访问
print(dir(stu))  # 查看stu有哪些属性
print(stu._Student__age)  # 在类外部访问需通过 _类名.__属性名

访问限制

做访问限制,是为了程序的健壮性。如果可以从外部对函数里面重要的属性进行任意修改,有可能程序崩溃只是因为一次不经意地参数修改。
在这里插入图片描述

# 保护类型属性及其访问
class Swan:
    '''天鹅类'''
    _neck_swan = '天鹅的脖子很长'   # 保护类型属性
    def __init__(self):
        print('__init__():',Swan._neck_swan)  # 访问保护类型的属性
        
swan = Swan()
print("直接访问:",swan._neck_swan)  # 通过实例名访问受保护类型的属性
# 私有类型属性及其访问
class Swan:
    '''天鹅类'''
    __neck_swan = '天鹅的脖子很长'   # 私有类型属性
    def __init__(self):
        print('__init__():',Swan.__neck_swan)  # 访问私有类型的属性
swan = Swan()
swan._Swan__neck_swan = '脖子很长'  # 修改私有类型的属性
print("直接访问:",swan._Swan__neck_swan)  # 修改后,访问私有类型的属性

#(通过变形改变私有属性的值,并不会影响方法中的调用)

继承

1. 基本认识

  • 继承可提高代码的复用性
  • 一个类继承一个父类,便可拥有父类的属性和方法
  • 如果一个类没有继承任何类,则默认继承object
  • 定义子类时,必须在其构造的函数中调用父类的构造函数。
  • 语法格式:
class 子类类名(父类类名):
	pass
  • 子类与父类的理解,如图:
    子类与父类
  • python 支持多继承,如图:
    在这里插入图片描述

示例

class Person:   # 没有继承任何类,默认继承object, object可以省略不写
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def info(self):
        print(self.name, self.age)


class Student(Person):   # Student作为子类继承Person这个父类
    def __init__(self, name, age, stu_no):
        super().__init__(name, age)  # 调用父类的
        self.stu_no = stu_no   # 学号

class Teacher(Person):
    def __init__(self, name, age, teachofyear):
        super().__init__(name, age)  # 调用父类的
        self.teachofyear = teachofyear # 教龄

# 创建对象
stu1 = Student('张三', 20, 3020226010)
teacher1 = Teacher('李四', 34, 10)

# 调用父类的实例方法
stu1.info()  # 只输出姓名和年龄
teacher1.info()

在这里插入图片描述

2. 方法重写

  • 如果子类对继承自父类的某个属性或方法不满意,可以在子类中对其(方法体)进行重新编写。
  • 子类重写后的方法中可以通过 super().xxx()调用父类中被重写的方法
class Person:   # 没有继承任何类,默认继承object, object可以省略不写
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def info(self):
        print(self.name, self.age)


class Student(Person):   # Student作为子类继承Person这个父类
    def __init__(self, name, age, stu_no):
        super().__init__(name, age)  # 调用父类的
        self.stu_no = stu_no   # 学号
    def info(self):
        super().info()  # 通过 super().info()调用父类中被重写的方法
        print('学号:', self.stu_no)  # 重写的内容

# 创建对象
stu1 = Student('张三', 20, 3020226010)
# 调用父类的实例方法
stu1.info()  # 能输出姓名、年龄和学号

3. object类

  • object类是所有类的父类,因此所有类都有object类的属性和方法。
  • 使用内置函数dir()可以查看指定对象所有属性
  • object有一个str_()方法,用于返回一个对于“对象的描述”,对应于内置函数str()经常用于print()方法,帮我们查看对象的信息,所以我们经常会对_str_()进行重写
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):  # 对_str_()进行重写,用于返回对象的描述
        return '我的名字是{},今年{}岁'.format(self.name, self.age)


stu1 = Student('张三', 20)
print(dir(stu1))
print(stu1)  # 默认调用__str__()
print(type(stu1))

 

多态

  • 多态就是具有多种形态,指的是即便不知道一个变量所引起的对象到底是什么类型,仍然可以通过这个变量调用方法,在运行过程中根据变量所引用的对象的类型,动态决定调用哪个对象中的方法。
  • 父类定义的引用变量可以指向子类的实例对象,提高了程序的拓展性。
class Animal:
    def eat(self):
        print('动物会吃。')

class Dog(Animal):
    def eat(self):    # 重写方法
        print('狗吃骨头...')


class Cat(Animal):
    def eat(self):    # 重写方法
        print('猫吃鱼...')

class Person:
    def eat(self):
        print('人吃五谷杂粮...')

# 定义一个函数
def fun(Animal):
    Animal.eat()

# 调用函数
fun(Cat())
fun(Dog())
fun(Person())  # Person虽然不是Animal的子类,但是里面也有eat方法。(动态语言的“鸭子类型”)

运行结果:
在这里插入图片描述

静态语言与动态语言

静态语言和动态语言关于多态的区别

  • 静态语言(如:Java)实现多态的三个必要条件:继承、方法重写、父类引用指向子类对象

  • 动态语言(如:python)的多态崇尚“鸭子类型”。当看到一只鸟走起来像鸭子、游泳起来像鸭子、收起来也像鸭子,那么这只鸟就可以被称为鸭子。在鸭子类型中,不需要关心对象是什么类型,到底是不是鸭子,只关心对象的行为。

特殊方法和特殊属性

在这里插入图片描述

特殊属性

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

# 创建实例对象
stu1 = Student('张三', 20)

# 类中的特殊属性
print('实例对象的属性字典:', stu1.__dict__)
print('类对象的属性方法字典:', Student.__dict__)
print('输出对象所属的类:', stu1.__class__)
print('输出类的基类元组:', Student.__bases__)
print('类的层次结构:', Student.__mro__)  # 查看继承关系

运行结果:
在这里插入图片描述

特殊方法

这块知识点不理解其实也不太影响,对于初学者有一定难度

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __add__(self, other):
        return self.name + other.name
    def __len__(self):
        return len(self.name)

# 创建实例对象
stu1 = Student('张三', 20)
stu2 = Student('李四', 19)
print(stu1 + stu2)  # 实现了两个对象的加法运算(因为在Student类中编写了__add__()特殊方法)
print(stu1.__add__(stu2))  # 同上
print(len(stu1))


lst = [1, 2, 3, 5]
print(len(lst))   # 在列表中len是内置函数
print(lst.__len__())  # 效果同上

运行结果:
在这里插入图片描述

class Student:

    def __new__(cls, *args, **kwargs):   # 用于创建对象
        print('__new__被调用执行了,cls的id值为{}'.format(id(cls)))
        obj = super().__new__(cls)
        print('创建对象的id为{}'.format(id(obj)))
        return obj


    def __init__(self, name, age):  # 初始化对象的属性
        self.name = name
        self.age = age
        print('__init__被调用了,self的id值为{}'.format(id(self)))

print('object这个类对象的id值为{}'.format(id(object)))
print('Student这个类对象的id值为{}'.format(id(Student)))

# 创建实例对象
stu1 = Student('张三', 20)
print('stu1这个Student类的实例对象的id值为{}'.format(id(stu1)))

运行结果:
在这里插入图片描述

  • __new__在前去创建对象,__init__在后为对象的实例属性进行赋值,最后将创建的对象放到stu1中存储
  • __new__先被调用,__init__后被调用,__new__的返回值(实例)将传递给__init__方法的第一个参数,然后__init__给这个实例设置一些参数。
    在这里插入图片描述

类的深拷贝和浅拷贝

  • 变量的赋值操作:只是形成两个变量,实际上还是指向同一个对象

  • 浅拷贝:Python拷贝一般都是浅拷贝,拷贝时,对象包含的子对象内容不拷贝,因此,源对象与拷贝对象会引用同一个子对象

  • 深拷贝:使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象,源对象和拷贝对象所有的子对象也不相同

总结

在这里插入图片描述

创建用于计算的属性

# 语法:
@prooerty
def methodname(self)  # 要转化为属性的方法
    block  # 一般要通过return语句返回方法结果
class Rect:
    def __init__(self,length,width): # 构造方法
        self.length = length # 矩形的长
        self.width = width    # 宽

    @property   # (装饰器)把方法转换为属性,实现可以计算的属性,
    def area(self):
        return self.length*self.width    # 计算矩形的面积
rect = Rect(800,600)   # 创建类的实例
print('面积为:',rect.area)  # 输出面积

property属性不能重新赋值

为属性添加安全保护机制

借助装饰器@property,创建可以读取但不能修改值的属性

class TVShow:
    '''电视节目类'''
    def __init__(self,show):
        self.__show = show
    @property
    def show(self):
        return self.__show   # 返回私有属性
tvshow = TVShow('正在播放《战狼2》')  # 创建类的实例
print('默认:',tvshow.show)    # 获取属性值,tvshow不能修改

在一定条件下,让属性值可修改

class TVShow:
    '''电视节目类'''
    list_film = ['战狼2','红海行动','湄公河行动','我和我的祖国']
    def __init__(self,show):
        self.__show = show
    @property
    def show(self):
        return self.__show   # 返回私有属性
    @show.setter  # 对以下方法进行转化,让属性可以修改
    def show(self,value):
        if value in TVShow.list_film:  # 允许修改私有属性的条件
            self.__show = '您选择了《'+value+'》,稍后播放'   # 修改返回值
        else:
            self.__show ='您点播的电影不存在'

tvshow = TVShow('战狼2')  # 创建类的实例
print('正在播放:《',tvshow.show,'》')    # 获取属性值
print('您可以从',TVShow.list_film,'中选择要点播的电影')
tvshow.show ='红海行动'
print(tvshow.show)

派生类中调用基类的__init__()方法定义类属性


class Fruit:
    def __init__(self,color='绿色'):
        Fruit.color = color  # 类属性

    def harvest(self,color):
        print('我原来是',Fruit.color,'的!')  # 输出类属性
        print('水果已经收获... \n,水果是',color,'的!\n')  # 输出形式参数


class Apple(Fruit):   # 继承自水果类
    color = '红色'
    # def __init__(self):    # 如果在派生类中不定义构造方法,就会执行基类的构造方法。
    print('我是苹果')

class Orange(Fruit):
    color = '橙色'
    def __init__(self): #在派生类中定义了构造方法
        print('我是橘子')
        super().__init__()   # 在派生类中调用基类的构造方法

apple = Apple()   # 创建苹果实例
apple.harvest(apple.color)  # 调用基类的harvest()方法
orange = Orange()
orange.harvest(orange.color)

模块(Modules)

概述

  1. 模块简介
  • 一个python程序中包含多个模块
  • 模块与函数的关系:一个模块中可以包含多个函数
  • Python 中一个以 .py 结尾的文件就是一个模块
  • 模块中定义了变量、函数、类、语句等来实现一些类似的功能。
  • Python 有很多自带的模块(标准库)和第三方模块,一个模块可以被其他模块引用
  1. 模块的好处
  • 方便其他程序和脚本的导入并使用
  • 避免函数名跟变量名冲突
  • 提高代码的可维护性和可重用性。

在这里插入图片描述
3. 使用模块的好处

  • 可以避免函数名和变量名冲突
  • 更容易查找代码
  • 提高代码的可重用性
  • 有选择地使用

创建模块

自定义模块

  • 新建一个文件名为 :模块名+ .py
  • 不能使用python自带的标准模块名称

import 导入模块

#语法一:
import 模块名 (as 别名)  # 别名可加可不加 
# 语法二:
from 模块名 import 变量或函数或类
from 模块名 import *   # 导入这个模块中的全部定义
print(dir())   # dir函数查看导入了哪些定义
  • 导入自定义模块时,推荐使用语法二

模块搜索目录
如果要导入的模块文件和导入它的文件不在同一目录中的解决方法:

  • 临时添加要查找的目录
import sys
sys.path.append('E:/change/temp')  # 模块所在路径,或E:\\change\\temp
  • 增加 .pth 文件 (推荐)
  • 在PYTHONPATH环境变量中添加

以主程序的形式执行

if __name__ == '__main__'
  • 每个模块的定义中都包括一个记录模块名称的变量__name__,程序可以检查该变量,以确定他们在哪个模块中执行。
  • 如果 if__name__ == '__main __'所在模块是被直接运行的,则该语句下代码块被运行;如果所在模块是被导入到其他的python脚本中运行的,则该语句下代码块不被运行。

简介

  • 包是一个分层次的目录结构,它将一组功能相近的模块组织在一个目录下。
  • 包与目录的区别:是否含有__init__.py 文件。(其中__init__.py 可为空也可定义属性和方法。)
  • 包的作用:避免模块名重名引发的冲突,起到规范代码的作用。
  • Python3.3 之前的版本__init__.py 是包的标识,是必须要有的,之后的版本可以没有。

创建包

在这里插入图片描述

导入包

# 语法一:
improt 包名.模块名 (as 别名)
# 语法二:
from 包名 import 模块名
from 包名.模块名 import 变量名

python中常用的内置模块

在这里插入图片描述

第三方模块的安装与运用

  • 在线安装: pip install 模块名
    * p
  • 使用:import 模块名

总结:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

洛不必达

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值