从零开始的python学习(八)P108+P109+P110+P111+P112+P113+P114
本文章记录观看B站python教程学习笔记和实践感悟,视频链接:【花了2万多买的Python教程全套,现在分享给大家,入门到精通(Python全栈开发教程)】 https://www.bilibili.com/video/BV1wD4y1o7AS/?p=6&share_source=copy_web&vd_source=404581381724503685cb98601d6706fb
上节课学习本章总结和章节选择题,实战一:计算列表元素的最大值,实战二:提取字符串中所有的数字,实战三:字符串中字母大小写转换,实战四:实现操作符in的判断功能,本节课学习两大编程思想-面向过程和面向对象,自定义类和创建自定义类的对象,类的组成,使用类模板创建N多个对象,动态绑定属性和方法,Python中的权限控制,属性的设置。
本章开始学习面向对象程序设计。下面是本章脉络:
注意。以上两种编程思想与语言没有关系,下面的语言举例只是代表语言之一。下面是两种思想的异同点:
一、两大编程思想-面向过程和面向对象
简单来说,类是一群具体事物的概括,对象就是这个类的具体。
例如
a=10
b=9.8
s='hello'
print(type(a)) #返回<class 'int'>
print(type(b)) #返回<class 'float'>
print(type(s)) #返回<class 'str'>
二、自定义类和创建自定义类的对象
使用类创建对象的语法结构是如下,并且首字母必须大写,并且后面那个小括号可以省略不写:
从图中可以看到,类相当于造汽车的图纸,也就是说类的抽象的一个模板,如果想落实这个图纸变成实实在在的,必须创建对象才能使用。右边就是设计出图纸以后,需要“对象名=类型()”这样创建一个实在的汽车。
#创建类 class 类型():
#编写一个Person
class Person():pass
#编写一个Cat类
class Cat():pass
#编写一个Dog类
class Dog: #这里小括号省略不写pass#编写一个Student类
class Student: #这里小括号省略不写pass#创建类的对象 对象=类名()
#创建一个Person类型的对象
per=Person() #per就是Person类型的对象
c=Cat() #c就是Cat类型的对象
d=Dog() #d就是Dog类型的对象
stu=Student() #stu就是Student类型的对象
print(type(per))
print(type(c))
print(type(d))
print(type(stu))
运行结果如下:
<class '__main__.Person'>
<class '__main__.Cat'>
<class '__main__.Dog'>
<class '__main__.Student'>进程已结束,退出代码为 0
三、类的组成
上一个环节我是只简单的创建了一个类,并没有设计这个类的内容。实际上类的组成有如下:
class Student:# 类属性:定义在类中,方法外的变量school = '北京XXX教育'#初始化方法def __init__(self,xm,age): #xm,age是方法的参数,是局部变量。也就是说xm和age的作用域是整个__init__方法。#下面进行赋值属性,其中等式的左边为实例属性self.name = xm #等式左边为实例属性,xm为局部变量,将局部变量的xm赋值给实例属性self.nameself.age = age #实例的名称和局部变量的名称可以相同#定义在类中的函数,称之为方法,自带一个参数selfdef show(self):print(f'我叫: {self.name},今年:{self.age}岁了')#静态方法@staticmethoddef sm():#print(self.name) #这个报错,说明不可以直接调用实例属性#self.show() #这个也报错,说明了不可以直接调用实例方法print('这是一个静态方法,不能调用实例属性,也不能调用实例方法')@classmethoddef cm(cls):#cls是class的简称#print(self.name)#self.show()print('这是一个类方法,不能调用实例属性,也不能调用实例方法')#截止,“图纸”就画好了,如果想要实现它就必须定义具体的对象
stu=Student('ysj',18) #为什么传了两个参数?因为__init__方法中有两个形参。self是自带的参数,无需手动输入(我们不用管)
#实例属性:使用对象名进行打点调用
print(stu.name,stu.age) #可以看出上面的self实际上就是占用了真正对象名的位置,也是就self相当于一个形参
#类属性:直接使用类名,打点调用
print(Student.school)
#实例方法:使用对象名进行打点调用
stu.show()
#类方法:@classmethod进行修饰的方法是直接使用类名打点调用
Student.cm()
#静态方法:@staticmethod进行修饰的方法是直接使用类名打点调用
Student.sm()
结果:
四、使用类模板创建N多个对象
一个类相当于一个汽车图纸,根据这图纸可以创建出多个汽车实体。
#编写学生类
#直接将上一节的学生类复制过来
class Student:# 类属性:定义在类中,方法外的变量school = '北京XXX教育'#初始化方法def __init__(self,xm,age): #xm,age是方法的参数,是局部变量。也就是说xm和age的作用域是整个__init__方法。#下面进行赋值属性,其中等式的左边为实例属性self.name = xm #等式左边为实例属性,xm为局部变量,将局部变量的xm赋值给实例属性self.nameself.age = age #实例的名称和局部变量的名称可以相同#定义在类中的函数,称之为方法,自带一个参数selfdef show(self):print(f'我叫: {self.name},今年:{self.age}岁了')#根据图纸可以创建N多个对象
stu=Student('ysj',18)
stu2=Student('利威尔',30)
stu3=Student('那维莱特',500)
stu4=Student('夜斗',450) #等号的右侧都是Studentprint(type(stu)) #<class '__main__.Student'>
print(type(stu2)) #<class '__main__.Student'>
print(type(stu3)) #<class '__main__.Student'>
print(type(stu4)) #<class '__main__.Student'>#对于类属性我们可以直接打点去调用它
Student.school='须弥教令院' #给类的类属性赋值,显然这里跟之前那个不一样了,我们重新赋了一个值#将学生对象存储到列表中
lst=[stu,stu2,stu3,stu4] #列表中的元素是Student类型的对象
for item in lst: #item是列表中的元素,是Student类型的对象item.show() #对象名打点调用实例方法
返回结果:
<class '__main__.Student'>
<class '__main__.Student'>
<class '__main__.Student'>
<class '__main__.Student'>
我叫: ysj,今年:18岁了
我叫: 利威尔,今年:30岁了
我叫: 那维莱特,今年:500岁了
我叫: 夜斗,今年:450岁了进程已结束,退出代码为 0
五、动态绑定属性和方法
对于上面的同一个汽车图纸,我们发现共有的对象虽然属性是一样的,但是属性值是不一样的。右边的两个图是stu和stu2的分别的实例属性,比如stu2中有一个genter也就是性别,也是就是说我们设定的类里面有两个实例属性,name和age,但时候在创建对象之后,我们可以动态去绑定属性。
#动态绑定属性和方法
#直接将上一节的学生类复制过来
class Student:# 类属性:定义在类中,方法外的变量school = '北京XXX教育'#初始化方法def __init__(self,xm,age): #xm,age是方法的参数,是局部变量。也就是说xm和age的作用域是整个__init__方法。#下面进行赋值属性,其中等式的左边为实例属性self.name = xm #等式左边为实例属性,xm为局部变量,将局部变量的xm赋值给实例属性self.nameself.age = age #实例的名称和局部变量的名称可以相同#定义在类中的函数,称之为方法,自带一个参数selfdef show(self):print(f'我叫: {self.name},今年:{self.age}岁了')
#创建两个Student类型对象
stu=Student('ysj',18)
stu2=Student('利威尔',30)
print(stu.name,stu.age)
print(stu2.name,stu2.age)
#为stu动态规定一个实例属性
stu2.gender='男'
print(stu2.name,stu2.age,stu2.gender)
#注意,在这我们是只给stu2设置了genter这样的属性,并没有给stu设置属性
#print(stu.genter) #报错:AttributeError: 'Student' object has no attribute 'genter'
#动态绑定方法
def introduce():print('我是一个普通的函数,我被动态绑定成了stu2对象的方法')#定义好方法以后将其绑定给stu2
stu2.fun=introduce #函数的一个赋值(绑定),不能加小括号,加小括号就成调用了
#fun就是stu2的方法
#调用
stu2.fun()
结果如下:
ysj 18
利威尔 30
利威尔 30 男
我是一个普通的函数,我被动态绑定成了stu2对象的方法进程已结束,退出代码为 0
六、Python中的权限控制
面向对象的三大特征:
封装,继承和多态。封装就是将对象变成一个“黑箱”,我们只管去调用它而不需要探求内部是如何实现的。继承就是根据图纸制造汽车的时候,需要使用类中规定好的属性,然后赋予具体的值。多态就是定义不同属性的时候其实是各不相同的。
1.封装
举例:
#权限控制
class Student:#首尾双下划线:表示特殊的方法def __init__(self, name, age,gender): #name, age,gender是方法的形参,同时也是局部变量self._name = name #单下划线:说明self._name是受保护的,只能本类和子类访问self.__age = age #双下划线:说明self.__age是私有的,只能类本身去访问self.__gender = gender #啥也没有,就是普通的实例属性,类的内部、外部、以及其子类都可以访问def _fun1(self): #受保护的print('子类以及本身可以访问')def __fun2(self): #私有的的print('只有定义的类可以访问')def show(self): #普通的实例方法self._fun1() #类本身访问受保护的方法self.__fun2() #类本身访问私有方法print(self._name) #受保护的实例属性print(self.__age) #私有的实例属性#创建一个学生类的对象
stu=Student('利威尔',30,'男')#如果在类的外部调用
print(stu._name)
#print(stu.__age) #AttributeError: 'Student' object has no attribute '__age',因为出了类的定义范围age就不能用了,因为只有定义的类可以访问#调用受保护的实例方法
stu._fun1() #子类以及本身可以访问
#stu.__fun2() #AttributeError: 'Student' object has no attribute '__fun2',因为私有的函数不能在实例外面访问#私有的实例属性和方法真的不能访问吗?答是有条件的
print(stu._Student__age)
stu._Student__fun2()
print(dir(stu))
运行结果:
利威尔
子类以及本身可以访问
30
只有定义的类可以访问
['_Student__age', '_Student__fun2', '_Student__gender', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_fun1', '_name', 'show']进程已结束,退出代码为 0
也就是只有按照print(dir(stu))运行结果里面的名字调用才能正常调用,访问私有属性也就是:
对象名._类名__属性名
七、属性的设置
首先上面这种调用方式(对象名._类名__属性名)是不推荐的,我们更推荐使用装饰器去调用。装饰器是使用@符号来开头的
class Student:def __init__(self,name,gender):self.name=nameself.__gender = gender #self.__gender是私有的实例属性#使用property修改方法,将方法转成属性使用@propertydef gender(self):return self.__gender#将我们的gender这个属性设置为可写属性@gender.setterdef gender(self,value):if value!='男' and value!='女':print('性别有误,已将性别默认设置为男')self.__gender = '男'else:self.__gender = valuestu=Student('利威尔','女')
print(stu.name,'的性别是',stu.gender) #stu.gender就会去执行stu.gender()
#如果尝试修改属性
stu.gender='其他' #注意必须要设定setter,否则改变属性会报错
print(stu.name,'的性别是',stu.gender)
运行结果:
利威尔 的性别是 女
性别有误,已将性别默认设置为男
利威尔 的性别是 男进程已结束,退出代码为 0
本节完