谈“对象“

简介: 谈“对象“

面向对象

一切皆对象,和java一样,各编程语言一样的思想


规范


类名首字母大写,和java一样


创建的规范


python3创建类的时候,可以不带括号,也可以带,也可以显示继承object,如果带个()空括号,其实也是隐士的继承了object。这三种方式是相等的。


类的组成


类属性:类中方法外,被该类所有对象共享


类方法:@classmethod修饰,使用类名直接访问的方法


静态方法@staticmethod,使用类名直接调用


类属性、类方法、静态方法都是用类名直接调用


实例方法


# 创建的语法
class Studnet:
    native_pace = '吉林' # 类属性 
    # 初始化方法 这个self赋值时候不用写,赋值name和age即可,self默认带
    def __init__(self,name,age): # 将局部变量的值赋值给实体属性,self.name称为实例属性
        self.name = name
        self.age = age
    # 实例方法
    # self 为这个方法名,name,age的为实例属性
    def eat(self): # 这个self这里必写,self单词可以变,但程序员习惯self
        print('学生在吃饭')
# 在类外定义的称为函数,类之内称为方法
    # 类方法
    @classmethod
    def cm(cls):
        print('类方法')
    # 静态方法中不能写self,注意
    @staticmethod
    def sm():
        print('静态方法')
# 类之外定义的称为函数,在类之内定义的称为方法
def drink():
    print('喝水')

对象的创建

和java一样


对象的创建又称为类的实例化


语法:


实例名=类名()


如stu = Student()


实例对象会有个类指针指向类对象


类名.方法名(类的对象),实际上就是方法定义处的self

Stu1 = Student('张三',20)Student.eat(stu1)


动态绑定属性和方法

Python是动态语言,在创建对象之后,可以动态地绑定属性和方法

stu1 = Studnet('张三',20)
stu2 = Studnet('李四',30)
print(id(stu1)) # 和stu2不同
print(id(stu2))
print('--------为stu2动态绑定性别属性-----------')
stu2.gender = '女'  # 这点和java不一样,java没有成员变量(属性-字段),是不能指定的
# Student中没有 gender属性 能动态绑定性别 ,只属于stu2自己
print(stu2.gender) # 女
def show():
    print('定义在类之外的,称函数')
stu1.show = show()
stu1.show # 定义在类之外的,称函数
stu2.show # 报错 没有胃stu2动态绑定show方法,在对象上之后函数就称为方法了

面向对象的三大特征

封装:提高程序的安全性


将数据(属性)和行为(方法)包装到类中。在方法内部对属性进行操作,在类对象的外部调用方法。这样,无需关心方法内部的具体实现细节,从而隔离了复杂度


在Python中没有专门的修饰符用于属性的私有,如果该属性不希望在类对象外部被访问,前面使用两个"-"


继承:提高代码的复用性


如果一个类没有继承任何类,默认继承object


Python支持多继承(java不支持多继承)


定义子类时,必须在其构造函数中调用父类的构造函数


多态:提高程序的可扩展性和维护性


封装

classStudent:def__init__(self,name,age):self.name = nameself.__age = agedefshow(self):       print(self.name,self.__age)stu = Student('张三',20)# 在类外部使用name、ageprint(stu.name) # 张三# print(stu.__age) # 报错print(dir(stu)) # dir()可以查看类的所有属性和方法 ,里面找到一个_Student__ageprint(stu._Student__age) # 这样也能访问,但是不建议这种访问方式​classStudent2:def__init__(self,age):self.set_age(age)defget_age(self):returnself.__age # 不希望在外面使用,所以加上两个__defset_age(self,age):if0<=age<=120:self.__age = ageelse:self.__age = 18stu1 = Student2(150)stu2 = Student2(30)print(stu1.get_age()) # 18print(stu2.get_age()) # 30


继承

classPerson(object): #object默认不写也行def__init__(self,name,age):self.name = nameself.age = agedefinfo(self):        print('姓名:{0},年龄{1}'.format(self.name,self.age))# 定义子类classStudent(Person):def__init__(self,name,age,score):super().__init__(name,age)self.score = scoredefinfo(self):super.info()# 还想用父类的info()可以super.        print(self.score)# 重写# 测试stu = Student('Haha',20,'1001')stu.info() # 从父类中继承的方法 ,重写后就是Student的方法了


object类

object类是所有类的父类,因此所有类都有object类的属性和方法


内置函数dir()可以查看指定对象的所有属性


Object有一个_ str_ ()方法,用于返回一个对于“对象的描述”,对于内置函数str()进程用于print()方法,帮我们查看对象的信息,所以我们经常会对__str _()进行重写,而不是输出内存地址


重写str

classStudent:def__init__(self,name,age):self.name=nameself.age=agedef__str__(self):return'我的名字是{0},今年{1}岁'.format(self.name,self.age)​stu=Student('Haha',20)print(stu) # 我的名字是Haha,今年{20}岁  默认调用_str_()这样的方法


多态

指的是一类事物有多种形态,一个抽象类有多个子类(因而多态的概念依赖于继承),不同的子类对象调用相同的方法,产生不同的执行结果,多态可以增加代码的灵活度


Python中虽然没有数据类型,但是具备多态特征

classAnimal:def eat(self):        print('eating...')classDog(Animal):    def eat(self):        print('dog gnawing...')​def fun(obj):    obj.eat()fun(Animal()) # eating...fun(Dog()) #  # dong gnawing


Java是静态,强类型语言,Python是动态语言

静态语言和动态语言关于多态的区别


静态语言实现多态的三个必要特征


继承


方法重写


父类引用执行子类对象


动态语言的多态的多态崇尚“鸭子类型”,当看到一只鸟走起来像鸭子、游泳像鸭子,收起来也像鸭子,那么这鸟就可以被称为鸭子;

在鸭子类型中,不用对象是什么类型,到底是不是鸭子,只关心对象的行为

特殊方法和特殊属性

特殊属性


_ dict __ :获得类对象或实例对象所绑定的所有属性和方法


__ len __():通过重写它,让内置函数len()的参数可以是自定义类型


特殊方法


_add _():通过重写它,让内置函数len()的参数可以是自定义类型


_new _():用于创建对象


_init() _:对创建的对象进行初始化

classA:def__init__(self,name,age):            self.name = name            self.age = agex = A('Jack',18)print(x.__dict__) #{'name': 'Jack', 'age': 18}print(x.__class__) # <class '__main__.A'> 所属的类classB(A):passprint(B.__base__) # <class '__main__.A'> # 类的基类,如果多继承,谁在前输出谁print(B.__bases__) # (<class '__main__.A'>,) 输出其父类类型的元素print(B.__mro__) # 继承层次结果 B继承A继承object (<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)print(A.__subclasses__())#子类列表  [<class '__main__.B'>]​a = 20b = 100c = a + bd = a.__add__(b) #等同于+print(c)print(d)classStudent:def__init__(self,name):        self.name = namedef__add__(self, other):# 必须在这里写,stu1.__add_(stu2)这样也报错return self.name + other.namedef__len__(self):# 必须写在这里才能计算长度return len(self.name)stu1 = Student('张三')stu2 = Student('李四')s = stu1 + stu2 # 写了__add__方法才能加,否则报错print(s) # 张三李四lst = [1,2,3,4,5]print(len(lst)) # 5print(lst.__len__()) # 5print(stu1.__len__()) # 2

6b32ca25d11239f9e28774481ddefdc6.png


new执行是优先于init的。new后的对象会给__ init __中的self


类的浅拷贝与深拷贝

变量的赋值操作


只是形成两个变量,实际上还是指向同一个对象


浅拷贝


Python拷贝如果没特殊说明的话,一般都是浅拷贝,拷贝时,对象包含的子对象的内容不拷贝,因此,源对象与拷贝对象会引用同一个子对象


深拷贝


使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象,源对象和拷贝对象所有的子对象也不相同


源对象和拷贝对象的所有子对象也要重新拷贝一份


浅拷贝

20926e6dbd5008ddb9cbcc48caa30caa.png


classCPU:passclassDisk:passclassComputer:def__init__(self,cpu,disk):       self.cpu = cpu       self.disk = diskcpu1 = CPU()cpu2 = cpu1 # 这个是赋值操作print(cpu1,cpu2) # 内存地址一样# <__main__.CPU object at 0x000001A54423FF40> <__main__.CPU object at 0x000001A54423FF40>print('----------------------')disk = Disk() # 创建一个硬盘computer = Computer(cpu1,disk) # 创建一个计算机类的对象# 浅拷贝import copycomputer2 = copy.copy(computer)print(disk)# # <__main__.Disk object at 0x000001E1026AF3D0>print(computer,computer.cpu,computer.disk)# computer2和computer内存地址不同,子对象的内存地址是相同的-Disk和CPU# <__main__.Computer object at 0x000001A543EF4850> <__main__.CPU object at 0x000001A54423FF40> <__main__.Disk object at 0x000001A54423F3D0>print(computer2,computer2.cpu,computer2.disk)# <__main__.Computer object at 0x000001A5442928F0> <__main__.CPU object at 0x000001A54423FF40> <__main__.Disk object at 0x000001A54423F3D0>print('---------------------------')# 深拷贝computer3 = copy.deepcopy(computer)print(computer,computer.cpu,computer.disk)print(computer3,computer.cpu,computer3.disk)# 打印的内存地址各不同,computer、cpu、disk都拷贝了一份,内存地址变化了# <__main__.Computer object at 0x00000265D67B3E80> <__main__.CPU object at 0x00000265D67B3FD0> <__main__.Disk object at 0x00000265D67B3EB0># <__main__.C

深拷贝

459d496d55b15cfad75f0ad0b78dc207.png


对于多肽

动态语言:动态语言关注对象的行为

静态语言:继承、方法重写、父类引用指向子类对象

模块

英文为Modules


一个模块可以包含N多个函数


在Pyhton中一个扩展名.py的文件就是一个模块


使用模块的好处


方便其它程序和脚本的导入并使用


避免函数名和变量名冲突


提高代码的可维护性


提高代码的可重用性


自定义模块

创建模块


新建一个.py文件,名称尽量不要与Python的自带的标准名称相同


导入模块


import 模块 [as 别名]


from 模块名称 import 函数/变量/类

import math # 导入数学模块 每一个模块都有id、type以及它的值组成print(id(math))print(type(math))print(math)print(math.pi) # 3.141592653589793#2051647076960#<class 'module'>#<module 'math' (built-in)>print(dir(math))from math import piprint(pi) # 这是能直接输出的print(pow(2,3)) # 如果不导入math,只导入from math import pi 是不能使用的


以主程序形式运行

在每个模块的定义中都包括一个记录模块名称的变量_ name _,程序可以检查该变量,以确定它们在哪个模块中执行,如果一个模块不是被导入到其它程序中执行,那么它可能在解释器的顶级模块中执行。顶级模块的 _ name _变量的值为 _main _

# 开发时间:2023/2/11defadd(a,b):return a+bif __name__ == '__main__':   print(add(10,20)) # 只有当运行这个calc2的时候才会执行这个主程序语句,可防止其它程序调用此类运行这个


Python中的包


Python中的包


包是一个分层次的目录结构,它将一组功能相近的模块组织在一起(包中包含N多个模块)


作用


代码规范


避免模块名称冲突


包与目录的区别


创建之后默认包含__ init __ .py文件的目录称为包


目录里通常不包含_init _ .py文件


包的导入


import 包名.模块名(import只能导入包名、模块名)


用from 能导入包、模块、函数名、变量名 pageage1.module_A import ma


比如


创建python软件包


在下面新建pageage1,下面创建2模块-module_A.py/moduleB.py


在外面创建demo.py

import pageage1.module_A as ma# 现在就可以使用pageage1.module_A的内容了(别名叫ma)


Python中常用的内置模块


模块名                                        描述


sys                               与Python解释器及其环境操作相关的标准库


time                               提供与时间相关的各种函数的标准库


os                                提供了访问操作系统服务功能的标准库


calendar                       提供与日期现相关的各种函数的标准库


urllib                            用于读取来自网上(服务器)的数据标准库


json                             用于使用序列号和反序列化对象


re                               用于在字符串中执行正则表达式匹配和替换


math                         提供标准算术运算函数的标准库


decimal                     用于进行准确控制精度、有效位数和四舍五入的十进制运算


logging                   提供灵活的记录事件、错误、警告和调试信息等日志信息的功能


简单的代码实现

import sysimport timeimport urllib.requestimport math# getsizeof是获取占用字节数print(sys.getsizeof(20)) # 28print(sys.getsizeof(21)) # 28print(sys.getsizeof(True)) # 28print(sys.getsizeof(False)) # 24print(time.time()) # 对应秒数 1676127718.0125294print(time.localtime(time.time())) # 将秒转成本地时间time.struct_time(tm_year=2023, tm_mon=2, tm_mday=11, tm_hour=23, tm_min=1, tm_sec=58, tm_wday=5, tm_yday=42, tm_isdst=0)print(urllib.request.urlopen('http://ww.baidu.com').read())print(math.pi)

第三方模块

Python如此强大,离不开第三方模块


第三方模块的安装


pip install 模块名(在线安装方式-cmd安装-也是使用最多的方式)


第三方模块的使用


import 模块名(安装导入之后我们就可以使用)


在cmd窗口,我们可以输入python进入python交互模式


此时import使用已经安装的模块如果能使用证明安装成功


编码格式

编码格式介绍


文件的读写原理


文件读写操作


文件对象常用的方法


with语句(上下文管理器)


目录操作


常见的字符编码格式


Python的解释器使用的是Jnicode(内存)


py文件在磁盘上使用UTF-8存储(外存)

0e86c89cc0168ce812d10d5a3aa1aeb6.png


py默认是UTF-8,它是变长编码,1-4个字节表示1个字符,英文1个字节,汉字3个字节

文件读写原理

读写俗称IO操作-先进先出,如管道一般


文件到内存称为读,内存到文件称为写


读写之后需要关闭资源


文件读写操作

内置函数open()创建文件对象


语法规则:file = open(filename,[,mode,encoding])


file 是被创建的文件对象,open是创建文件对象的函数,


filename:是要创建或打开的文件名称,


mode:打开模式为只读模式


encoding:默认文本文件中字符的编写格式为gbk(所以我们在编译器中常见一打开乱码,并提示reload gbk)

file = open('a.txt','r') # 读,中括号是可选,写不写都行print(file.readlines()) # readlines读取的是一个列表file.close()


常用的文件打开模式


常用的文件打开模式


文件的类型


按文件中数据的组织形式,文件分为以下两大类


文本文件:存储的是普通“字符"文本,默认为unicode:字符集,可以使用记本事程序打开


二进制文件:把数据内容用“字节”进行存储,无法用记事本打开,必须使用专用的软件打开,举例:mp3音频文件,jpg图片.doc文档等


打开模式                                                描述


r(read only)                以只读模式打开文件,文件的指针将会放在文件的开头


w(write only)              以只写模式打开文件,如果文件不存在则创建,如果文件存在,则覆盖原有内容,文件指针在文件的开头


a                                     以追加模式打开文件,如果文件不存在则创建,文件指针在文件开头,如果文件存在,则在文件末尾追加内容,文件指针在原文件末尾


b                                   以二进制方式打开文件,不能单独使用,需要与共它模式一起使用,rb,或者wb


+                               以读写方式打开文件,不能单独使用,需要与其它模式一起使用,a+


文件对象的常用方法

方法名                                                 说明


read([size])                        从文件中读取size个字节或字符的内容返回。若省略[size],则读取到文件末尾,即一次读取文件所有内容


readline()                         从文本文件中读取一行内容


readlines()                   文本文件中的每一行都作为单独的字符串对象,并将这些对象返回到列表中返回


write(str)                      将字符串str内容写入文件


writelines(s_list)            将字符串列表s_lst写入文本文件,不添加换行符


seek(offset[,whence])        把文件指针移动到新的位置,offset表示相对于hencel的位置:offset:为正往结束方向移动,为负往开始方向移动whence(从何处)不同的值代表不同含义:0:从文件头开始计算(默认值)1:从当前位置开始计算2:从文件尾开始计算


tell()                          返回文件指针的当前位置,第一个字母是0,也就是从0开始


flush()                       把缓冲区的内容写入文件,但不关闭文件


close()                      把缓冲区的内容写入文件,同时关闭文件,释放文件对象相关资源-close()之后就不能写内容了,flush之后能close

file = open('a.txt','r')file = seek(2) # a.txt有中国两字。一个字占取2字节(gbk),从国开始读(如果在pyCharm中写的txt,可能就是utf-8了,不是2字节)print(file.read()) # 国# tellprint(file.tell()) # 会把当前所有内容打印出,指向最后一个位置。如seek(2)跳过了2,如果打印hello的话只会出现llo


with语句

with语句可以自动管理上下文资源,不论什么原因跳出with块,都能确保文件正确的关闭,以此来达到释放资源的目的


写文件时建议使用with语句形式

acfd5b2208b0c6820590e92d252b41d6.png


上下文为表达式,结果为上下文管理器


实现了__ enter__ () 方法和 __ exit()__方法 称为这个类遵守上下文管理协议,这个类的实例对象称为上下文管理器

# open('logo.png','rb') with之后as之前为上下文表达式,结果为上下文管理器-->同时创建一个运行时上下文-->自动调用_enter_()方法,并将返回值赋值给src_filewith open('logo.png','rb') as src_file:# as src_file:可选项上下文管理器对象的引用[可选项]src_file.read() # with语句体# 离开运行时上下文,自动调用上下文管理器的特殊方法_exit_()
withopen('a.txt','r') asfile:    print(file.read()) # 不用再手动close关闭了,因为离开with语句时会自动释放资源
# 开发时间:2023/2/12# MyContentMgr实现了特殊方法__enter__(),__exit__()称为该类对象遵守了上下文管理器协议,该类对象的实例对象,称为上下文管理器classMyContentMgr(object):def__enter__(self):       print('enter方法被调用执行了')return selfdef__exit__(self, exc_type, exc_val, exc_tb):       print('exit方法被调用执行了')# print('show方法被调用执行了',1/0) 即使产生异常也会调用exit方法,称为自动关闭资源defshow(self):# 实例Method       print('show方法被调用执行了')​# MyContentMgr这个类遵守上下文管理协议,它的对象就称为上下文管理器,把这个对象赋给file去存储# 相当于file = MyContentMgr(),这时候就可以通过file调用它的方法# with里面的所有缩进都称为with语句体with MyContentMgr() as file:# 这个with语句体执行之后就会自动跳出上下文管理器,调用exit方法   file.show()  # exit方法被调用执行了

目录操作

os模块是Python内置的与操作系统功能和文件系统相关的模块


该模块中的语句的执行结果通常与操作系统有关,在不同的操作系统上运行,得到的结果可能不一样。


os模块与os.path模块用于对目录或文件进行操作


既然是和os有关的,那么可以调用os有关的文件


不需要安装,它是自带的模块


os模块操作目录相关函数

函数                                                          说明


getcwd()                                返回当前的工作目录(文件目录)


listdir(path)                           返回指定路径下的文件和目录信息


mkdir(path[,mode])                               创建目录


makedirs(path1/path2...[,mode])           创建多级目录


rmdir(path)                                           删除目录


removedirs(path1/path2......)               删除多级目录


chidr(path)                             将path设置为当前工作目录


import os# 调用记事本# os.system('notepad.exe')# 直接调用可执行文件# os.startfile('C:\\Users\\79382\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe')

os.path模块操作目录

import 导入os.path


函数                                                        说明


abspath(path)                       用于获取文件或目录的绝对路径


exists(path)                 用于判断文件或目录是否存在,如果存在返回True,否则返回False


join(path,name)                   将目录与目录或者文件名拼接起来


splitext()                                    分离文件名和扩展名


basename(path)                       从一个目录中提取文件名


dirname(path)                从一个路径中提取文件路径,不包括文件名


isdir(path)                                用于判断是否为路径


案例

import os.pathprint(os.path.abspath('demo13.py')) # F:\pythonProject1\venv\Scripts\demo13.pyprint(os.path.exists('demo13.py')) # Falseprint(os.path.join('E:\\Python','demo13.py')) # E:\Python\demo13.pyprint(os.path.split('E:\\vipython\\chap15\\demo13.py')) # ('E:\\vipython\\chap15', 'demo13.py')print(os.path.splitext('demo13.py')) # ('demo13', '.py')print(os.path.basename('E:\\vippython\\chap15\\demo13.py')) # demo13.pyprint(os.path.dirname('E:\\vippython\\chap15\\demo13.py')) # E:\vippython\chap15print(os.path.isdir('E:\\vippython\\chap15\\demo13.py')) # False 因为demo13.py是文件


获取当前目录下的指定文件

import ospath = os.getcwd() # 获取当前目录下的所有文件lst = os.listdir(path)for filename in lst: # 获取所有以py结尾的文件if filename.endswith('.py'):       print(filename)

获取当前目录下的指定文件(包括子目录)

import ospath = os.getcwd()# os.walk()可以遍历指定目录下所有的文件lst_files = os.walk(path)print(lst_files) # 获取的是一个对象# 这个迭代器对象返回来的是一个元组for dirpath,dirname,filename in lst_files:'''      print(dirpath)      print(dirname)      print(filename)      print('------------')  '''for dir in dirname:       print(os.path.join(dirpath,dir))for file in filename:       print(os.path.join(dirpath),file)   print('------------------------------')



相关文章
|
7天前
|
JSON 程序员 C#
使用 C# 比较两个对象是否相等的7个方法总结
比较对象是编程中的一项基本技能,在实际业务中经常碰到,比如在ERP系统中,企业的信息非常重要,每一次更新,都需要比较记录更新前后企业的信息,直接比较通常只能告诉我们它们是否指向同一个内存地址,那我们应该怎么办呢?分享 7 个方法给你!
|
6月前
|
C++
C++中的对象
C++中的对象
54 2
|
6月前
|
测试技术 索引
v-for 与对象
v-for 与对象
|
前端开发
67 # 对象的处理
67 # 对象的处理
34 0
|
存储 程序员 编译器
C++都有对象了,你还没有吗?
C++都有对象了,你还没有吗?
83 0
|
Java 开发者 容器
你有对象吗?
你有对象吗?
107 0
|
存储 编译器 C语言
我现在必须new一个对象!!!
C++内存管理,手动开辟空间,我现在必须new一个对象!!!
89 0
我现在必须new一个对象!!!
|
算法 Java
对象的比较
本篇文章是对Java中一些常见的比较的总结,在涉及到比较方面,有元素的比较与对象的比较,下边博主来带领大家一起了解这些比较方式。
109 0