当前位置: 首页 > news >正文

Python面向对象编程

05、Python面向对象

5.1、oop介绍

面向对象编程 oop 【object oriented programming】是一种Python的编程思路

  • 面向过程:
    在思考问题的时候,怎么按照步骤去实现,
    然后将问题解决拆分成若干个步骤,并将这些步骤对应成方法一步一步的最终完成功能
  • 面向过程:就是一开始学习的,按照解决问题步骤去编写代码【根据业务逻辑去写代码】
  • 面向对象:关注的是设计思维【找洗车店, 给钱洗车】
  • 从计算机角度看:面向过程不适合做大项目
  • 面向过程关注的是:怎么做
  • 面向对象关注的是:谁来做

5.2、类和对象

  • 类:是一个模板,模板里包含多个函数,函数里实现一些功能

  • 对象:则是根据模板创建的实例,通过实例对象可以执行类中的函数

  • 类由3部分构成:

    • 类的名称:类名
    • 类的属性:一组数据
    • 类的方法:允许对进行操作的方法(行为)

例如:创建一个人类
事物的名称(类名):人(Person)
属性:身高,年龄
方法;吃 跑…

  • 类是具有一组 相同或者相似特征【属性】和行为【方法】的一系列对象的集合

现实世界 计算机世界
行为------》方法
特征------》属性

  • 对象:是实实在在的一个东西,类的具象化 实例化
  • 类是对象的抽象化 而对象是类的实例

5.3、定义类

#定义类和对象
#类名:采用大驼峰方式命名


#创建对象
#对象名=类名()
'''

class 类名:
    属性
    方法

'''
#实例方法 :
# 在类的内部,使用def关键字可以定义一个实例方法,与一般函数 定义不同,类方法必须包含参数self【self可以是其他的名字,但是这个位置必须被占用】,且为第一个参数
#属性:在类的 内部定义的变量
#定义在类里面,方法外面的属性成为类属性,定义在方法里面使用self引用的属性称之为实例属性
class Person:
    '''
    对应人的特征
    '''
    name='小勇'   #类属性
    age=22       #类属性
    '''
    对应人的行为 
    '''

    def __int__(self):
        self.name = '小赵'#实例属性
    def eat(self):#实例方法
        print('狼吞虎咽的吃')
    def run(self):#实例方法
        print('飞快地的跑')


#创建对象【类的实例化】
xm=Person()
xm.eat()#调用函数
xm.run()
print('{}的年龄是{}'.format(xm.name,xm.age))

5.4、__init__方法

# 如果有n个这样对象 被实例化,那么就需要添加很多次实例属性,显然比较麻烦
class Person1:
    def __init__(self):#魔术方法
        '''
        实例属性的声明
        '''
        self.name='小勇'
        self.age=22
        self.sex='男生'
    def run(self):
        print('跑太快了吧')
xy=Person1()
# xy.run()
print(xy.age)

5.5、self理解

  • self和对象指向同一个地址,可以认为self就是对象的引用
  • 在实例化对象时,self不需要开发者传参,Python自动将对象传递给self
  • self只有类中定义实例方法的时候才有意义,在调用的时候不必传入相应的参数,
  • 而是由解释器自动取指向
  • self的名字时可以更改的,可以定义成其他的名字,只是约定俗成的定义成了self
  • self指的是类实例对象本身
class Person:
    def __init__(self,pro):
        self.pro=pro
    def geteat(s,name,food):
        # print(self)
        print('self在内存中的地址%s'%(id(s)))
        print('%s喜欢吃%s,专业是:%s'%(name,food,s.pro))

zs=Person('心理学')
print('zs的内存地址%s'%(id(zs)))
zs.geteat('小王','榴莲')

5.6、魔术方法

魔术方法: __ xxx __


'''
__init__ 方法:初始化一个类,在创建实例对象为其赋值时使用
__str__方法 : 在将对象转换成字符串str(对象)测试的时候,打印对象的信息
__new__方法 : 创建并返回一个实例对象,调用了一次,就会得到一个对象
__class__方法 : 获得已知对象的类(对象__class__)
__del__方法:  对象在程序运行结束后进行对象销毁的时候调用这个方法,来释放资源
'''

class Animal:
    def __init__(self,name,color):
        self.name=name
        self.color=color
        print('--------init-------')

    def __str__(self):
        return '我的名字是%s,我的颜色为%s'%(self.name,self.color)

    def __new__(cls, *args, **kwargs):
        print('--------new-------')
        return object.__new__(cls)
dog =Animal('旺财','黑色')
print(dog)


'''
__new__和__init__函数区别
__new__类的实例化方法:必须返回该实例 否则对象就创建不成功
__init__用来做数据属性的初始化工作,也可以认为是实例的构造方法,接收类的实例 self 并对其进行构造
__new__至少有一个参数是cls是代表要实例化的类,此参数在实例化时由Python解释器自动操作
__new__函数执行要早于__init__函数
'''


5.7、析构方法


'''
当一个对象被删除或者被销毁是,python解释器会默认调用一个方法,这个方法为__del__()方法,也被成为析构方法
'''
class Animals:
    def __init__(self,name):
        self.name=name
        print('这是构造初始化方法')
    def __del__(self):
        print('当在某个作用域下面,没有被引用的情况下,解释器会自动调用此函数,来释放内存空间')
        print('这是析构方法')
        print('%s 这个对象被彻底清理了,内存空间被释放了'%self.name)


cat=Animals('猫猫')
# del cat #手动的清理删除对象
input('程序等待中......')

#当整个程序脚本执行完毕后会自动的调用_del_方法
# 当对象被手动摧毁时也会自动调用_del_方法
# 析构方法一般用于资源回收,利用_del_方法销毁对象回收内存资源


5.8、单继承

Python中展现面向对象的三大类型: 封装,继承,多

  1. 封装:值得是把内容封装到某个地方,便于后面的使用
    他需要:
    把内容封装到某个地方,从另外一个地方去到调用被封装的内容
    对于封装来说,其实就是使用初始化构造方法将内容封装到对象中,然后通过对象直接或者self来获取被封装的内容
  2. 继承:和现实生活当中的继承是一样的,也就是子可以继承父的内容【属性和行为】(爸爸有的儿子有, 相反, 儿子有的爸爸不一定有),
  3. 所谓多态,定义时的类型和运行时的类型是不一样,此时就成为多态

class Animal:
    def eat(self):
        '''
        吃
        '''
        print('吃')
    def drink(self):
        '''
        喝
        '''
        print('喝')

class Dog(Animal):#继承Animal父类,  此时Dog就是子类
    def wwj(self):
        print('汪汪叫')
class Cat(Animal):
    def mmj(self):
        print('喵喵叫')
d1=Dog()
d1.eat()#继承了父类的行为
d1.wwj()
c1=Cat()
c1.drink()
c1.eat()

'''
对于面向对象的继承来说,其实就是将多个子类共有的方法提取到父类中,
子类仅仅需要继承父类而不必一一去实现
这样就可以极大提高效率,减少代码的重复编写,精简代码的层级结构 便于扩展

class 类名(父类):
    pass
'''

5.9、多继承

class shenxian:
    def fly(self):
        print('神仙会飞')

class Monkey:
    def chitao(self):
        print('猴子喜欢吃桃子')
class SunWuKong(shenxian,Monkey):
    pass

swk=SunWuKong()
swk.fly()
swk.chitao()

#当多个父类当中存在相同方法时候,
class D:
    def eat(self):
        print('D.eat')
class C(D):
    def eat(self):
        print('C.eat')
class B(D):
    pass
class A(B,C):
    pass

a=A()
# b=B()
a.eat()
print(A.__mro__)#可以现实类的依次继承关系      查找执行顺序
#在执行eaet方法时,顺序应该是
#首先到A里面去找,如果A中没有,则就继续去B类中去查找,如果B中没有,则去C中查找,
#如果C类中没有,则去D类中查找,如果还没有找到,就会报错
#A-B-C-D 也是继承的顺序


5.10、重写父类方法

  • 所谓重写,就是子类中,有一个和父类相同名的方法,在子类中的方法会覆盖掉子类中同名的方法,
  • 为什么要重写,父类的方法已经不满足子类的需要,那么子类就可以重写父类或者完善父类方法


class Father:
    def smoke(self):
        print('抽芙蓉王')
    def drink(self):
        print('喝二锅头')
class Son(Father):
    #与父类的(抽烟)方法同名,这就是重写父类方法
    def smoke(self):
        print('抽中华')

#重写父类方法后,子类调用父类方法时,将调用的是子类的方法
son=Son()
son.smoke()


5.11、多态

  • 所谓多态,定义时的类型和运行时的类型是不一样,此时就成为多态

#要想实现多态,必须有两个前提需要遵守:
'''
1.继承:多态必须放生在父类和子类之间
2.重写:子类重写父类的方法
'''
class Animal:
    '''
    基类[父类]
    '''
    def say(self):
        print('我是一个动物'*10)
class Dark(Animal):
    '''
    子类【派生类】
    '''
    def say(self):
        '''
        重写父类方法
        '''
        print('我是一个鸭子'*10)
class Dog(Animal):
    def say(self):
        print('我是一只🐕'*10)
# dark=Dark()
# dark.say()


#统一的去调用
def  commonInvoke(obj):
    obj.say()
list=[Dark(),Dog()]
for item in list:
    '''
    循环调用函数
    '''
    commonInvoke(item)


5.12、类属性和实例属性

  1. 类属性:就是类对象拥有的属性,它被所有类对象的实例对象所共有,类对象和实例对象可以访问
  2. 实例属性:实例对象所拥有的属性,只能通过实例对象访问

class Student:
    name ='黎明'#属于类属性,就是Student类对象所拥有
    def __init__(self,age):
        self.age=age #实例属性

lm=Student(18)
print(lm.name)
print(lm.age)
print(Student.name)#通过Student类对象访问name属性
# print(Student.age)#类对象不能访问实例属性

#类对象可以被类对象和实例对象共同访问使用的
#实例对象只能实例对象访问



5.13、类方法和静态方法

  • 类方法的第一个参数是类对象cls,通过cls引用的类对象的属性和方法
  • 实例对象的第一个参数是实例对象self,通过self引用的可能是类属性,也可能是 实例属性
    ,不过在存在相同名称的类属性和实例属性的情况下,实例属性的优先级更高
  • 静态方法中不需要额外定义参数,因此在静态方法中引用类属性的话,必须通过类对象来引用

class People:
    country='china'
    @classmethod #类方法 用classmethod进行修饰
    def get_country(cls):
        return  cls.country#访问类属性
    @classmethod
    def change_country(cls,data):
        cls.country=data#修改列属性的值,在类方法中
    @staticmethod
    def gatData():
        return People.country
    @staticmethod
    def add(x,y):
        return x+y

print(People.gatData())
p=People()
print(p.gatData())#注意:一般情况下,我们不会通过实例对象去访问静态方法
print(People.add(1,2))
# print(People.get_country())#通过类对象去引用
# p=People()
# print('通过实例对象访问',p.get_country())
# People.change_country('英国')
# print(People.get_country())

#由于静态方法主要来存放逻辑性的代码,本身和类以及实例对象没有交互
#也就是说,在静态方法中,不会涉及到类中方法和属性的操作
#数据资源能够得到有效的充分利用


import time
class TimeTest:
    def __init__(self,hour,minute,second):
        self.hour=hour
        self.minute=minute
        self.second=second

    @staticmethod
    def showTime():
        return time.strftime('%H:%M:%S',time.localtime())
print(TimeTest.showTime())
# t=TimeTest(2,10,11)
# print(t.showTime())#没必要通过实例对象访问静态方法


5.14、私有化属性

  • 语法:

    • 两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问
  • 使用私有化属性的场景

    1. 把特定的一个属性隐藏起来,不想让类的外部进行直接调用
    2. 我想保护这个属性,不想让属性的值随意的改变,
    3. 保护这个属性,不想让派生类【子类】去继承
  • 要想访问私有变量一般是写两个方法,一个访问,一个修改,由方法去控制访问

class Person:
__age =18 #实例一个私有化属性,属性名字前面加两个下划线
‘’’





class Person:
    __hobby = 'dance'

    def __init__(self):
        self.__name = '李四'  # 加两个下划线将此属性私有化,不能再外部直接访问,在类的内部可以访问
        self.age = 30

    def __str__(self):
        return '{}的年龄是{},喜欢{}'.format(self.__name, self.age, Person.__hobby)  # 调用私有化属性

    def change(self, hobby):
        Person.__hobby = hobby


class Studeng(Person):
    def printInfo(self):
        # print(self.__name)#访问不了父类中的私有属性
        print(self.age)

    pass


xl = Person()
# print(xl.name)#通过类对象,在外部访问的
print(xl)
xl.change('唱歌')  # 修改私有属性的值
print(xl)
stu = Studeng()
stu.printInfo()
stu.change('Rap')
print(stu)
# print(xl.hobby)  # 通过实例对象访问类属性
# print(stu.hobby)  # 通过实例对象访问类属性
# print(Person.hobby)  # 通过类对象访问类属性


  • 小结:

    1. 私有化的【实例】属性,不能在外部直接的访问,可以在类的内部随意的使用
    2. 子类不能继承父类的私有化属性,【只能继承父类公共的属性和行为】
    3. 在属性名的前面直接加__,就可以将其私有化
  • 单下划线、 双下划线、 头尾双下划线三者区别

_xxx前面加下划线,以单下划线开头表示的是protected类型的变量,即保护类型只能允许其本身与子类进行访问,不能使用from xxx import *的方式导入
__xxx__前后两个下划线,魔术方法,一般是python自带的,开发者不要创建这类型的方法
xxx_后面单下划线,避免属性名与Python关键字冲突


5.15、私有化方法

  • 概述
    • 私有化方法跟私有化属性一样,有些重要的方法,不允许外部调用,防止子类意外重写,把普通的方法设置成私有化方法
    • 私有化方法一般是类内部调用,子类不能继承外部不能调用
  • 语法

class A:
def __myname(self): #在方法名前面加两个下划线
print(‘小明’)




class Animal:
    def __eat(self):
        print('吃东西')

    def run(self):
        self.__eat()  # 在此调用私有化方法
        print('飞快地跑')


class Bird(Animal):
    pass


bird = Bird()
bird.run()


5.16、Property函数

#  属性函数 (property)
class Perons:
    def __init__(self):
        self.__age = 18

    def ger_age(self):#访问私有实例属性
        return self.__age

    def set_age(self, age):#修改私有实例属性
        if age < 0:
            print('年龄太小')
        else:
            self.__age = age

    #定义一个类属性,实现通过直接访问属性的形式去访问私有属性
    age=property(ger_age,set_age)
p=Perons()
print(p.age)
p.age=-1
print(p.age)

5.17、__new__方法

image.png

  • new方法在init方法之前执行
class A(object):
    def __init__(self):
        print("__init__执行了")

    def __new__(cls, args, **kwargs):
        print("__new__执行了")
        return object.__new__(cls)  # 调用父类的new方法


a = A()  # 实例化的过程会自动调用__new__方法取创建实例

运行结果如下:

image.png

5.18、单例模式

单例模式:是一种常用的软件设计模式

目的:确保某一个类只有一个实例存在

如果希望在某个系统中只能出现一个实例,那么单例对象就能满足要求

# 创建一个单例对象,基于__new__去实现


class DataBaseClass(object):
    def __new__(cls, *args, **kwargs):
        # cls._instance=cls.__new__(cls)不能使用自身的new方法,容易造成深度递归,应该调用父类的new方法
        if not hasattr(cls, "_instance"):  # 如果不存在,就开始创建
            cls._instance = super().__new__(cls, *args, **kwargs)
        return cls._instance


db1 = DataBaseClass()
print(id(db1))
db2 = DataBaseClass()
print(id(db2))

5.19、异常处理

不需要在每个可能出错的地方捕获,只要在合适的层次去捕获错误就可以

#语法格式:
try:
	可能出错的代码块
except:
	出错后执行的代码块
else:
	没有出错的代码块
finally:
	不管有没有错都执行的代码块

try-except

  • except在捕获错误类型的时候,主要根据具体的错误类型来捕获的
  • 用一个try可以捕获多个不同类型的异常

code 1:


try:
    print(b) #这里是要捕获的代码

except NameError: #指定错误类型为NameRrror
    #捕捉到错误会在这里执行
    print("NameError")

code 2:

try:
    print(b) #这里是要捕获的代码

except NameError as msg:
    #捕捉到错误会在这里执行
    print(msg)

code 3:

try:
   
    li=[1,2,54,78] #这里是要捕获的代码
    print(li[10])
    a=10/0
except NameError as msg:
    #捕捉到错误会在这里执行
    print(msg)

except IndexError as msg:
    print(msg)
except ZeroDivisionError as msg:
    print(msg)

code 4:

try:
    a=10/0
except Exception as msg:
    print(msg)
  

code 5:

def A(s):
    return 10/int(s)
def B(s):
    return A(s)*2
def main():
    try:
        B("0")
    except Exception as msg:
        print(msg)

main()
#不需要在每个可能出错的地方捕获,只要在合适的层次去捕获错误就可以

try-except-else

try:
    print (aa)
except Exception as msg:
    print(msg)
else:
    print("当try里面没有错误。else才会执行")

try-except-else-finally

try:
    print (aa)
except Exception as msg:
    print(msg)
else:
    print("当try里面没有错误。else才会执行")
finally:
    print("不过有没有错都执行")

自定义异常

  • 自定义异常,都要直接或者间接的继承 ErrorException
  • 由开发者主动抛出自定义异常,在python中使用 raise关键字
class ToolsMyException(Exception):
    def __init__(self, leng):
        self.leng = leng

    def __str__(self):
        return "您输入的的姓名长度是"+str(self.leng)+"已经超过长度"
  
def name_Test():
    name=input("请输入姓名")
    try:
        if len(name)>5:
            raise ToolsMyException(len(name))
        else:
            print(name)
    except ToolsMyException as result:
        print(result)
    finally:
        print("执行完毕-------")

name_Test()

相关文章:

  • java计算机毕业设计霍山石斛网站源码+数据库+系统+lw文档+mybatis+运行部署
  • Python文件处理与垃圾回收机制
  • java计算机毕业设计基于MVC框架的在线书店设计源码+数据库+系统+lw文档+mybatis+运行部署
  • 计算机毕业设计springboot+vue基本微信小程序的外卖点餐订餐平台
  • 文件用手机拍照片打印时,打印出来总是有黑阴影,如何去掉黑色阴影打印清晰的图片
  • okhttp3与旧版本okhttp的区别分析
  • 学习C++第二课
  • Java连接池详解
  • 面向对象编程——类与对象(C#)(未写完)
  • 军品研制过程参考标准
  • 开学季,学长带你认识新生活
  • R语言data.table导入数据实战:data.table数据列索引
  • Java 基础三:使用Velocity模板生成 xml
  • 《华为数据之道》总结(上篇)
  • 【牛客 - 剑指offer / 快速幂】JZ16 数值的整数次方 两种方案(直接运算、快速幂) Java实现
  • ----------
  • 【399天】跃迁之路——程序员高效学习方法论探索系列(实验阶段156-2018.03.11)...
  • 【跃迁之路】【444天】程序员高效学习方法论探索系列(实验阶段201-2018.04.25)...
  • CSS中外联样式表代表的含义
  • ECMAScript 6 学习之路 ( 四 ) String 字符串扩展
  • java小心机(3)| 浅析finalize()
  • KMP算法及优化
  • Mysql数据库的条件查询语句
  • python 装饰器(一)
  • ReactNativeweexDeviceOne对比
  • Service Worker
  • Spring框架之我见(三)——IOC、AOP
  • Webpack4 学习笔记 - 01:webpack的安装和简单配置
  • 从地狱到天堂,Node 回调向 async/await 转变
  • 猫头鹰的深夜翻译:JDK9 NotNullOrElse方法
  • 配置 PM2 实现代码自动发布
  • 前端每日实战:70# 视频演示如何用纯 CSS 创作一只徘徊的果冻怪兽
  • 设计模式 开闭原则
  • 算法之不定期更新(一)(2018-04-12)
  • 3月27日云栖精选夜读 | 从 “城市大脑”实践,瞭望未来城市源起 ...
  • Semaphore
  • ​猴子吃桃问题:每天都吃了前一天剩下的一半多一个。
  • # .NET Framework中使用命名管道进行进程间通信
  • #使用清华镜像源 安装/更新 指定版本tensorflow
  • $.ajax,axios,fetch三种ajax请求的区别
  • $refs 、$nextTic、动态组件、name的使用
  • ( 用例图)定义了系统的功能需求,它是从系统的外部看系统功能,并不描述系统内部对功能的具体实现
  • (12)目标检测_SSD基于pytorch搭建代码
  • (ctrl.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“
  • (附源码)spring boot校园拼车微信小程序 毕业设计 091617
  • (算法)Game
  • (淘宝无限适配)手机端rem布局详解(转载非原创)
  • *1 计算机基础和操作系统基础及几大协议
  • .h头文件 .lib动态链接库文件 .dll 动态链接库
  • .NET Project Open Day(2011.11.13)
  • .net 简单实现MD5
  • .net 中viewstate的原理和使用
  • .NET基础篇——反射的奥妙
  • .NET值类型变量“活”在哪?
  • .sdf和.msp文件读取