一、面向对象

面向对象就是将编程当成是一个事物,对外界来说,事物是直接使用的,不用去管他内部的情况。而编程就是设置事物能够做什么事

1、类和对象

类和对象的关系:用类去创建一个对象,先有类再有对象,一个类可以创建多个对象,不同对象的self地址不相同

1.1、定义类

创建对象:对象名 = 类名

对象方法/实例方法:对象名.wash( )

class Machine():
    def wash(self):
        print('洗衣服')
Haier = Machine()
print(Haier)
Haier.wash()

类里面的self:注意到我们创建类的时候,函数参数会自动填充self,由于打印对象和打印self得到的内存地址相同,所以self指的是调用该函数的对象,在上面的代码案例中,self就指的是Haier

1.2、对象属性操作

以下三个步骤,是要先添加对象属性,然后分类外类里,来获取对象属性

1.2.1、类外添加对象属性

语法:对象名.属性名 = 值

class machine():
    def wash(self):
        print('洗')
Haier = machine()
Haier.wash()
Haier.width = 400
Haier.height = 300
1.2.2、类外面获取对象属性

语法:对象名.属性名

class machine():
    def wash(self):
        print('洗')
Haier = machine()
Haier.width = 400
print(f'Haier的宽度是{Haier.width}')
1.2.3、类里面获取对象属性

语法:self.属性名

class machine():
    def print_info(self):
        print(f'洗衣机的宽度是{self.width}')
Haier = machine()
Haier.width = 400
Haier.print_info()
1.3、魔法方法

在Python中,__xx__( )的函数叫做魔法方法,指的是具有特殊功能的函数

1.3.1、__init__( )

__init__( )魔法方法,用于初始化对象,在创建一个对象时默认被调用,不需要手动调用

class Machine():
    def __init__(self):
        self.width = 400
        self.height = 300
    def print_info(self):
        print(f'洗衣机的宽是{self.width},高是{self.height}')

Haier = Machine()
Haier.print_info()

带参数的__init__( ),在括号里,self是默认的自带的,代表对象本身,我们如果想要输出显示洗衣机的名字,不能直接在print_info里输入{self},最好的方法是把name也当作参数一起传入init,带参数的__init__( )方便一个类创建多个对象

class Machine():
    def __init__(self,name,width,height):
        self.width = width
        self.height = height
        self.name = name
    def print_info(self):
        print(f'洗衣机{self.name}的宽度是{self.width}')
Haier = Machine('Haier',10,20)
Haier.print_info()

# result:洗衣机Haier的宽度是10
1.3.2、__str__( )

当我们print对象名的时候,输出的默认是对象的内存地址,如果定义了__str__方法,那么就会打印从这个方法中return的数据

class Machine():
    def __str__(self):
        return '这是一个洗衣机'
Haier = Machine()
print(Haier)
1.3.3、__del__( )

当删除对象时,python解释器会默认调用__del__( )方法,其实即使不使用del删除对象,我们等程序运行结束时,系统会释放内存,这个时候也会自动调用__del__( )

class Machine():
    def __str__(self):
        return '这是一个洗衣机'
    def __del__(self):
        print(f'已经删除')
Haier = Machine()
print(Haier)
# result:
# 这是一个洗衣机
# 已经删除

2、案例

2.1、烤地瓜
# 定义地瓜类:初始化属性,被烤和添加调料的方法,显示对象信息的str
class SweetPotato():
    def __init__(self):
        self.cook_time = 0 # 烤的时间
        self.condition = '生的' # 烤的状态
        self.condiments = [] # 调料列表
    def cook(self,time): # 烤的方法
        self.cook_time += time
        if 0 <= self.cook_time < 3:
            self.condition = '生的'
        elif 3 <= self.cook_time < 5:
            self.condition = '半生'
        elif 5 <= self.cook_time < 8:
            self.condition = '熟了'
        elif self.cook_time >= 8:
            self.condition = '糊了'
    def add_condiments(self,condiment): # 添加调料方法
        self.condiments.append(condiment)
    def __str__(self): # 输出对象状态
        return f'这个地瓜烤了{self.cook_time}分钟,状态是{self.condition},添加的调料有{self.condiments}'
# 创建对象并调用对应的实例方法
digua1 = SweetPotato()
print(digua1)
digua1.cook(2)
digua1.add_condiments('pepper')
print(digua1)
digua1.cook(4)
digua1.add_condiments('sausage')
print(digua1)
2.2、搬家具

这里我来解释一下,为什么在add_furniture那边可以这么自然的用item.name这种语句呢,是因为我在下面已经先创建了家具类的对象bed,我已经确定了bed是一个家具类,所以我可以使用家具类里的参数

class Furniture(): # 家具类
    def __init__(self,name,area):
        self.name = name
        self.area = area

class House(): # 房屋类
    def __init__(self,address,area):
        self.address = address
        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.address},占地面积是{self.area},剩余面积{self.free_area},里面有家具{self.furniture}'

bed = Furniture('双人床',30)
sofa = Furniture('沙发',80)
home1 = House('上海',100)
print(home1)
home1.add_furniture(sofa)
print(home1)
home1.add_furniture(bed)
print(home1)
房子地址是上海,占地面积是100,剩余面积100,里面有家具[]
房子地址是上海,占地面积是100,剩余面积20,里面有家具['沙发']
放不下了
房子地址是上海,占地面积是100,剩余面积20,里面有家具['沙发']

3、继承

Python面向对象的继承指的是多个类之间的所属关系,即子类默认继承父类的所有属性和方法

语法class B(父类),在Python中,所有类默认继承object类,object类是顶级类或基类,其他子类叫做派生类

class A(): # 父类
    def __init__(self):
        self.a = 1
    def info_print(self):
        print(self.a)
class B(A): # 子类
    pass
test = B()
test.info_print()
3.1、单继承

子类只继承一个父类,上面这个继承的例子就是单继承

3.2、多继承

子类继承多个父类,一个类有多个父类的时候,如果属性和方法同名,默认使用第一个父类的同名属性和方法,不同名则都继承到了

class A():
    def __init__(self):
        self.a = 2
    def info_print(self):
        print(self.a)
class B():
    def __init__(self):
        self.a = 1
    def info_print(self):
        print(self.a)
class C(A,B):
    pass
ivy = C()
ivy.info_print()

# result:2

4、子类重写父类属性和方法

如果子类和父类拥有同名属性和方法,优先调用的是子类的

class Master():
    def __init__(self):
        self.kongfu = '师傅'
    def make(self):
        print(f'这是{self.kongfu}方法')

class School():
    def __init__(self):
        self.kongfu = '学院'
    def make(self):
        print(f'这是{self.kongfu}方法')

class prentice(Master, School):
    def __init__(self):
        self.kongfu = '独创'
    def make(self):
        print(f'这是{self.kongfu}方法')

ivy = prentice()
ivy.make()

4.1、拓展:mro顺序

子类.__mro__        快速查看子类继承的父类和父类之间的层级关系

按照上面的例子,我们可以得出结果如下

print(prentice.__mro__)
# result:
(<class '__main__.prentice'>, <class '__main__.Master'>, <class '__main__.School'>, <class 'object'>)
4.2、子类调用父类的同名方法和属性

在同名的情况下,注意了,我们在写子类的时候,如果在子类里写了自己的属性和方法,然后我们创建了一个子类对象之后,优先调用的就是子类方法,但是为了不丧失父类方法的这个选择,我们可以多def几个有关父类的方法,并在方法中初始化父类属性,像这样

def master_make(self):
    Master.__init__(self)
    Master.make(self)
def school_make(self):
    School.__init__(self)
    School.make(self)
4.3 super( )调用父类方法

super就是一根链条

class A: ...                class A: ... 
class B(A): ...           class B( ): ...
class C(B): ...           class C(A, B): ...

这两种情况,第一个是单继承,单链,C-B-A,第二个是多继承,顺序是C-A-B(优先第一个父类),super就相当于两节火车之间的链条,如果每一个类之间都有super,那一定可以串联起来,如果不想串联这么多,那一定要按照mro顺序来写super,在第一种情况,我们在C下面写super就是找到B,第二种情况我们在C下面写super就是找到A

方法一:super(当前类名,self).函数( )

方法二:super( ).函数( )

5、私有属性和方法

设置私有属性和方法:在属性名和方法名前面加上两个下划线__

在这里会报错,无法继承给B

class A():
    def __init__(self):
        self.__money = 100
class B(A):
    pass
ivy = B()
print(ivy.__money)

在Python中,一般定义函数名get_xx用来获取私有属性,定义set_xx用来修改私有属性,注意!!这个是工作习惯,函数名可以改变,但是一般就是用这两个

!!注意,比如我们的私有属性在A里面,我们就在A里面def获取和set函数

class A():
    def __init__(self):
        self.__money = 100
    def get_money(self):
        return self.__money
    def set_money(self,money):
        self.__money = money
class B(A):
    pass
ivy = B()
print(ivy.get_money())
ivy.set_money(200)
print(ivy.get_money())

6、多态

多态指的是一类事物有多种形态

多态是一种调用对象的方式,子类重写父类方法,调用不同子类对象的相同父类方法,可以产生不同的执行结果

步骤:定义父类,并提供公共方法;定义子类并重写父类方法;传递子类对象给调用者,可以看到不同子类执行效果不同

class Dog():
    pass
class ArmyDog(Dog):
    def work(self):
        print("追击敌人")
class DrugDog(Dog):
    def work(self):
        print('追查毒品')
class Police():
    def job(self,dog):
        dog.work()
ad = ArmyDog()
dd = DrugDog()
ivy = Police()
ivy.job(dd)

7、类属性及相关方法

下面这个就是类属性,不要和self.width = 100这样的搞混了,这种self是写在__init__里的,是实例属性,访问类属性可以通过对象去访问,也可以通过类去访问

在记录某项数据的时候,如果这个数据要一直保持一致,则定义类属性,为什么?因为实例属性要求每个对象为其单独开辟一份内存空间来记录数据,类属性为全类共有的,仅占用一份内存

class Dog():
    tooth = 10
a = Dog()
b = Dog()
print(a.tooth)
print(b.tooth)
print(Dog.tooth)
7.1、修改类属性

类属性只能通过类修改,不能通过实例对象修改,如果通过实例对象修改类属性,表示的是创建了一个同名的实例属性,类属性就相当于一个大的东西,牵一发而动全身的东西

class Dog():
    tooth = 10
a = Dog()
Dog.tooth = 20
print(a.tooth)
# result:20
7.2、类方法

需要用装饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类,一般以cls作为第一个参数

当方法中需要使用类对象,比如访问私有类属性时,定义类方法,类方法一般和类属性配合使用

class Dog():
    __tooth = 10
    @classmethod
    def get_tooth(cls):
        return cls.__tooth
a = Dog()
print(a.get_tooth())
7.3、静态方法

静态方法需要通过装饰器@staticmethod来进行修饰,静态方法既不需要传递类对象,也不需要传递实例对象,也就是形参没有self/cls,当方法中既不需要使用实例也不需要使用类时,创建静态方法

class Dog():
    @staticmethod
    def print_info():
        print("这是一个静态方法")
a = Dog()
a.print_info()

二、异常

当检测到一个错误之后,解释器就无法继续执行了,出现错误提示,这就是异常

如果你不确定你写的这一句代码会不会报错,可以把这句代码放到异常语句里书写

1、异常介绍

try:
    可能发生错误的代码
except:
    如果出现异常执行的代码
try:
    open('1.txt','r')
except:
    open('1.txt','w')

异常类型

这里的异常类型就是NameError,异常类型就是最后一排,冒号前面的东西

1.1、捕获指定异常

如果尝试执行的代码的异常类型和要捕获的异常类型不一样,则无法捕获异常,一般try下面只放一条尝试执行的代码

try:
    可能发生错误的代码
except 异常类型:
    如果捕捉到该异常类型执行的代码

try:
    print(num)
except NameError:
    print("NameError")
1.2、捕获多个异常类型

当捕获多个异常时,把要捕获的异常的名字写在except后面,用元组的形式存放

try:
    print(num)
except (ZeroDivisionError,NameError):
    print("有错误")
1.3、捕获异常描述信息

在这里"name 'num' is not defined.这个是异常描述信息,以下代码,result是一个变量,print就是打印异常描述信息

try:
    print(num)
except (ZeroDivisionError,NameError) as result:
    print(result)
1.4、捕获所有异常

Exception是所有程序异常类的父类

try:
    print(num)
except Exception as result:
    print(result)
1.5、异常的else

else表示的是如果没有异常的时候要执行的代码

try:
    print(1)
except Exception as result:
    print(result)
else:
    print('未发现异常')
# result:
1
未发现异常
1.6、异常的finally

finally表示的是无论是否异常都要执行的代码,例如关闭文件

try:
    f = open("test.txt","r")
except Exception as result:
    f = open("test.txt","w")
else:
    print('未发现异常')
finally:
    f.close()
1.7、命令提示符运行py文件

在我的电脑中,找到存放py代码项目的那个路径,删除掉之后输入cmd,就会进入到cmd界面,然后输入python test.py,就可以运行,为什么输入python而不是python3呢,因为我的python已经是3.x.x版本了

2、异常的传递

在命令提示符中运行ctrl+c停止才会报错,pycharm中不属于报错,import time的意义是要使用time模块里的sleep函数,让程序运行的慢一点,不然这个程序一瞬间就执行完了,我们没有停止的机会来测试这个案例

import time
try:
    f = open('test.txt','r')
    try:
        while True:
            con = f.readline()
            if len(con) == 0:
                break
            time.sleep(3)
            print(con)
    except:
        print('程序被意外终止')
except:
    print('文件不存在')

3、自定义异常

抛出这个自定义异常用raise

将不满足程序逻辑要求的代码,捕获异常,比如要求输入3位数字密码,只输入了2位,然后会报异常,把这个异常当作一个类,把他定义出来

!!:可以这样理解,其实这个程序本身是没有异常的,但是因为不符合你的业务逻辑,所以定义了一个异常类,把这个不符合逻辑的代码归类为异常,以便可以执行except里面的代码

class InputerNumError(Exception):
    def __init__(self, len,min_len):
        self.len = len
        self.min_len = min_len

    def __str__(self):
        return f'你输入的密码长度为{self.len},密码至少要{self.min_len}位'

def main():
    try:
        num = input('请输入密码:')
        if len(num) < 3:
            raise InputerNumError(len(num),3)
    except Exception as e:
        print(e)
    else:
        print('密码输入完成')
        
main()

三、模块

Python模块,就是一个python文件,以.py结尾,我们可以在左边的外部库里找到random.py文件,我们import 模块,就是导入一个py文件

1、导入模块

第一种        import 模块名

import 模块名
模块名.功能名()

import math
print(math.sqrt(9)) # sqrt:square root 平方根

第二种        from 模块名 import 功能1,功能2......,这种方式导入模块时,调用不用math.sqrt()了,直接写就行

from math import sqrt
print(sqrt(9))

第三种        from 模块名 import *

from math import *
print(sqrt(9))
1.1、定义别名

模块定义别名        import 模块名 as 别名,定义了别名之后,就不能再用原名,不然报错

import math as mt
print(mt.sqrt(4))

功能定义别名        from 模块名 import 功能 as 别名,定义别名之后,不能再用原名

from math import sqrt as aa
print(aa(4))

2、模块制作

每个python文件都可以作为一个模块,模块的命名必须符合标识符命名规则

模块制作分三步        定义模块--测试模块--调用模块

定义、测试模块

如果就这样把测试的代码留在上面,那么在别的文件导入这个my_module1作为模块的时候,也会运行这个测试代码,所以这个测试代码只能在模块内运行

我们引入__name__,这个__name__是系统变量,是模块的标识符,如果在自己本来的文件下面,则等于__main__,如果在别的文件下面,则等于别的文件的文件名

3、模块定位顺序

tip1:自己的文件名不要和已有的模块名重复,否则导致模块功能无法使用;

当导入一个模块时,Python解析器对模块位置搜索的顺序是从当前目录开始,到shell变量PYTHONPATH下的每个目录,也就是说,如果我们在当前目录下创建一个空的random文件,导入random模块的时候会优先导入这个,导致报错

tip2:使用from 模块名 import 功能的时候,如果功能名字重复,调用到的是最后定义或导入的功能,以下是案例,这个会报错,这里会优先调用函数sleep而不是模块中的sleep

from time import sleep
def sleep():
    print("Sleeping...")
sleep(2)

4、__all__列表

module代码

__all__ = ['testA']
def testA(a,b):
    print(a+b)
def testB(a,b):
    print(a-b)

自身代码

from my_module1 import *
testA(2,3)
testB(3,4) # 报错

!!注意这个时候会报错的,因为在module模块中,all列表里只有testA这个元素,所以在导入这个模块时,也只能导入testA这个功能

5、Python中的包

包将有联系的模块组织在一起,放到同一个文件夹下,并在这个文件夹创建一个名字为__init__.py 

的文件,这个文件夹就称为包

5.1、制作包

[New]--[Python Package]--输入包名--[OK]--新建功能模块(有联系的模块)

新建包后,包内部会自动创建__init__.py文件,这个文件控制着包的导入行为

5.2、导入包

方法一:import 包名.模块名        包名.模块名.目标

import mypackage.my_module1
mypackage.my_module1.print_info()

方法二:必须在__init__.py文件中添加__all__ = [],控制允许导入的模块列表

from 包名 import *        模块名.目标

和上面的__all__列表一样,没有允许的就不能调用

四、学生管理系统(面向对象)

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}'

aa = Student('xjj','男','324')
print(aa)

managerSystem.py

from StudentManagerSystem.student import Student

class StudentManager():
    def __init__(self):
        # 存储学员数据
        self.student_list = []

    def run(self):
        # 加载学员数据
        self.load_student()

        while True:
            self.show_menu()
            num = int(input('请输入需要的序号:'))
            if num == 1: # 添加
                self.add_student()
            elif num == 2: # 删除
                self.del_student()
            elif num == 3: # 修改
                self.modify_student()
            elif num == 4: # 查询
                self.search_student()
            elif num == 5: # 显示
                self.show_student()
            elif num == 6: # 保存
                self.save_student()
            elif num == 7:
                break
    @staticmethod
    def show_menu():
        print('请选择功能-------------------')
        print('1、添加')
        print('2、删除')
        print('3、修改')
        print('4、查询')
        print('5、显示')
        print('6、保存')
        print('7、退出')
        print('-'* 20)

    def add_student(self):
        name = input('输入姓名:')
        gender = input('输入性别:')
        tel = int(input('输入手机号:'))
        student = Student(name, gender, tel)
        self.student_list.append(student)
        print(student)
    def del_student(self):
        del_name = input('输入要删除的姓名:')
        for i in self.student_list:
            if i.name == del_name:
                self.student_list.remove(i)
                break
        else:
            print('没有找到用户')
        print(self.student_list)
    def modify_student(self):
        print('修改')
    def search_student(self):
        print('查询')
    def show_student(self):
        print('显示')
    def save_student(self):
        print('保存')
    def load_student(self):
        print('加载')

main.py

from managerSystem import *
if __name__ == '__main__':
    manager1 = StudentManager()
    manager1.run()

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐