Python 基础入门学习

五.面向对象

  1. 是对一系列具有相同特征和行为的事物的统称,是一个抽象的概念,不是真实存在的事物。对象是由类创建出来的真实存在的事物。
#创建类
class 类名():  #类名要满足标识符命名规则,同时遵循大驼峰命名习惯
    代码
    ......
	def 函数名(self):  #self指调用该函数的对象
        代码

#创建对象
对象名 = 类名()
  1. 类外面添加对象属性
对象名.属性名 = 值

类外面获取对象属性

对象名.属性名

类里面获取对象属性

self.属性名

综合实例

class Washer():
    def wash(self):
        print('wash the clothes!')
    def get_size(self):
        print(f'此洗衣机的尺寸是{self.width} X {self.height}')

haier1 = Washer()
haier1.width = 500
haier1.height = 300

haier2 = Washer()
haier2.width = 600
haier2.height = 400

print(haier1.width)
haier1.get_size()
haier2.get_size()
  1. 魔法方法: __init__() 、 __str__()、__del__()。
#1. __init__() 初始化对象。
#创建对象时默认被调用;不需开发者传递self参数,python解释器会自动把当前对象引用传递过去。

class washer():
    def __init__(self,width,height):
        self.width = width
        self.height = height

    def print_info(self):
        print(f'{self.width} X {self.height}')

h = washer(500,800)
h.print_info()
#输出结果 500 X 800

#2. __str__() 使得用print输出对象时,输出该方法中return的数据,而不再输出对象的内存地址。

    def __str__(self):
        return "这是洗衣机对象!"
    
print(h)
#输出结果 这是洗衣机对象!

#3. __del__() 当删除对象时,python解释器会默认调用__del__()方法

    def __del__(self):
        print(f'{self}对象已经被删除!')
     
del h
#输出结果 <__main__.washer object at 0x000002531DF744F0>对象已经被删除!
  1. 两个案例
    烤地瓜
#需求:1.被烤时间和地瓜状态相对应  2.用户可按意愿添加调料

class SweetPotato():

    def __init__(self):
        self.cook_time=0
        self.cook_state='生的'
        self.condiments=[]

    def cook(self, time):
        if time >=0:
            self.cook_time += time
            if 0<= self.cook_time < 3:
                self.cook_state = '生的'
            elif 3 <= self.cook_time < 5:
                self.cook_state = '半生不熟'
            elif 5 <= self.cook_time < 8:
                self.cook_state = '熟了'
            elif self.cook_time >= 8:
                self.cook_state = '糊了!'
        else:
            print('时间刺客?!')

    def add_condiment(self, con):
        self.condiments.append(con)

    def __str__(self):
        return f'这个地瓜烤了{self.cook_time}分钟,状态是{self.cook_state},添加的调料有{self.condiments}'

p = SweetPotato()
p.add_condiment('番茄酱')
print(p)
p.cook(8)
p.add_condiment('芥末')
print(p)

# 这个地瓜烤了0分钟,状态是生的,添加的调料有['番茄酱']
# 这个地瓜烤了8分钟,状态是糊了!,添加的调料有['番茄酱', '芥末']

搬家具

#需求 将小于房子剩余面积的家具摆放到房子中

class Furniture():
    def __init__(self,name,area):
        self.name = name
        self.area = area

class House():
    def __init__(self,adress,area):
        self.adress = adress
        self.area = area
        self.free_area = area
        self.furniture = []

    def add_furniture(self,item):
        if self.free_area >= item.area:
            self.furniture.append(item.name)
            self.free_area -= item.area
        else:
            print('家具太大,剩余面积不足,无法容纳')

    def __str__(self):
        return f'这个房子的地址是{self.adress},总面积是{self.area},当前剩余面积是{self.free_area},家具有{self.furniture}'

bed = Furniture('双人床',6)
sofa = Furniture('沙发',10)
court = Furniture('高尔夫球场',1000)
house = House('陆家嘴',200)
print(house)
house.add_furniture(bed)
house.add_furniture(sofa)
house.add_furniture(court)
print(house)

#这个房子的地址是陆家嘴,总面积是200,当前剩余面积是200,家具有[]
#家具太大,剩余面积不足,无法容纳
#这个房子的地址是陆家嘴,总面积是200,当前剩余面积是184,家具有['双人床', '沙发']
  1. 继承: Python面向对象的继承指的是多个类之间的所属关系,即子类默认继承父类的所有属性和方法,具体如下:
#定义父类A
class A(object):
    def __init__(self):
        self.num = 1
        
    def infor_print(self):
        print(self.num)
        
#定义子类B,继承父类A
class B(A):
    pass

#创建对象,验证对象继承
result = B()
result.info_print()

在python中,所有类默认继承object类,object类是顶级类或基类;其他子类叫派生类

拓展:python2中的经典类 和 python3中的新式类

#经典类(不由任意内置类型派生出的类)
class 类名:
    代码
    ......
    
#新式类
class 类名(object):
    代码
    ......
    
#在今后的学习和运用中,统一使用新式类

单继承:一个子类继承一个父类,这种单一的继承关系称为单继承。

多继承:一个子类同时继承多个父类。

class 子类(父类A,父类B,父类C)
#当两个父类中的属性和方法有同名时,优先继承第一个父类中的同名属性和方法,即继承A类。

子类重写父类同名属性与方法:在子类中可以重写与父类中同名的属性和方法。子类创建的对象调用属性和方法时,会调用子类中重写的属性和方法。

拓展: **__mro__**顺序 方法查看类的继承层级顺序。

print(类名.__mro__)

子类调用父类同名属性和方法:在子类中重写了父类中同名属性与方法的情况下,调用父类中的同名属性和方法。

class 子类B(父类A):
    def 同名方法(self):
        #如果之前调用了父类的属性和方法,则父类属性会覆盖子类属性,故在调用子类属性前,先调用子类自己的初始化
        self.__init__(self)
        代码
        
    def 调用父类方法(self):
        #调用父类方法,为保证调用到的属性也是父类的属性,必须在调用方法前调用父类的初始化
        父类A.__init__(self)
		父类A.同名方法(self)

多层继承:一般指大于两层的继承关系。

class A(object):
	...
    
class B(A):
    ...
    
class C(B):  #多层继承
    ...

super()调用父类方法:自动查找父类,直接调用父类的属性方法,调用顺序遵循__mro__类属性的顺序。

class A(object)
class B(A)

class C(B):
    #方法一:原始方法
    def useAB(self):
        A.__init__(self)
        A.同名方法(self)
        B.__init__(self)
        b.同名方法(self)
        
    #方法二:super()方法
    #方法2.1 super(当前类名,self).函数()
    def useAB(self):
        super(C,self).__init__()
        super(C,self).同名方法() 
        #此时会调用父类B的方法;若想调用A类的方法,需要在B类的同名方法中添加同样的super方法代码来调用A类
        
    #方法2.2 super().函数()
    def useAB(self):
        super().__init__(self)
        super().同名方法()
        #同样调用父类B的方法;无法直接调用父类的父类A的属性和方法
  1. 私有权限
    设置私有属性和方法:在属性名和方法名前面加上两个下划线。
    私有属性和私有方法只能在类内访问和修改,即子类无法继承或直接访问父类的私有属性和方法。
class A(object):
    def __init__(self):
        self.name = 'A'
        self.__money = 99999  #私有属性
    
    def __CostMoney(self,money):  #私有方法
        self.__money -= money

获取和修改私有属性值:可在类内定义公有函数来获取和修改 私有属性值,在类外调用该函数来实现获取和修改私有属性功能。

#一般在类内用函数名get_xx来获取私有属性,用set_xx来修改私有属性
class A(object):
    def __init__(self):
        self.__money = 99999
        
    def get_money(self):
        return self.__money
    
    def set_money(self,new_money):
        self.__money = new_money
        
class B(A):
    pass

b = B()

b.get_money()  #成功获取父类中的私有属性
b.set_money(0)  #成功修改父类中的私有属性
  1. 多态:一种使用对象的方式,子类重写父类方法,调用不同子类对象的相同父类方法,可以产生不同的执行结果。即传入不同的对象,产生不同的结果。
  2. 类属性和实例属性:类属性即类所拥有的属性,它为该类所有对象共有。类属性可以用 类对象实例对象 访问。
    类属性只能通过类对象修改
#修改类属性
类名.属性 = 值
  1. 类方法:需要用装饰器 @classmethod 来标识其为类方法,类方法第一个参数必须是类对象,一般以 cls 作为第一个参数。
class A(object):
    __num = 777
    
    @classmethod
    def get_num(cls):
        return cls.__num
    
obj = A()
print(obj.get_num())
  1. 静态方法:通过装饰器 @staticmethod 进行修饰,静态方法即不需要传递类和对象的方法,有利于减少不必要的内存占用和性能消耗。
class A(object):
    @staticmethod
    def info_print():
        print('这是A类')

六.异常

  1. 异常的定义:解释器检测到错误时无法继续执行,并出现一些错误的提示,这就是所谓的异常
    异常的作用:使得解释器检测到错误时,转而执行另一句没错误的语句,使得程序不因一个错误而停止下来。
  2. 基本写法
try:
    可能发生错误的代码
except:
    出现异常时执行的代码
else:
    没有异常时执行的代码
finally:
	无论是否异常都要执行的代码

体验案例:

#需求:尝试以r模式打开文件,若文件不存在(发生错误),则以w方式打开
try:
    f = open('test.txt','r')
except:
    f = open('test.txt','w')
  1. 捕获指定异常
try:
    print(num)
except (NameError, ZeroDivisionError) as result:
    print(result)  #捕获的异常描述信息
    num = 777
    print(num)
   
#若尝试执行代码的异常类型和要捕获的异常类型不一致,则无法捕获异常
#一般try下方只放一行尝试执行的代码
  1. 捕获所有异常:利用 Exception 类
#Exception是所有程序异常类的父类
try:
    可能错误的代码
except Exception as result:
    print(result)
  1. 异常中的 else 和 finally:
try:
    f = open('test.txt','r')
except Exception as result:
    f = open('test.txt','w')
    print(result)
else:  # try 下方的代码无异常时执行的代码
    print('代码没有异常和错误')
finally:  #无论有无异常都要执行的代码,如关闭文件
    f.close()
  1. 异常的传递
import time
try:
    f = open('test.txt') #默认打开模式为只读
    #尝试循环读取内容
    try:
        while True:
            con = f.readline()
            #无内容时退出循环
            if len(con) == 0:
                break
            time.sleep(2)
            print(con)
    except:
        #在命令提示符中按下 Ctrl+C 终止程序
        print('程序被意外终止')
except:
    print('文件不存在')
  1. 自定义异常: 抛出自定义异常的语法为raise 异常类对象
#自定义异常类,继承Exception
class ShortInputError(Exception):
    def __init__(self,length,min_length):
        self.length=length
        self.min_length=min_length

    #设置抛出异常的描述信息
    def __str__(self):
        return f'输入长度为{self.length},不能少于{self.min_length}个字符'

def main():  #封装代码
    try:
        con = input('请输入密码: ')
        if len(con) < 6:
            raise ShortInputError(len(con),6)
    except Exception as result:
        print(result)
    else:
        print('密码输入完成')
        
main()

七.模块

  1. 了解模块:Python模块(Module),是一个Python文件,包含了Python对象定义和语句。
  2. 导入和调用模块
#导入及调用模块

#写法一
import 模块名  #导入模块中的所有代码
模块名.功能名()

#写法二
from 模块名 import 功能1,功能2...  #单个调用某功能
功能名()   #即不需要在功能前写 "模块名."

#写法三
from 模块名 import *
功能名()  

#一般用第一种写法

利用as定义别名:定义别名后,使用时要用定义的别名

#模块定义别名
import 模块名 as 别名

#功能定义别名
from 模块名 import 功能 as 别名
  1. 制作模块:模块名字就是py文件的名字。自定义模块名必须要符合标识符命名规则
#只会在当前文件中调用下列测试代码,其他导入的文件内不符合该条件,也就不会执行测试代码
# __name__ 是系统变量,是模块的标识符。如果在自身模块里,则其值为 '__main__';否则是所在模块的名字
if __name__ == '__main__':
    测试模块功能代码
  1. 模块定位顺序:当导入一个模块,Python解释器对模块位置的搜索顺序是:
    当前目录 > 搜索在shell变量PYTHONPATH下的每个目录 > 操作系统的默认python路径
    注意
    自己的文件名不要和已有模块名重复,否则模块功能无法使用。
    使用from 模块名 import 功能时,若功能名字重复,则调用最后定义的或最后导入的功能。
    当使用 import 模块名 的写法调用模块时,不需要担心功能名重复。
  2. __all__列表:如果一个模块文件中有__all__ 变量列表,当使用from 模块名 import *导入该模块时,则只能导入__all__列表中的元素。
  3. :包将有联系的模块组织在一起,放到同一个文件夹下,并且在这个文件夹内自动生成一个名字为__init__.py的文件,这个文件控制着包的导入行为。
    创建包:在Pycharm中 New -> Python Package -> 输入包名 - > [OK] 即可新建一个包。
    导入包
#方法一
import 包名.模块名
包名.模块名.功能

#方法二
#注意,必须在 __init__.py 文件中添加 __all__ = [] 来控制允许导入的模块列表
from 包名 import *
模块名.功能

面向对象综合实例

#使用面向对象编程思想完成学员管理系统的开发

#为了方便维护代码,一般一个角色一个程序文件
#项目要有主程序入口,习惯为main.py

#系统要求:学员数据存储在文件中
#系统功能:添加学员、删除学员、修改学员信息、查询学员信息、显示所有学员信息、保存学员信息、退出系统等功能


#student.py
#学员类
class Student(object):
    def __init__(self,name,gender,tel):
        #姓名、性别、手机号
        self.name = name
        self.gender = gender
        self.tel = tel

    def __str__(self):
        return f'{self.name},{self.gender},{self.tel}'


#mangerSystem.py
#存储数据的: student.data
#存储数据的形式: 列表存储学员对象
#系统功能: 添加、删除、修改、查询、显示、保存学员信息

#管理系统类
class StudentManager(object):
    def __init__(self):
        #存储数据所用列表
        self.student_list = []

    #一. 程序入口函数,启动程序后执行的函数
    def run(self):
        #1. 加载学员信息
        self.load_student()

        while True:
            #2. 显示功能菜单
            self.show_menu()
            #3. 用户输入目标功能序号
            menu_num = int(input('请输入您需要的功能序号: '))

            #4. 根据用户输入的序号执行相应功能
            if menu_num == 1:
                # 添加学员
                self.add_student()

            elif menu_num == 2:
                # 删除学员
                self.del_student()

            elif menu_num == 3:
                # 修改学员信息
                self.modify_student()

            elif menu_num == 4:
                # 查询学员信息
                self.search_student()

            elif menu_num == 5:
                # 显示所有学员信息
                self.show_menu()

            elif menu_num == 6:
                # 保存学员信息
                self.save_student()

            elif menu_num == 7:
                # 退出系统 - 退出循环
                break

    #二. 系统功能函数
    #2.1 显示功能菜单 -- 静态方法
    @staticmethod
    def show_menu():
        print('请选择如下功能: ')
        print('1.添加学员')
        print('2.删除学员')
        print('3.修改学员信息')
        print('4.查询学员信息')
        print('5.显示所有学员信息')
        print('6.保存学员信息')
        print('7.退出系统')

    #2.2 添加学员
    def add_student(self):
        #1. 用户输入
        name = input('请输入姓名: ')
        gender = input('请输入性别: ')
        tel = input('请输入手机号: ')

        #2. 创建学员对象 -- 先导入student.py模块
        student = Student(name,gender,tel)

        #3. 将对象添加到学员列表
        self.student_list.append(student)

    #2.3 删除学员
    def del_student(self):
        #1. 用户输入目标学员姓名
        del_name = input('请输入要删除的学员姓名:')

        #2. 如果用户输入的目标学员存在则删除,否则提示不存在
        for i in self.student_list:
            if i.name == del_name:
                self.student_list.remove(i)
                break
        else:
            print('查无此人!')

    #2.4 修改学员信息
    def modify_student(self):
        #1. 用户输入目标学员姓名
        modify_name = input('请输入要修改的学员姓名: ')

        #2. 如果用户输入的目标学员存在,则修改信息,否则提示不存在
        for i in self.student_list:
            if i.name == modify_name:
                i.name = input('请输入学员姓名: ')
                i.gender = input('请输入学员性别: ')
                i.tel = input('请输入学员手机号: ')
                print('修改成功!')
                break
        else:
            print('查无此人!')

    #2.5 查询学员信息
    def search_student(self):
        #1. 用户输入目标学员姓名
        search_name = input('请输入要查询的学员姓名: ')

        #2. 若存在,打印学员信息,否则提示不存在
        for i in self.student_list:
            if i.name == search_name:
                print(f'姓名{i.name},性别{i.gender},手机号{i.tel}')
                break
        else:
            print('查无此人!')

    #2.6 显示所有学员信息
    def show_student(self):
        print('姓名\t性别\t手机号')
        for i in self.student_list:
            print(f'{i.name}\t{i.gender}\t{i.tel}')

    #2.7 保存学员信息
    def save_student(self):
        # 拓展 __dict__方法,以字典方式返回类和对象内的属性
        #1. 打开文件
        f = open('student.data','w')

        #2. 文件写入学员数据 - 先将学员对象数据转换成列表字典数据再做存储
        new_list = [i.__dict__ for i in self.student_list]
        # 文件内数据要求为字符串类型,故要先转换数据类型为字符串才能写入文件
        f.write(str(new_list))

        #3. 关闭文件
        f.close()

    #2.8 加载学员信息
    def load_student(self):
        #尝试以"r"模式打开数据文件,有异常则用"w"模式打开;存在则读取数据
        try:
            f = open('student.data','r')
        except:
            f = open('student.data','w')
        else:
            #1. 读取数据
            data = f.read()

            #2. 先将文件中的 字符串型字典数据 转换为 对象数据 后再存储到学员列表
            new_list = eval(data)
            self.student_list = [Student(i['name'],i['gender'],i['tel']) for i in new_list]

        finally:
            #3. 关闭文件
            f.close()

#main.py

#导入模块
#from managerSystem import *

#启动管理系统
#if __name__ == '__main__':
student_manager = StudentManager()
student_manager.run()