【Python】面向对象、模块化


  本文是我在学习Python过程当中的心得和学习笔记,包含了Python的入门知识,控制结构,列表,字典,元组,集合,字符串,函数等等Python基础内容,并附上了学习的代码,仅供大家参考。如果有问题,有错误欢迎大家留言。剩余的内容可以通过 这篇文章找到。

一、面向对象编程

在这里插入图片描述
  Python当中一切皆为对象,Python是面向对象的编程语言。
  类一般指数据类型,不同的数据类型属于不同的类,例如int类,float类等等。对象一般指类具体化之后的事物,例如100,99,520都是int类之下包含的相似的不同个例,这些个例专业术语成为实例或者对象。
  类的组成:类属性、实例方法、静态方法、类方法。
  类属性:类中方法以外的变量成为类属性,被该类所有对象所共享。
  实例方法:在类当中定义的普通函数,在类外面定义的称为函数,在类内部定义的称为类的方法。
  类方法:使用@classmethod修饰的方法, 使用类名直接访问的方法。
  静态方法:使用@staticmethod修饰的方法,使用类名直接访问的方法。

1.1类的定义和调用

#类名由一个或多个单词组成,每个单词的首字母大写,其余字母小写
class Student:  #Student为类的名称
    native_place = '福建' #直接写在类里面的变量,称为类的属性
    def __init__(self,name,age):    #这是一个实例方法,初始化函数,默认输入的值到这个函数进行操作
        self.name = name    #self.name 称为实体属性,进行了一个赋值操作,将局部变量的name的值赋值给实体属性
        self.age = age
    #实例方法
    def eat(self):  #默认里面加self
        print('学生正在吃饭...')
    #静态方法
    @staticmethod
    def method():   #默认里面什么都不加
        print('我使用了staticmethod进行修饰,所以我是静态方法')
    #类方法
    @classmethod
    def cm(cls):    #默认里面要加cls
        print('我是类方法,因为我使用了classmethod进行修饰')
#在类之外定义的称为函数,在类之内定义的称为方法
def drink():
    print('喝水')

#创建Student类的对象
stu1 = Student('张三',23) #这里的默认调用初始化函数,两个参数默认输入到这个函数中进行操作
stu1.eat()      #调用类的方法,对象名.方法名()
print(stu1.name)    #调用类的属性
print(stu1.age)

Student.eat(stu1)   #这行代码与stu1.eat()功能相同,都是调用Student类中的eat方法
                    #类名.方法名(类的对象)-->实际上就是调用方法定义处的self
print(stu1.native_place)
Student.native_place = '北京' #改变类的属性
print(stu1.native_place)
print('-------类方法的使用方式--------')
Student.cm()
print('-------静态方法的使用方式--------')
Student.method()

#动态绑定类的属性和方法
stu2 = Student('李四',30)
print(id(stu1))
print(id(stu2))
stu1.gender = '女'
print(stu1.name, stu1.age, stu1.gender)
print(id(stu1)) #绑定属性前后stu1的ID(内存地址)不变
#print(stu2.name, stu2.age, stu2.gender) #报错,因为stu2没有绑定gender属性

def show():
    print('定义在类之外的,称为函数')
stu1.show = show
stu1.show()
#stu2.show() #报错,因为stu2没有绑定show方法

1.2 封装和多态

在这里插入图片描述
封装

class Student:
    def __init__(self,name,age):
        self.name = name
        self.__age = age    #年龄不希望在类的外部被使用,所以加了__
    def show(self):
        print(self.name,self.__age)
stu = Student('张三',20)
print(stu.name) #在类的外部使用name,可以访问
#print(stu.__age)   #在类的外部使用__age,不能访问,报错
stu.show()  #使用类的内置方法去调用,属于内部访问,可以访问

#强行访问__age的方法
print(dir(stu))             #打印出类的全体属性
print(stu._Student__age)    #在类的外部可以使用__age

1.3 继承和方法重写

  以下图为例老虎、猴子等为子类;哺乳动物为父类;动物为祖先类。
在这里插入图片描述
  语法格式为:

class 子类类名(父类类名1,父类类名2...):
    pass

  需要注意的是:
    1.Python支持多继承(属于Python特色了),即一个子类可以继承多个父类。

class A(object):#A类继承object
    pass
class B(object):#B类继承object
    pass
class C(A,B):#C类继承A, B
    pass

    2.定义子类时,必须在其构造函数当中调用其父类的构造函数。
  方法重写:父类的方法在子类当中重新编写(即更改的意思)

    3.如果一个类没有继承任何类,那么默认继承object类。使用内置函数dir( )可以察看指定对象的所有属性和方法。
在这里插入图片描述

class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def __str__(self):
        return '我的名字是{0},今年{1}岁'.format(self.name,self.age)
        #字符串格式化输出

stu = Student('张三',20)
print(dir(stu)) #输出类的所有属性和方法
print(stu)      #若不在Student中重写__str__()方法,则输出的是Student类的地址
#这里我们重写了,则输出的是return中的语句
class Person(object):   #Person继承object,object也可以不写
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def info(self):
        print(self.name,self.age,end='\t')

class Student(Person):  #Student继承Person类
    def __init__(self, name, age,stu_no):
        # 先初始化父类属性,然后在对子类的属性进行幅值,super().可以理解为调用了父类的方法
        # super().是为了解决多继承当中多个父类的问题,倘若父类当中的方法名称相同,则可以在super().当中说明调用的是哪个父类的方法
        super().__init__(name,age)
        self.stu_no = stu_no
    def info(self):     #方法重写
        super().info()
        print('学号:{0}'.format(self.stu_no))

class Teacher(Person):  #Teacher继承Person类
    def __init__(self, name, age,teach_of_year):
        super().__init__(name,age)
        self.teach_of_year = teach_of_year
#创建实例对象
stu = Student('张三',20,'1001')
teacher = Teacher('李四',34,10)
#调用父类的方法
stu.info()
teacher.info()

1.4 多态

在这里插入图片描述
  Java是静态语言,Python是动态语言
在这里插入图片描述

class Animal(object):
    def eat(self):
        print('动物会吃')
class Dog(Animal):
    def eat(self):
        print('狗吃骨头...')
class Cat(Animal):
    def eat(self):
        print('猫吃鱼...')

class Person:
    def eat(self):
        print('人吃五谷杂粮')

#定义一个函数,这里就使用了多态
#先判定obj的类型,然后在根据其类型调用其方法
def fun(obj):
    obj.eat()
#调用函数
cat1 = Cat()
cat1.eat()
print('----------------')
fun(Cat())
fun(Dog())
fun(Animal())
fun(Person())
'''Dog和Cat是重写了父类当中的方法,Person虽然和Animal没有继承关系
但是通过多态,我们可以利用一个函数就将他们的输出联系起来
在Python当中,我们只关注对象的行为(方法)是否类似,而不关注对象类型是否相同'''

1.5 特殊属性和特殊方法

在这里插入图片描述

#特殊属性__dict__
class A:
    pass
class B:
    pass
class C(A,B):
    def __init__(self,name,age):
        self.name = name
        self.age = age
#创建C类的对象
x = C('Jack',20)    #x是C类的一个实例对象
print(x.__dict__)   #实例对象的属性字典
print(C.__dict__)   #C类的属性字典
print(x.__class__)  #<class '__main__.C'>,,表明属于C类
print(C.__bases__)  #C类的父类类型元素
print(C.__base__)   #输出C类的父类,AB谁写前面就输出谁,这里是A
print(C.__mro__)    #C类的层次结构,即输出所有父类和祖先类(包括object)
print(A.__subclasses__())   #输出A的所有子类,仅C类一个
#特殊方法
class Student:
    def __init__(self,name):
        self.name = name
    def __add__(self,other):    #实现两个对象相加
        return self.name+other.name
    def __len__(self):
        return len(self.name)
stu1 = Student('Jack')
stu2 = Student('李四')
s = stu1+stu2
print(s)    #报错,显示不能相加
#倘若非得相加,那么在Student类当中定义__add__函数
s2 = stu1.__add__(stu2) #和前面的功能相同,实现相加操作
print(s2)

lst = [11,22,33,44]
print(len(lst))     #输出列表长度
print(lst.__len__())
print(len(stu1))

在这里插入图片描述

'''总结:执行实例创建:
    1.先将类名(Person)传给new的cls,开新空间(obj)用于后续实例对象创建
    2.接受到obj的self,实例对象p1指向self
    3.new在前为实例创建对象,init为实例的属性赋值,因此在我们创建一个实例对象(如p1)时,首先调用的是new创建,然后在调用init赋值
    (可以使用debug逐步观察)
'''
class Person(object):
    def __new__(cls,*args,**kwargs):    #传入参数为Person类对象(观察id可以看出)
        print('__new__被调用了,cls的id值为{0}'.format(id(cls)))
        obj = super().__new__(cls)
        print('创建的对象的id为:{0}'.format(id(obj)))
        return obj

    def __init__(self,name,age):    #传入参数为实例对象p1,self=p1(观察id可以看出)
        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)))

#创建Person类的实例对象
p1 = Person('张三',20)
print('p1这个Person类的实例对象的id:{0}'.format(id(p1)))

1.6 拷贝

在这里插入图片描述

class CPU:
    pass
class Disk:
    pass
class Computer:
    def __init__(self,cpu,disk):
        self.cpu = cpu
        self.disk = disk
#变量赋值
cpu1 = CPU()
cpu2 = cpu1
print(cpu1,id(cpu1))
print(cpu2,id(cpu2))    #cpu1和cpu2 id相同,体现了Python赋值的驻留机制,即虽然形成两个变量,但是实际上还是指向同一个对象
#浅拷贝
import copy
disk = Disk()   #创建一个硬盘类对象
computer = Computer(cpu1,disk)
computer2 = copy.copy(computer)
print(computer,computer.cpu,computer.disk)
print(computer2,computer2.cpu,computer2.disk)
print('----------------------------------')
#深拷贝
computer3 = copy.deepcopy(computer)
print(computer,computer.cpu,computer.disk)
print(computer3,computer3.cpu,computer3.disk)
'''
总结:
computer和computer2的cpu disk id相同,但是本身的id不同,这就称为浅拷贝
浅拷贝后对象的属性(这里是id变化了)改变,但子对象(被调用的类)不变(这里是cpu和disk)。
深拷贝是对象的属性和子对象全部发生改变,所有属性和子对象的id改变
'''

二、 模块化编程

  一个模块当中可以包含多个函数、类、语句。在Python当中一个.py文件就是一个模块。
使用模块的好处有:
  方便其它程序和脚本的导入并使用;
  避免函数名和变量名冲突;
  提高代码的可维护性;
  提高代码的可重用性。

2.1 模块调用

在这里插入图片描述
  导入模块的两种方法

import math #关于数学运算的模块,可以使用模块中的所有函数、类
print(id(math))
print(type(math))
print(math)
print(math.pi)
print('----------------------')
print(dir(math))
print(math.pow(2,3))
from math import pi #仅仅导入一个特定的对象
print(pi)
#print(math.pow(2,3))    #报错

  定义自定义模块calc.py

#自定义模块calc.py
def add(a,b):
    return a+b

  调用自定义模块calc.py

import calc
print(calc.add(10,20))

  在主程序当中调用

#自定义模块calc.py
def add(a,b):
    return a+b

if __name__ == '__main__':
    print(add(10,20))
'''只有执行calc.py文件时,才会输出这个语句'''

2.2 Python中的包

在这里插入图片描述
  包类似于C语言当中的多个头文件组成的头文件,其中调用了多个模块。为了避免名称相同的模块冲突,而设置的包。

#导入package1包中的module_A模块
import package1.module_A
print(package1.module_A.a)
'''
import package1.module_A as ma  #ma是package1.module_A的别名
print(ma.a)
#二者作用相同
'''
#导入带有包的模块时的注意事项
import package1
import calc
#使用import方式进行导入时,只能跟包名或者模块名

from package1 import module_A
from package1.module_A import a
#使用from ...import可以导入包、模块、函数、变量等等

2.3 Python当中常用的模块

请添加图片描述
  shcedule模块需要下载,在pycharm中左下角点击小正方形,然后再点击packages,最后在搜索框中搜索schedule,下载即可。

import schedule
import time

def job():
    print('哈哈 --------')

schedule.every(3).seconds.do(job)
#每3秒执行一次job()
while True:
    schedule.run_pending()
    time.sleep(1)   #休眠1秒

2.4 文件读写

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

file = open('a.txt','r',encoding='UTF-8')
print(file.readlines())
file.close()

在这里插入图片描述
  with语句(上下文管理器),with语句可以自动管理上下文资源,不论什么原因跳出with块,都能确保文件正确的关闭,以此来达到释放资源的目的。
  如下代码所示,使用with语句打开文件,就不再需要 file.close( )。

with open('a.txt','r',encoding='UTF-8') as file:
    print(file.read())

2.5 OS模块的常见函数

  os模块是Python内置的与操作系统功能和文件系统相关的模块,该模块中的语句的执行结果通常与操作系统有关,在不同的操作系统上运行,得到的结果可能不一样。
  os模块与os.path模块用于对目录或文件进行操作。

#os模块是与操作系统相关的一个模块
import os
os.system('notepad.exe')    #打开记事本
os.system('calc.exe')       #打开计算器
#直接调用可执行文件(.exe文件)
os.startfile('D:\\QQ\\Bin\\QQScLauncher.exe')
# os.startfile('D:/QQ/Bin/QQScLauncher.exe')	# 相同
#打开QQ

在这里插入图片描述

import os
print(os.getcwd())

lst = os.listdir('../chap12')
print(lst)

#os.mkdir('newdir2')
#os.makedirs('A/B/C')
#os.rmdir('newdir2')
#os.removedirs('A/B/C')

在这里插入图片描述

import os.path
print(os.path.abspath('demo12.py'))
print(os.path.exists('demo12.py'),os.path.exists('demo18.py'))  #判断文件是否存在
print(os.path.join('E:\\python','demo12.py'))   #仅仅是单纯的拼接,文件没有复制,没有其他操作
print(os.path.split('D:\\software\\pycharm\\project\\hi\\chap12\\demo12.py'))   #将文件名和路径名分开
print(os.path.splitext('demo12.py'))    #将文件名和后缀名分开
print(os.path.basename('D:\\software\\pycharm\\project\\hi\\chap12\\demo12.py'))    #从路径当中将文件名+后缀名提取出来

猜你喜欢

转载自blog.csdn.net/qq_45765437/article/details/130782741