前言
经过长时间的百lian成钢系列咱们又回到了Python基础语法系列。今天给大家分享的是博主在去年学习Python的时候学到的类与对象系列。也算是博主对自己的学的知识进行一遍复习巩固吧。在阅读文章的时候如果大家有什么疑问的话可以及时的评论区或者私信联系博主。我会认真的写到每一个知识点,一方面巩固我的知识一方面便于你们进行理解。😉本篇博客会着重介绍概念,有相关方面基础的小伙伴可以跳过上集直接看下集。
💟什么是面向对象?
刚开始接触面向对象的小伙伴可能会很萌,这个面向"对象"可不是陪你一快上课一块吃饭的那个对象现实中的对象与编程语言上的对象虽然在职能上有一定的不同,但是其本质还是一样的。
在现实中:假如你某天比较忙,就可以给你对象说一声中午饭做好并在家等着你。你乖巧的对象很听话,做好了饭并等着你。然而做饭的细节你没有看到。看到的只是你给她的一个请求,得到的是一个结果。这仅仅是可以做的一件事。当然现实中的对象还可以做很多事:洗衣服、捶背、讲故事....能做多少事得看你的家庭帝位有多高或者你的对象会多少技能。你可以找一个会唱歌的对象天天给你唱歌、你可以找一个会跳舞的对象天天给你跳舞。当然了咱可不建议你这样做。现实中只找一个就好了。
在计算机中:对象依旧会完成你指定的一系列任务。你可以对其进行功能定制。你可以拥有多个。你是不是心动了?
💞面向过程思想案例实现
面向过程最经典的思想是什么呢?大家在上第一节C语言课的时候应该都听过蛋炒饭案例吧,就是说有天中午你很饿,然后要做蛋炒饭吃,首先你要学习做蛋炒饭、然后开火、放锅、加油、切菜淘米、再然后炒菜炒米,最后才吃。这一系列的操作下来之后一份香喷喷的蛋炒饭被你吃掉了。但是你要是再想吃一份糖醋里脊、荷香扣肉......你不得不自己再自己重复上述过程。一系列菜品让你自己做灰常的头疼,并且会有很大的浪费。但是你不得不按部就班的做,一步做不好就吃不到。
💞面向对象思想案例实现
经过前几次的做饭,你费尽了脑筋,所以你不得不动动脑子。你想到了你的好朋友小鸡、中鸡、大鸡,小鸡那里有一个产菜法宝,你只需要告诉他菜的名字他便会切好送给你,中鸡那里有一个万能菜单,你只需要将菜名给他他便会给你一些列的做菜教程。大鸡那里有一个万能锅,你只需要将做菜教程跟菜品放锅里面,不久就会有香喷喷的菜出锅。于是你站在你三个朋友的肩膀上发明了万能厨房(只需要报菜名、烹饪方式、火候)就会产出相应的菜。从此以后你的午饭再也不愁了。你的三个好朋友小鸡、中鸡、大鸡的法宝就可以看成一个个对象,而你面向这些对象根据他们的耦合关系进行组合得到了一个万能厨房系统。
💟面向对象在不同语言之间的区别
语言名称 | 是否支持继承 | 是否支持多继承 | 是否需要指定继承权限(类型) | 特别说明 |
C | × | - | - | 本身不支持继承,但是可以自己实现 |
C++ | √ | √ | √ | 无敌 |
JAVA | √ | × | √ | 安全、高效 |
Python | √ | √ | × | 灰常灵活 |
Golang | × | - | - | 支持组合类型,结构体可以组合各个接口 |
💟类与对象的基本概念
💞类的基本概念
类在平时生活中代表了一类有共同特性的事务,比如一群老虎、一窝蚂蚁、一片森林....每一类都有属于他自己的特色,而人们可以通过相关的特性进行抽象,总能抽象出该类所共有一系列的特征。类在平时看来是抽象的是人为定义的一个概念。
在Python中万物皆对象,所以类也属于对象的范畴,只不过比较特殊使用类可以生成一系列的对象。
💞对象的基本概念
在前面咱们也提到了对象可以为你做很多事情,只要是你提出来的基本都会帮你做还会对你不离不弃。如果你有需要你还可以亲手定制对象的功能。能为你做事的就是对象。 |
在Python中对象与其他语言的本质没有太大不同。 |
💟面向对象的三大特性
💞封装
把客观事务或群体的特性抽象出来存进类内,通过访问控制将某些特殊属性隐藏起来仅供可信赖的对象进行访问、修改。此时就是将属性封装了起来。Python中进行属性或方法的封装是要在属性前加两个下划线。eg:
class T: def __init__(self): self.__name="Tom"
💞继承
鸟的品种有很多种,所有不同品种的鸟都属于鸟类,所以可以将所有不同品种的鸟的特征进行二次抽取,抽出所有鸟的共同特征,存放进鸟类,然后其他不同品种的鸟通过继承鸟类中的属性实现他原本应有的基本属性。继承是为了便于对程序进行维护和修改。
-------重点-------:Python中继承后子类生成对象时不会自动调用父类的构造函数,需要自己使用super().__init__()进行初始化父类属性。或者父类类名.__init__()
class T: def __init__(self): self.name="Tom" class Y(T): y=100 def __init__(self): super().__init__() def pr(self): print(self.name) def countadd(self): Y.y+=1
💞多态
在编程中多态是指一段代码可以根据传入的对象不同展现出不同的效果或者说一个对象可以表现出多个类型的能力。 |
💟Python中的面向对象
💞类对象
类对象通过关键字class进行声明语法如下:(默认继承自object) |
class Person: pass • 1 • 2
类属性
类属性属于整个类,并不属于某个实例,是所有对象的共有的一个副本,实例对象可以使用类属性,只不过从他开始使用那一刻开始,类属性就变成他自己的属性了。如果一个对象一直没有使用类属性,那么他所对应的类属性值一直为类属性的值。 |
特殊类属性
class.__name__:查看类的名字
class.__base__:类的基类
class.__bases__:类的基类组
class.__qualname__:类的限定名称
class.__mro__:基类的元组
class.__subclasses__:子类列表
class.mro():基类元组,可以被子类重写
类方法
值得注意的是类方法不对特定的实例进行操作,在类方法中访问实例方法会报错。声明类方法需要在方法前面加上@classmethod装饰器。类方法的第一个参数一般以cls命名,可以自己进行改动。 |
💞实例对象
实例属性
实例属性应在类的方法中声明 |
一般属性
对象的一般属性有两种声明方式:
使用时进行赋值(可以动态的增加属性,也是无敌了)
函数中进行赋值(构造函数,如果是一般的函数会不符合逻辑)
特殊属性
__dict__属性字典(可以看该对象有哪些属性与方法)
__class__对象所属类
魔法方法
__init__:构造方法,对实例对象的属性进行初始化
__new__:返回一个对象,该对象还没有进行初始化,只是开好空间对象创建会先调用new函数然后调用init
__del__:析构函数,销毁对象占有的空间
__len__:返回对象的长度
__str__:返回对象对应的字符串,自己定制可以直接print对象
__call__:把对象像调用函数一样调用,执行相应的操作
__add__:两个对象相加(结果返回一个对象)
__sub__:两个对象相减(结果返回一个对象)类似的还有乘、加等、减等…
__eq__:判断两个对象是否相等(可以根据某个属性或者某些属性进行判断)最后返回bool
__iter__:实现了该方法,对象变为可迭代对象,返回值应为对象本身
__next__:实现了该方法的对象是迭代器。可以获取下一状态的结果。
…类似的还有很多有用的时候baidu一下即可。
使用方法如下:
设计一个三维向量类,并实现向量的加法、减法以及向量与标量的乘法和除法运算(要求重载__add__、sub、__mul__等方法)。
class ope(): def __init__(self,a,b,c): self.a=a self.b=b self.c=c def __add__(self,t): temp=ope(self.a+t.a,self.b+t.b,self.c+t.c) return temp def __sub__(self,t): temp=ope(self.a-t.a,self.b-t.b,self.c-t.c) return temp def __mul__(self,t): temp=ope(self.a*t.a,self.b*t.b,self.c*t.c) return temp def __str__(self): return f"a:{self.a} b:{self.b} c:{self.c}" def lenth(self): return (self.a**2*self.b**2*self.c)**0.5 a1=ope(1,2,3) a2=ope(2,3,4) a3=a1+a2 a4=a1-a2 a5=a1*a2 print(a3) print(a4) print(a5) print(a3.lenth())
💞静态属性
静态方法不可以访问实例对象的属性,可以通过类对象或者实例对象进行调用静态方法的定义,要在方法的上面注明@staticmethod装饰器(在Python中静态方法通常用于处理传进来的参数) |
如果敲代码有不会的地方的话,可以先看看下面练习案例:
# 类的声明(三种方法,两种变量) print('-----------------类的定义----------------------') class A: # 静态函数声明 name='张三' def __init__(self,name,age): print('构造函数被调用') self.name=name self.age=age def printf(self): myname='李四' print('我是'+A.name+'我爸是'+myname) @staticmethod def printf1(): print('我是'+A.name) @classmethod def printf2(cls): print('我是'+A.name) def eat(): print('A吃东西') # 重写类的str方法,在print类的时候直接按指定的方式进行输出 # 没有重写该方法之前,打印对象的地址属性 # <__main__.A object at 0x000001F661BC8F10> <__main__.A object at 0x000001F661BC8A60> def __str__(self) -> str: return '我是{0}'.format(self.name) def __add__(self,other): return self.name+other.name def __len__(self): return len(self.name) print('-----------------实例对象的声明----------------------') a=A('王五',20) a.printf1() a.printf2() # a.printf() A.printf(a) A.printf1() A.printf2() b=A('陈六',22) print(a,b) print('-----------------动态属性的绑定----------------------') # 动态属性绑定 # 动态的属性绑定,只针对该对象有效 a.sex='男' print(a.sex) # 以下代码运行出错 # print(b.sex) # 动态方法绑定 def fine(): print('I am Fine') b.f=fine b.f() # 以下代码报错 # a.f() print('-----------------类对象与实例对象----------------------') ''' 类对象:一个类就是一个对象 实例对象:一个类的实现就是实例对象 ''' # A是一个类型 print(type(A)) # a的类别是__main__.A print(type(a)) print('-----------------类的封装----------------------') # 想要不被外界访问,就在属性或者方法前面加上两个__ class B: def __init__(self,name,age,sex): # 封装属性 self.__name=name self.__age=age self.sex=sex def __msg(): print('私有属性') def passage(self): print('我叫',self.__name,'我今天',self.__age,'我的性别是',self.sex) B.__msg() def eat(): print('B吃东西') pig=B('小朱佩奇',20,'男') B.passage(pig) pig.passage() #print(pig.__name) 这一句无法输出,原因是name属性被隐藏起来了,没有权限访问 print(pig.sex) # 以下两个方法没有办法打印 # print(B.__msg()) # print(pig.__msg()) print('-----------------类的继承----------------------') # 继承语法极为简单,直接在类的后面加上一个括号,支持多继承 # 继承子类,必须在构造方法中调用父类的构造方法 class C(B,A): def __init__(self, name, age, sex,money): super().__init__(name, age, sex) self.money=money def msage(self): print(super().passage(),self.passage(),self.money) def eat(self): print('C吃东西') c=C('王八',20,'男',24000) c.msage() print('-----------------类的多态----------------------') # python中的多态,不在乎类对象之间的关系,只关心方法是否一致 # 静态语言(java,c++)等实现多态要进行的步骤有:继承、方法重写、引用指向不同对象 # 动态语言中,直接只关注对象的行为 def show(obj): obj.eat() show(A) show(B) show(C) print('-----------------类的特殊属性----------------------') # 类的特殊属性dict(以字典的方式,将对象的属性名,及对应的属性打印出来) print(a.__dict__) # 查看对象有哪些属性 print(dir(a)) print(a.__class__) print('-----------------类的特殊方法----------------------') # 方法的重写add,len(add与len是基本的运算方法,实例对象无法直接使用,需要重写后调用) a=a+b print(a) # len测试的数据没有的话会报错 print(len(a)) print('-----------------类的祖先object----------------------') # 按照顺序打印,继承了哪些类 print(C.__mro__) # 查看直接继承的子类 print(A.__base__) print(A.__bases__) print(C.__bases__) print('-----------------类的创建过程----------------------') ''' 类创建的过程 cls是类对象在创建p1的时候先将person的id传进object的new函数中,获得一个创建好的对象obj 也就是init函数中的self,在new中创对象,在init函数中进行初始化,初始化完毕后将最终获取的 对象赋值给变量 ''' class Person(object): def __new__(cls,*args,**kwargs): print('new函数执行,cls的值为{0}'.format(id(cls))) obj=super().__new__(cls) print('创建的对象id为:{0}'.format(id(obj))) return obj def __init__(self,name,age): print('init函数被调用,self的id值为:{0}'.format(id(self))) self.name=name self.age=age print('object类对象的id为:{0}'.format(id(object))) print('person类对象的id为:{0}'.format(id(Person))) p1=Person('张三',18) print('p1这个person实例对象的id为{0}'.format(id(p1))) print('-----------------类的浅拷贝----------------------')
到此面向对象上集已经结束了,再来回顾一下,上集主要介绍到了什么是面向对象编程,什么是类、什么是对象、什么是面向过程编程、什么试试面向对象编程、魔法函数都有哪些?。你有大致的印象了吗?下集主要对类的装饰器、迭代器、生成器进行相关的介绍欢迎大家持续关注。