Python面向对象编程

Python面向对象编程

基础

名词

类:就是具有相同属性和功能的一类事物。
对象:就是类的具体表现。
面向对象思维:要自己建立对象,自己建立场景,你就是面向对象世界中的上帝,你想让你的车干嘛就干嘛,你想让人干嘛就干

程序的对象对应现实中具体的事务(看得见摸得着的东西都算)
现实中的事务转换到电脑上变成程序
世间万物的一切皆对象
看得见摸得着的东西都是对象,只要是对象就能转换到计算机中以代码的形式表现

面向过程 : 想要一个结果 写代码 实现计算结果
面向对象开发 : 有哪些角色 角色的属性和技能 两个角色之间是如何交互的

优点:

  • 面向对象编程:是一类相似功能函数的集合,使你的代码更清晰化,更合理化
  • 面向对象,要拥有上帝的视角看问题,类其实就是一个公共模板(厂房),对象就从具体的模板实例化出来



类和对象之间的关系?

  • 类是一个大范围 是一个模子 它约束了事物有哪些属性 但是不能约束具体的值
  • 对象是一个具体的内容 是模子的产物 它遵循了类的约束 同时给属性赋上具体的值

小菜

对象:有下面几个对象

张一的手机
张二的手机
张三的手机
张四的手机

对象的集合–>共同特征:品牌、颜色、大小、价格
动作(能干啥):打电话、发微信,玩游戏

类别:手机、学生
学生:张一、张二、张三、张四
学生特征:姓名、性别、年龄、身高
学生动作:刷抖音、打电话
能做的动作有很多,在实际开发中,只列需要的动作
这些特征称为属性,动作称为方法

多个对象–>提取对象的共同特征和动作–>封装到一个类中,这就是面向对象

在代码中先定义类,在写其他
书写规则:约定俗成,类的首字母大写,多个单词使用驼峰体命名
例如:ValueError、TypeError等等

语法格式

在python3中,默认继承object类,所以书写的时候可以不写
语法:

class 类名():
    属性:特征
    方法:动作
class ShouJi(object):
    pass
    # 或者
class ShouJi:
    pass

实例化所经历的步骤

实例化所经历的步骤

  1. 类名() 之后的第一个事儿 :开辟一块儿内存空间

  2. 调用 init 把空间的内存地址作为self参数传递到函数内部

  3. 所有的这一个对象需要使用的属性都需要和self关联起来

  4. 执行完init中的逻辑之后,self变量会自动的被返回到调用处(发生实例化的地方)

  5. self可以修改,但是一般不改,约定俗成

面向对象基础方法

1、创建手机类模板

class ShouJi:
    pass

print(ShouJi)# <class '__main__.ShouJi'>

# 类是一个模型,使用类来创建对象:类名()
张一=ShouJi()
# 张一就是对象  张一=ShouJi()的过程 是通过类获取一个对象的过程 - 实例化(对象就是实例)
print(张一) #<__main__.ShouJi object at 0x000002D40D680DF0>
张二=ShouJi()
print(张二) #<__main__.ShouJi object at 0x000002D40D680D90>
张三=ShouJi()
张四=ShouJi()

在这里插入图片描述

说明:

对象

  1. 对象===实例
  2. 给类中所有的属性填上具体的值就是一个对象或者实例
  3. 只有一个类,但是可以有多个对象都是这个类的对象

实例化

  1. 实例 = 类名()
    首先开辟空间,调用init方法,把开辟的空间地址传递给self参数
    init方法中一般完成 : 把属性的值存储在self的空间里 - 对象的初始化
    self这个地址会作为返回值,返回给"实例"

  2. 方法 : 定义在类里的函数,并且还带有self参数

  3. 实例变量 : self.名字

2、模板添加属性

class ShouJi:
    品牌='华为'

# 类是一个模型,使用类来创建对象:类名()
张一=ShouJi()
print(张一) #<__main__.ShouJi object at 0x000002D40D680DF0>
 # 属性调用,通过对象.属性来调用
print(张一.品牌) #华为

张二=ShouJi()
print(张二) #<__main__.ShouJi object at 0x000002D40D680D90>
print(张二.品牌) #华为

张三=ShouJi()
张四=ShouJi()

在这里插入图片描述
3、模型修改
属性修改是模板中的不变,修改的是自己的属性,就好比王者荣耀中的个人所拥有的英雄
张一手机是苹果,不是华为

class ShouJi:
    品牌='华为'

张一=ShouJi()
print(张一) #<__main__.ShouJi object at 0x000002D40D680DF0>
print(张一.品牌) #修改之前的:华为
张一.品牌 = '苹果'
print(张一.品牌) #修改之后的:苹果
# 张一修改属性并不影响其他的

张二=ShouJi()
print(张二) #<__main__.ShouJi object at 0x000002D40D680D90>
print(张二.品牌) #华为

类中的属性

属性有类属性和对象属性,,在类中定义的属性叫做类属性(模型中的),在对象的属性叫做对象属性。是属于对象自己的
属性查找:先在对象自己的内存空间中查找,没有去类的内存空间中查找,不存在就报错
属性在自己内存空间找到,就不会再去模板的空间你去找

class Student:
    name='张一'
    age= 18

Student()

张一=Student()

在这里插入图片描述
2、动态对象属性
赋值操作永远作用的自己的内存空间,不会改变其他空间

class Student:
    name='张一'
    age= 18

张一=Student()
张一.age=20
print(张一.age)

在这里插入图片描述
3、类中的属性值如何修改
类中的属性值也叫做初始值,默认值
类属性通过类名去找

class Student:
    name='张一'
    age= 18

Student.name=20
print(Student.name)

类中的方法

类:类有什么属性,但不知道属性的值
对象:明确属性的值
python的数据类型属于类,内置的类
变量名=xx数据类型的对象
所以在python中一切皆对象,对象的类型就是类
所有的对象都有一个类型,class A实例化出来的对象的类型就是A类

类的成员和命名空间

class A:
    def __init__(self):pass#init是默认方法,函数在类中叫做绑定方法,存储在类的命名空间之中
    def fu1(self):pass#可以自定义方法
    def fu2(self):pass
    def fu3(self):pass
    国家='中国'#类中可以定义变量,是静态变量或者叫静态属性,存储在类的命名空间之中

print(A.__dict__)#查看A类中的命名空间
print(A.国家)

在这里插入图片描述

总结:
类中的变量是静态变量
对象中的变量只属于对象本身,每个对象有属于自己的空间来存储对象的变量
当使用对象名去调用某一个属性的时候会优先在自己的空间中寻找,找不到再去对应的类中寻找
如果自己没有就引用类的,如果类也没有就报错
对于类来说,类中的变量所有的对象都是可以读取的,并且读取的是同一份变量

__init__魔术方法

前面有__,后面__的都是魔术方法:__ 名字__()
init:初识的、初始化
创建对象之后,系统默认执行动作,不需要你调用
在这里插入图片描述

手机1在实例化的过程所进行的操作:
1、寻找内存空间是ShouJi类的地址
2、使用ShouJi类创建对象,开辟一块内存空间,与ShouJi类一样
3、对象创建完之后,去ShouJi类中找有没有__init__方法,没有的话,将内存空间给对象手机1,空间创建完成,
4、有__init__,则会进入__init__方法,执行里面的动作
5、__init__中的self得到的是对象的内存空间的地址
6、__init__执行完里面的方法在赋值给对象手机1

init:保证每个对象都存在里面的额属性

class ShouJi:
    def __init__(self): # 动态给self空间添加属性,就是对象的空间
        self.pinPai='华为'
        self.jiaGe=1000

    def call(self): # self是当前对象
        # print('self:',self)
        print('正在打电话')
        print('价格:',self.jiaGe)
手机1=ShouJi()
手机1.jiaGe=2000
手机1.call()

对象方法

1、对象方法,固定参数

class Student:
    def __init__(self):
        self.name='张一'
        self.age=18
        
    def eat(self):
        print('{}正在吃饭'.format(self.name))
        print('今年{}岁'.format(self.age))

st1=Student()
st1
st1.eat()

在这里插入图片描述

2、属性动态变化,魔术方法传参
外界传递的是什么就是什么

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

    def eat(self):
        print('{}正在吃饭'.format(self.name))
        print('{}今年{}岁'.format(self.name,self.age))

st1=Student(name='李四',age=20)
st1.eat()

创建对象的时候传递参数,会系统传递到init中,这些解释性自动去完成,传递的参数由模板中定义

3、普通方法带参数

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

    def eat(self,food):
        print('{}正在吃饭,吃的{}'.format(self.name,food))
        print('{}今年{}岁'.format(self.name,self.age))

st1=Student(name='李四',age=20)
st1.eat('烧烤')

4、同级的方法可以相互调用,通过self.方法名()

def eat(self):
    print('吃饭了')

def run(self):
    print('跑步中')
    self.eat()

类方法

通过装饰器来添加,在普通方法上添加@classmethod就是类方法
类方法属于类
普通方法,依赖对象存在,类方法不依赖对象,由类去调用
类方法里面的参数是cls,是class的简写
传参跟init用法一样

特点:
1、类方法定义需要@classmethod装饰器,传递的不是对象,而是类
2、类方法中的参数cls不是对象,而是类
3、类方法只能使用类属性,里面不能出现对象属性
4、可以不创建对象,通过类名来调用,调用方法:类名.属性名()
5、类中不能使用普通方法
6、类有自己的私有属性

作用:
只能访问类方法和类属性,所以在创建对象前,完成某些动作

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

    def eat(self,food):  # 普通方法,依赖对象存在
        print(6)
        # print('{}正在吃饭'.format(self.name))
        # print('{}今年{}岁'.format(self.name,self.age))

    @classmethod
    def xueXi(cls): # 类方法里面的参数是cls,是class的简写
        print(cls) #<class '__main__.Student'>,这里就是Student类

Student.xueXi()

类的私有属性

一般用于私有化,例如性别,年龄等
只有在我的这个范围才能修改,别人改不了
语法:在属性前面:__age=18,这种的就变成私有的了

1、私有方法创建
正常:未私有化之前

class Student:
    __age=18
    def show(self):
        print('>>>:',Student.age)

print(Student.age)

私有化时候,私有之后外部无法调用

class Student:
    __age=18
    def show(self):
        print('>>>:',Student.age)

print(Student.age) #AttributeError: type object 'Student' has no attribute 'age'

2、那如何操作呢
没有对象,通过类方法(装饰器)来操作,查看修改都是

class Student:
    __age=18

    @classmethod
    def updata(cls):
        print('年龄修改:')
        cls.__age=20

    @classmethod
    def show(cls):
        print('修改后的年龄:',cls.__age)

Student.updata()
Student.show()

静态方法

静态方法:类似于类方法,依赖于装饰器
1、需要装饰器装饰@staticmethod装饰
2、装饰的函数不需要参数,cls参数,self参数,可以自定义参数
3、静态方法只能访问类的属性、方法,对象的无法访问
4、加载时机同类方法一样

class Student:
    __age=18

    @classmethod
    def updata(cls):
        print('年龄修改:')
        cls.__age=20

    @classmethod
    def show(cls):
        print('修改后的年龄:',cls.__age)

    @staticmethod
    def static():
        print('我是静态方法')
        print(Student.__age)

Student.static()

加装饰器有参数是类方法,加装饰器没有参是静态方法
装饰器跟类差不多,但是没有cls参数

一、类方法与静态方法的异同:
不同:
1、装饰器不同
2、类方法有参,静态方法无惨
相同:
1、只能访问类的属性与方法,对象的无法访问
2、都可以通过类名访问调用
3、都可以在创建对象之前使用,不依赖于对象

二、普通方法与类方法、静态方法的不同
不同:
1、没有装饰器
2、需要对象,永远依赖于对象,每个普通方法都有一个self,代表对象本身
3、只有创建了对象(实例化)才可以调用普通方法,否则无法调用

特性

三大特征:封装、多态、继承

继承

不同的类中,有很多相同的方法,代码重复性高

  1. 继承就是解决重复的
  2. 继承之后,子类可以使用父类中的:方法、静态变量
  3. 子类和父类的方法重名的时候,我们只使用子类的方法,而不会去调用父类的方法了,就近选择,优先自己
  4. 子类想要调用父类的方法的同时还想执行自己的同名方法
    在子类的方法中调用父类的方法:父类型.方法名()
class B(A):pass
#类里面写另一个类的名字就是继承关系
# B继承A,A就是父类,也叫基类,超类,B是子类,也叫派生类
class ShouJiA:
    def __init__(self):
        self.pinPai='华为'
        self.jiaGe=1000

    def call(self): #
        print('正在打电话')
class ShouJiB(ShouJiA):
    pass

shouji=ShouJiB()
print(shouji.jiaGe) # 1000

多继承

继承:儿子继承爹把爷爷也加进来,不断往上继承
单继承可以继承N个

class D:
    def func(self):
        print('in D')
class C(D):pass
class A(C):
    def func(self):
        print('in A')
class B(A):pass
B().func()

多继承:有好几个爹

class B:
    def func(self):print('in B')
class A:
     def func(self):print('in A')

class C(B,A):pass
C().func()

一个类有多个父类,在调用父类方法的时候,按照继承顺序,先继承的就先寻找

写代码的时候,是先有的父类还是先有的子类?
在加载代码的过程中 需要先加载父类 所以父类写在前面

多继承的继承顺序问题

只要继承object类就是新式类
不继承object类的都是经典类

  • python3 所有的类都继承object类,都是新式类
  • 在py2中 不继承object的类都是经典类,继承object类的就是新式类了
  • 经典类 :在py3中不存在,在py2中不主动继承object的类
在py2中
class A:pass         # 经典类
class B(object):pass # 新式类
在py3中
class A:pass         # 新式类
class B(object):pass # 新式类

单继承

在单继承方面(无论是新式类还是经典类都是一样的)

class A:
    def func(self):pass
class B(A):
    def func(self):pass
class C(B):
    def func(self):pass
class D(C):
    def func(self):pass
d = D()
# 寻找某一个方法的顺序:D->C->B->A
# 越往父类走,是深度

多继承(钻石继承)

在经典类中,都是深度优先,总是在一条路走不通之后再换一条路,走过的点不会再走了
新式类在走到一个点,下一个点既可以从深度走,也可以从广度走的时候,总是先走广度,再走深度,广度优先

class A:
    def func(self):
        print('A')

class B(A):
    pass
    # def func(self):
    #     print('B')
class C(A):
    pass
    # def func(self):
    #     print('C')
class D(B,C):
    pass
    # def func(self):
    #     print('D')
print(D.mro())   # 只在新式类中有,经典类没有的
# d = D()
# d.func()

在这里插入图片描述

广度优先的算法:C3算法

算法的内容:
如果是单继承 那么总是按照从子类->父类的顺序来计算查找顺序
如果是多继承 需要按照自己本类,父类1的继承顺序,父类2的继承顺序,…

merge的规则 :如果一个类出现在从左到右所有顺序的最左侧,并且没有在其他位置出现,那么先提出来作为继承顺序中的一个;或 一个类出现在从左到右顺序的最左侧,并没有在其他顺序中出现,那么先提出来作为继承顺序中的一个

如果从左到右第一个顺序中的第一个类出现在后面且不是第一个,那么不能提取,顺序向后继续找其他顺序中符合上述条件的类
在这里插入图片描述

  • 经典类 - 深度优先 新式类 - 广度优先
  • 深度优先要会看,自己能搞出顺序来
  • 广度优先遵循C3算法,要会用mro,会查看顺序
  • 经典类没有mro,但新式类有

查看继承:新式类中有,经典类汇总不存在

class A:
    def func(self):
        print('A')

class B(A):
    pass
    # def func(self):
    #     print('B')
class C(A):
    pass
    # def func(self):
    #     print('C')
class D(B,C):
    pass
    # def func(self):
    #     print('D')
print(D.mro())   # 只在新式类中有,经典类没有的

多态

python当中处处是多态,一切皆对象
1、多态,一个类型表现出来的多种状态
同一事物有多种形态
可以再不考虑对象具体类型的情况下而直接使用对象

2、鸭子类型
Linux中的一切皆文件就是如此:鸭子类型

未完成,还有

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

浅水鲤鱼

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

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

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

打赏作者

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

抵扣说明:

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

余额充值