一、上堂回顾
1.默写题目
1.简述面向过程和面向对象的区别
a.面向过程 思路:问题是怎样分步解决的,然后亲力亲为的去解决【执行者】 代码:代码从上往下依次执行 b.面向对象: 思路:将复杂的问题简单化,找到一个具有特殊功能的具体的个体,委托这个个体帮忙完成某件事情 代码:类和对象2.简述类和对象之间的联系与区别
类:将多个具有特殊功能的个体进行提取,提取相同的特征和行为【类是一个抽象的模板】 对象:在一个指定的类中,具体的存在 包含关系3.定义一个类,在类中书写构造函数和成员函数,并在类外面创建对象,调用成员函数
class MyClass(): #name = "" #构造函数 #注意1:创建对象 在其中定义成员变量 #注意2:self的作用:区分成员变量还是局部变量 #注意3:self的含义:当前类的实例 def __init__(self,name,age): self.name = name self.age = age #注意4:成员函数和普通函数之间的区别和联系 def show(self): pass m = MyClass("lisi",10) m.show()
2.知识点回顾
作业:
textDemo01.py
#.定义一“圆”(Circle)类,圆心为“点”Point类,构造一圆,求圆的周长和面积,并判断某点与圆的关系 #测试类 """ 分析: Circle: 特征:圆心,半径 行为;圆的周长和面积 Point: 特性:x y """ from homework.circle import Circle from homework.point import Point import math #1.创建一个圆心的对象 circlePoint = Point(10,20) #2.创建一个圆的对象 ci = Circle(8,circlePoint) #半径,x坐标,y坐标 print(ci.radius,ci.circlePoint.x,ci.circlePoint.y) #3.求圆的面积和周长【调用成员函数】 print(ci.area()) print(ci.zhouChang()) #4.判断某一点和圆之间的关系 #创建某一个点的对象 myPoint = Point(33,55) result = (circlePoint.x - myPoint.x) ** 2 + (circlePoint.y - myPoint.y) ** 2 distance = math.sqrt(result) if distance > ci.radius: print("圆外") elif distance < ci.radius: print("圆内") else: print("圆上")circle.py
class Circle(): #构造函数 def __init__(self,radius,circlePoint): self.radius = radius #半径 self.circlePoint = circlePoint #圆心,是一个点的对象 #成员函数 #求面积 def area(self): return 3.14 * self.radius ** 2 #求周长 def zhouChang(self): return 2 * 3.14 * self.radiuspoint.py
class Point(): #构造函数 def __init__(self,x,y): self.x = x self.y = y
二、析构函数
构造函数:创建对象的时候第一个被自动调用的函数 __init__ 和构造函数相反,当对象被销毁的时候自动调用的函数,被称为析构函数 __del__ 对象什么时候被销毁:程序执行完毕,使用del删除 使用场景:对象即将被销毁的时候需要做的一些工作,比如关闭文件,关闭数据库,关闭各种资源代码演示:
import time class Pig(): #构造函数 def __init__(self,name,age): self.name = name self.age = age print("构造函数被调用") #析构函数 def __del__(self): print("析构函数被调用") p = Pig("小白",10) #释放对象 #del p #注意:对象释放以后将不能再访问【相当于该对象未被创建过】 #print(p.name) #NameError: name 'p' is not defined time.sleep(3) #注意:在函数中创建的对象,其实还是一个局部变量,会在函数执行完毕之后被自动释放 def func(): p1 = Pig("",0) func()
面向对象语言的三大特征:封装,继承,多态
扫描二维码关注公众号,回复: 2857726 查看本文章![]()
是什么?
如何使用?
有什么样的作用?
三、封装
1.概念
广义的封装:函数和类的定义本身,就是封装的体现
狭义的封装【在面向对象中的封装】:一个类的某些属性,在使用的过程中,如果不希望被外界直接访问,就可以将该属性作为私有的【private,只有当前类持有】,然后暴露给外界一个访问的函数即可【间接的访问属性】
封装的本质:就是属性私有化的过程
封装的好处:提高了数据的安全性,提高了数据的复用性
说明:举例:插排【不需要关心属性在类的内部做了什么样的操作,只需要关心将值传进去,获取将结果获取出来】
2.属性私有化
如果想要属性不能被外界直接访问,则可以在属性名称的前面添加两个下划线__,此时称该属性为私有属性【私有成员变量】
私有属性的特点:只能在类的内部被直接访问,在外界不能直接访问
代码演示:
#1.属性不私有化的时候 class Person1(): def __init__(self,name,age): self.name = name self.age = age def myPrint(self): print(self.name,self.age) #创建对象 p1 = Person1("lisi",10) #通过对象.属性 访问属性 print(p1.name,p1.age) #通过 对象.成员函数 调用函数 p1.myPrint() #通过对象直接访问属性,并且给属性赋值 p1.name = "jack" print(p1.name) #2.属性私有化 #写法:在需要被私有化的属性的前面添加__ class Person2(): def __init__(self,name,age): self.name = name self.__age = age #私有化属性 def myPrint(self): #在类的内部可以直接访问私有化属性 print(self.name,self.__age) p2 = Person2("aaa",5) p2.myPrint() p2.name = "abc" #注意1:属性被私有化之后,将不能再直接访问 #print(p2.age) #ttributeError: 'Person2' object has no attribute 'age' #在类的外部,不能通过对象直接访问属性 #print(p2.__age) #AttributeError: 'Person2' object has no attribute '__age' #属性的动态绑定,age和__age其实属于两个不同的变量 p2.age = 100 print(p2.age) #注意2:此处的操作属于属性的动态绑定,和类中的__age不是同一个变量 p2.__age = 200 print(p2.__age) #所以,重新创建一个对象,该对象仍然不能直接访问__age p21 = Person2("",0) #print(p21.__age) #AttributeError: 'Person2' object has no attribute '__age'
3.get函数和set函数
get函数和set函数并不是系统内置的函数,而是自定义的,为了和封装的概念相吻合,命名为getXxx()和setXxx()
get函数:获取值 【p1.name】
set函数:赋值 【p1.name = 值】
说明:
getXxx()和setXxx()中Xxx代表的是被私有化的属性的名称
语法:
get函数:
def getXxx(self):
return 私有化属性
set函数:
def setXxx(self,私有化属性的名称)
私有化属性 = 私有化属性的名称
举例:假设一个类中有一个私有化属性age,self.__age = age
def getAge(self):
return self.__age
def setAge(self,age):
self.__age = age
代码演示:
#3.使用get函数和set函数访问私有化属性 class Person3(): def __init__(self,name,age): self.__name = name self.__age = age #私有化属性 def myPrint(self): #在类的内部可以直接访问私有化属性 print(self.__name,self.__age) #给age添加get函数和set函数 #get函数:获取被私有化的属性的值 #命名方式:getXxx #特点;需要设置返回值,将私有化属性的值返回 def getAge(self): return self.__age #set函数:给私有化属性赋值 #命名方式:setXxx #特点;需要设置参数,参数和被私有化的属性有关 def setAge(self, age): #数据的过滤 if age < 0: age = 0 self.__age = age def getName(self): return self.__name def setName(self,name): self.__name = name p3 = Person3("111",3) p3.myPrint() #111 3 print(p3.getAge()) #3 p3.setAge(10) print(p3.getAge()) p3.setAge(-10) print(p3.getAge()) p3.setName("222") print(p3.getName())
4.@property装饰器
装饰器的作用:可以给函数动态的添加新的功能,对于类的成员函数,装饰器同样起作用
Python的内置装饰器@property的作用:将一个函数转换为属性进行使用【简化get函数和set函数】
使用:@property装饰器的作用相当于get函数,同时,会自动生成一个新的装饰器@属性名.setter,相当于set函数
注意:使用在类的成员函数中,可以简化代码,同时保证对参数的校验
代码演示:
#4.使用@property装饰器 class Person4(): def __init__(self,name,age): self.__name = name self.__age = age #私有化属性 def myPrint(self): #在类的内部可以直接访问私有化属性 print(self.name,self.__age) #注意:函数的命名方式:被私有化的属性的名称,举例:self.__age ---->age #函数的命名并不是固定的,只要是一个合法的标识符即可,但是,一般情况下,使用变量名命名,方便区分 #相当于get函数,设置返回值,将被私有化的属性的值返回 @property def age(self): return self.__age #注意:函数命名方式:和@property作用的函数名保持一致,装饰器的命名方式:@属性名.setter #相当于是set函数,设置参数,给私有化属性进行赋值 @age.setter def age(self,age): if age < 0: age = 0 self.__age = age @property def name(self): return self.__name @name.setter def name(self,name): self.__name = name p4 = Person4("jack",4) #@property本质:将函数在转换为属性使用 #获取值 print(p4.age) #相当于调用了get函数【@property修饰的函数】,将被私有化的属性的值返回 #设置 p4.age = 100 #相当于调用了set函数【@age.setter修饰的函数】,将100作为参数传值 print(p4.age) p4.name = "tom" print(p4.name)
5.属性的不同形式
代码演示:
class Person5(): def __init__(self,name,age): self.name = name self.__age = age #私有化属性 def myPrint(self): print(self.name,self.__age) #1.属性私有化的工作原理 per = Person5("jack",55) #per.__age:Python解释器将__age变成了_Person5__age #可以通过对象._Person5__age去访问,但是不建议使用,不同的解释器可能存在解释的变量不一致的情况 #Python本身没有任何机制阻止你干坏事,一切全凭自觉 print(per._Person5__age) #2. class Person6(): def __init__(self,name,age,height): self._name = name self.__age = age self.__height__ = height p = Person6("tom",10,5.0) #a.在变量的前面添加一个下划线,属于特殊变量,则认为该变量受保护的 #特点:在类的外面也可以直接访问,但是不建议使用 print(p._name) #b.在变量的前后各添加两个下划线,属性特殊变量,一般认为这种变量都是系统的内置变量或者内置函数 # 【__name__、__init__、__del__ 】 #特点:在类的外面也可以直接访问,但是不建议使用 print(p.__height__) """ 【面试题:解释下面不同变量的含义】 xxx:普通变量 _xxx;受保护的变量,自定义变量不建议使用 __xxx:私有变量,在外界不能直接被访问 __xxx__:系统的内置变量,自定义变量不建议使用 """
6.私有函数
类中的成员函数也可以被私有化
写法:在函数名的前面添加两个下划线【函数名就是一个变量名】,此时,该函数被称为私有函数
特点:只能在当前类中被直接调用
代码演示:
class Site(): def __init__(self,name): self.name = name def func(self): print("这是一个普通【公共】函数") #在公共函数中将私有函数调用,d调用格式:self.__私有的函数名称(参数列表) self.__func1() def __func1(self): print("这是一个私有函数") s = Site("千锋") s.func() #s.__func1()
四、继承
1.概念
如果两个或者两个以上的类具有相同的特征【属性】和行为【成员函数】,我们可以抽取一个类出来,在抽取出来的类中声明公共的部分
被抽取出来的类:父类,超类,基类
两个或者两个以上的类:子类,派生类
他们之间的关系:子类 继承自 父类 / 父类 派生出了 子类
作用:简化代码,提高了代码的复用性和可维护性
extends
2.单继承
一个子类只能有一个父类,被称为单继承
语法:
父类:
class 父类类名(object):
类体【公共部分】
子类:
class 子类类名(父类类名):
类体【子类特有的部分】
注意:object是所有类的父类
代码演示:
测试文件
from extends01.person import Person from extends01.student import Student from extends01.worker import Worker #1.创建父类的对象 p = Person("lisi",10) print(p.name,p.age) #print(p.name) p.show() #2.创建子类的对象 #注意:子类可以继承父类中的公共的成员变量和成员函数 w1 = Worker("aaa",1) #w1.age能正常使用:默认调用了父类中的被@property修饰的函数 print(w1.name,w1.age) w1.show() #3.子类除了继承父类中的成员变量和成员的函数之外,还可以有特有的成员变量和成员函数 s = Student("bob",18,"语文") s.show() s.test() #4.子类对象可以访问父类中的公共的成员变量和成员函数,反之,父类对象无法访问子类中特有的成员变量和成员函数 p.test()父类:
#定义父类 #注意;如果没有显式的规定父类,则这个类的父类默认为object class Person(object): #成员变量 def __init__(self,name,age): self.name = name self.__age = age #成员函数 def show(self): print("父类中的show被调用") @property def age(self): return self.__age @age.setter def age(self, age): self.__age = age子类:
from extends01.person import Person #定义子类 class Worker(Person): def __init__(self,name,age): """ self.name = name self.age = age """ #在子类中调用父类中的构造函数,主要是为了将父类中现有的成员变量应用到子类中 #方式一:super(当前类,self).__init__(属性列表) #注意:super:和父类有关【父类的引用】 #super(Worker,self).__init__(name,age) #方式二:父类名.__init__(self,属性列表) #Person.__init__(self,name,age) #方式三:super().__init__(属性列表) super().__init__(name,age) #说明:上述三种写法都可以使用,作用是一样的,目的都是为了调用父类的构造函数 from extends01.person import Person #定义子类 class Student(Person): def __init__(self,name,age,subject): super().__init__(name,age) self.subject = subject def test(self): print("testing")总结:
继承的特点:
a.子类对象可以直接访问父类中未私有化的属性
b.子类对象可以调用父类中为私有化的成员函数
c.父类对象不能访问子类特有的属性和成员函数
继承的优缺点:
优点:
a.可以简化代码,减少冗余
b.提高代码的可维护性
c.提高代码的安全性
d.是多态的前提
缺点:
耦合和内聚被用来描述类与类之间的关系,耦合性越低,内聚性越高,说明代码越好
但是,在继承关系中,耦合性是比较高【如果修改父类,子类也会随着发生改变】
3.多继承
一个子类可以有多个父类
注意:不能为了使用某个类中的某些功能,而刻意去实现继承
代码演示:
#多继承 class Father1(object): def __init__(self,money): self.money = money def play(self): print("play") def func(self): print("func~~~~1111") class Father2(object): def __init__(self, faceValue): self.faceValue = faceValue def eat(self): print("eat") def func(self): print("func~~~~2222") class Child(Father2,Father1): def __init__(self,money,faceValue,hobby): self.hobby = hobby #注意:子类继承多个父类中的成员变量,需要分别调用父类中的构造函数 Father1.__init__(self,money) Father2.__init__(self,faceValue) def show(self): print("show") #创建一个子类的对象 c = Child(100,100,"打麻将") print(c.money,c.faceValue,c.hobby) c.play() c.eat() c.show() c.func() #注意;如果多个父类中存在重名的函数,当子类对象调用的时候,Python在父类列表中从左到右进行搜索, #第一个存在指定函数的父类,则子类对象调用其中的函数