美文网首页
12-多态&文件操作

12-多态&文件操作

作者: 郑元吉 | 来源:发表于2018-12-08 13:56 被阅读3次

一、多态

1.概念

一种事物的多种体现形式,函数的重写其实就是多态的一种体现

在Python中,多态指的是父类的引用指向子类的对象

代码演示:

#父类
class Animal(object):
    pass

#子类
class Dog(Animal):
    pass

class Cat(Animal):
    pass

#定义变量
a = []   #a是list类型
b = Animal()  #b是Animal类型
c = Cat()  #c是Cat类型

#isinstance():判断一个对象是否属于某种类型【系统还是自定义的类型】
print(isinstance(a,list))
print(isinstance(b,Animal))
print(isinstance(c,Cat))

print(isinstance(c,Animal))  #True

print(isinstance(b,Dog))   #False

#结论:子类对象可以是父类类型,但是,父类的对象不能是子类类型

2.使用

案例:人可以喂猫,喂狗

思路:

a.定义动物类【父类】

b.定义子类,继承自动物类

c.定义人类

d.使用多态,优化

代码演示:

duoTaiDemo.py文件

from duotai.person import Person
from duotai.cat import Cat
from duotai.dog import Dog

#1.创建一个Person的对象
p = Person()

#2.创建一个Cat的对象
c = Cat("小白")

#3.人执行自己的行为
p.feedAnimal(c)

d = Dog("旺财")
p.feedAnimal(d)

person.py文件

class Person(object):
    """
    def feedCat(self,cat):
        print("喂猫:",cat.name)
        cat.eat()
    def feedDog(self,dog):
        print("喂猫:",dog.name)
        dog.eat()
    """
    #多态
    #ani被当做父类的引用 ,当传参的时候,实参是一个子类对象的时候,则体现出了 多态的应用
    def feedAnimal(self,ani):   #ani = c   c = Cat("")
        print("喂动物:", ani.name)
        ani.eat()

animal.py文件

class Animal(object):
    def __init__(self,name):
        self.name = name

    def eat(self):
        print("eating")

cat.py文件

from duotai.animal import Animal

class Cat(Animal):
    def __init__(self,name):
        super(Cat,self).__init__(name)

dog.py文件

from duotai.animal import Animal

class Dog(Animal):
    def __init__(self,name):
        super(Dog,self).__init__(name)

总结:

​ 简化代码,提高代码的可读性,可维护性

二、获取对象信息

type() isinstance() dir()

代码演示:

#1.type() :判断一个对象所属的类型
num = 10
print(type(num))
print(type("hello"))

class Check(object):
    pass
c = Check()
print(type(c))

#使用==判断type返回的结果
print(type(12) == type(57))  #True
print(type(12) == type("57"))  #False

#使用type返回的结果和数据类型直接判断
print(type(12) == int)

#2.isinstance()  :判断一个对象是否属于某种指定的数据类型
#自定义的类中
class Dog(object):
    pass

d = Dog()
print(isinstance(d,Dog))
print(isinstance([1,2,4],list))

#特殊用法:可以判断一个对象是否属于多种数据类型中的某一种
print(isinstance([1,2,4],(tuple,list)))

#3.dir()  :列出指定对象中所包含的所有的内容【成员变量,成员方法】
dict = {}
print(dir(dict))

print(dir("abc"))

print(dir(d))

三、类中特殊的属性和方法

1.实例属性和类属性

1.1实例属性和类属性的区别

a.定义的位置不同,类属性时直接定义在类中,实例属性定义在构造函数中

b.访问的方式不同,类属性使用类名直接访问,实例属性使用对象访问

c.在内存中出现的时机不同,类属性随着类的出现而出现,实例属性随着对象的出现而出现

d.优先级不同,实例属性的优先级高于类属性

代码演示:

class Person(object):
    #1.定义位置
    #类属性:直接定义在类中
    name = "abc"
    age = 0

    def __init__(self,name):
        #实例属性:定义在构造函数中
        self.name = name


#2.访问方式
print(Person.name)  #类属性:类名.属性 或者 对象.属性

p = Person("hello")
print(p.name)   #实例属性:对象.属性

#3.优先级不同:实例属性的优先级高于类属性
print(p.name)   #hello

#4.不同对象的类属性在内存中是不是同一块空间?----->不是
p1 = Person("小白")
p2 = Person("小红")
print(p1.age)
print(p2.age)
p1.age = 33
print(p1.age)
print(p2.age)
print(id(p1.age))
print(id(p2.age))
"""
0
0
33
0
1420404832
1420403776
"""

#注意:尽量避免类属性和实例属性的重名

#删除属性【类属性,实例属性】
del p1.age
1.2动态添加属性和方法

代码演示:

from  types import MethodType


class Person(object):
    #__slots__ = ("name","age")
    pass


#1.动态添加属性
per = Person()
str = "fjsgh"
per.name = str

#2.动态添加方法
def say(self):
    print("fhsj")
"""
per.test = say
per.test(per)
"""

#弊端:违背了普通函数定义
#解决方案:MethodType类,存在于types模块下

#类似于偏函数
#参数:函数名,对象
#作用:在现有函数的基础上生成了一个对象【新的函数】,赋值给成员变量,则认为给对象添加了一个成员方法
per.test = MethodType(say,per)
per.test()

2.类方法和静态方法

类方法:使用@classmethod装饰器修饰的方法,被称为类方法,可以通过类名调用,也可以通过对象调用,但是一般情况下使用类名调用

静态方法:使用@staticmethod装饰器修饰的方法,被称为静态方法,可以通过类名调用,也可以通过对象调用,但是一般情况下使用类名调用

代码演示:

class Test(object):
    #1.类属性
    age = 100

    def __init__(self,name):
        #2.实例属性
        self.name = name

    #3.成员方法,通过对象调用
    #必须有一个参数,这个参数一般情况下为self,self代表是当前对象
    def func(self):
        print("func")

    #4.类方法
    """
    a.必须有一个参数,这个参数一般情况下为cls,cls代表的是当前类
    b.类方法是属于整个类的,并不是属于某个具体的对象,在类方法中禁止出现self
    c.在类方法的内部,可以直接通过cls调用当前类中的属性和方法
    d.在类方法的内部,可以通过cls创建对象
    """
    @classmethod
    def test(cls):
        print("类方法")
        print(cls)   #<class 'methodDemo01.Test'>
        print(cls.age)

        #6
        #注意:cls完全当做当前类使用
        c = cls("hello")
        c.func()

    #7.静态方法
    @staticmethod
    def show():
        print("静态方法")

t = Test("hjfsh")
t.func()

#5,.调用类方法
Test.test()   #类名.类方法的名称()
t.test()       #对象.类方法的名称()

#7。调用静态方法
Test.show()
t.show()

总结:实例方法【成员方法】、类方法以及静态方法之间的区别

a.语法上

​ 实例方法:第一个参数一般为self,在调用的时候不需要传参,代表的是当前对象【实例】

​ 静态方法:没有特殊要求

​ 类方法:第一个参数必须为cls,代表的是当前类

b.在调用上

​ 实例方法:只能对象

​ 静态方法:对象 或者 类

​ 类方法:对象 或者 类

c.在继承上【相同点】

​ 实例方法、静态方法、类方法:当子类中出现和父类中重名的函数的时候,子类对象调用的是子类中的方法【重写】

代码演示:

class SuperClass(object):
    @staticmethod
    def show():
        print("父类中的静态方法")

    @classmethod
    def check(cls):
        print("父类中的类方法")

class SubClass(SuperClass):
    pass

s = SubClass()
s.show()
s.check()

注意:注意区分三种函数的书写形式,在使用,没有绝对的区分

3.类常用属性

__name__
  通过类名访问,获取类名字符串
  不能通过对象访问,否则报错
  
__dict__
  通过类名访问,获取指定类的信息【类方法,静态方法,成员方法】,返回的是一个字典
  通过对象访问,获取的该对象的信息【所有的属性和值】,,返回的是一个字典
  
__bases__
  通过类名访问,查看指定类的所有的父类【基类】

代码演示:

class Animal(object):
    def __init__(self,arg):
        super(Animal, self).__init__()
        self.arg = arg


class Tiger(Animal):
    age = 100
    height = 200

    def __init__(self,name):
        #super(Tiger, self).__init__(name)
        self.name = name

    def haha(self):
        print("haha")

    @classmethod
    def test(cls):
        print("cls")

    @staticmethod
    def show():
        print("show")


if __name__ == "__main__":

    #1.__name__
    print(Tiger.__name__)  #Tiger

    t = Tiger("")
    #print(t.__name__)  #AttributeError: 'Tiger' object has no attribute '__name__'

    #2.__dict__
    print(Tiger.__dict__)  #类属性,所有的方法
    print(t.__dict__)   #实例属性

    #3.__bases__,获取指定类的所有的父类,返回的是一个元组
    print(Tiger.__bases__)

四、运算符重载

运算符重载其实就是函数重写

代码演示:

print(1 + 1)
print("1" + "1")
#print("1" + 1)
#不同的数据类型进行加法运算得到的是不同的解释

#思考问题:两个对象相加?
class Person(object):
    def __init__(self,num):
        self.num = num

    def __str__(self):
        return "num=" + str(self.num)

    def __add__(self, other):
        #两个对象相加得到的结果仍然为一个对象
        return Person(self.num + other.num)   #Peson(30)


p1 = Person(10)
p2 = Person(20)

print(p1)  #10
print(p2)  #20

print(p1 + p2)  #30

#p1 + p2----->p1.__add__(p2),

五、文件读写

1.概念

在Python中,通过打开文件生成一个文件对象【文件描述符】操作磁盘上的文件,操作主要由文件读写

2.普通文件的读写

普通文件包含:txt文件,图片,视频,音频等

2.1读文件

操作步骤:

​ a.打开文件:open()

​ b.读取文件内容:read()

​ c.关闭文件:close()

说明:最后一定不要忘了文件关闭,避免系统资源的浪费【因为一个文件对象会占用系统资源】

代码演示:

#一、打开文件
"""
open(path,flag[,encoding,errors])
path:指定文件的路径【绝对路径和相对路径】
flag:打开文件的方式
    r:只读、
    rb:read binary,以二进制的方式打开,只读【图片,视频,音频等】
    r+:读写

    w:只能写入
    wb:以二进制的方式打开,只能写入【图片,视频,音频等】
    w+:读写

    a:append,如果一个文件不为空,当写入的时候不会覆盖掉原来的内容
encoding:编码格式:gbk,utf-8
errors:错误处理
"""
path = r"C:\Users\Administrator\Desktop\SZ-Python\Day15\笔记\致橡树.txt"
#调用open函数,得到了文件对象
f = open(path,"r",encoding="gbk")

"""
注意:
a.以r的方式打开文件时,encoding是不是必须出现
    如果文件格式为gbk,可以不加encoding="gbk"
    如果文件格式为utf-8,必须添加encoding="utf-8"
b。如果打开的文件是图片,音频或者视频等,打开方式采用rb,但是,此时,不能添加encoding="xxx"
"""

#二、读取文件内容
#1.读取全部内容   ***********
#str = f.read()
#print(str)

#2.读取指定的字符数
#注意:如果每一行的结尾有个"\n",也被识别成字符
"""
str1 = f.read(2)
print(str1)
str1 = f.read(2)
print(str1)
str1 = f.read(2)
print(str1)


#3.读取整行,不管该行有多少个字符    *********
str2 = f.readline()
print(str2)
str2 = f.readline()
print(str2)
"""

#4.读取一行中的指定的字符
#str3 = f.readline(3)
#print(str3)

#5.读取全部的内容,返回的结果为一个列表,每一行数据为一个元素
#注意:如果指明参数,则表示读取指定个数的字符
str4 = f.readlines()
print(str4)

#三、关闭文件
f.close()

其他写法:

#1.读取文件的简写形式
#with open()  as 变量

#好处:可以自动关闭文件,避免忘记关闭文件导致的资源浪费
path = "致橡树.txt"
with open(path,"r",encoding="gbk") as f:
    result = f.read()
    print(result)

#2.
try:
    f1 = open(path,"r",encoding="gbk")
    print(f1.read())
except FileNotFoundError as e:
    print("文件路径错误",e)
except LookupError as e:
    print("未知的编码格式",e)
except UnicodeDecodeError as e:
    print("读取文件解码错误",e)
finally:
    if f1:
        f1.close()

读取图片等二进制文件:

#1.
f = open("dog.jpg","rb")

result = f.read()
print(result)

f.close()

#2
with open("dog.jpg","rb") as f1:
    f1.read()

#注意:读取的是二进制文件,读取到的内容为\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x01\x00H\x00H\x00\x00\xff\xdb\x0
2.2写文件

操作步骤:

​ a.打开文件:open()

​ b.写入数据:write()

​ c.刷新管道【内部缓冲区】:flush()

​ d.关闭文件:close()

代码演示:

path = "file1.txt"

#1.打开文件
#注意:写入文件的时候,文件可以不存在,当open的时候会自动创建文件
#读取文件的时候,文件必须先存在,才能open
f = open(path,"w",encoding="utf-8")

#2.写入数据
#注意:将数据写入文件的时候,默认是没有换行的,如果向换行,则可以手动添加\n
f.write("Python1805高薪就业,走上人生巅峰")

#3.刷新数据缓冲区
#作用:加速数据的流动,保证缓冲区的流畅
f.flush()

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

#简写形式
with open(path,"w",encoding="utf-8") as f1:
    f1.write("hello")
    f.flush()

3.编码和解码

编码:encode,字符串类型转换为字节类型

解码:decode,字节类型转换为字符串类型

注意:编码和解码的格式必须保持一致

代码演示:

path = "file2.txt"

#编码:字符串----》字节
with open(path,"wb") as f1:
    str = "today is a good day 今天是个好天气"
    f1.write(str.encode("utf-8"))

#解码:字节----->字符串
with open(path,"rb") as f2:
    data = f2.read()
    print(data)
    print(type(data))

    newData = data.decode("utf-8")
    print(newData)
    print(type(newData))

4.csv文件的读写

csv:逗号分隔值【Comma Separated Values】

一种文件格式,.csv,本质是一个纯文本文件,可以作为不同程序之间数据交互的格式

打开方式:记事本,excel

4.1读文件

代码演示:

#C:\Users\Administrator\Desktop\SZ-Python\Day15\笔记\text.csv
import  csv


#方式一:三部曲
def readCsv1(path):
    #1.打开文件
    csvFile = open(path,"r")

    #2.将文件对象封装成可迭代对象
    reader= csv.reader(csvFile)

    #3.读取文件内容
    #遍历出来的结果为列表
    for item in reader:
        print(item)

    #4.关闭文件
    csvFile.close()

readCsv1(r"C:\Users\Administrator\Desktop\SZ-Python\Day15\笔记\text.csv")

#方式二:简写
def readCsv2(path):
    with open(path,"r") as f:
        reader = csv.reader(f)
        for item in reader:
            print(item)

readCsv2(r"C:\Users\Administrator\Desktop\SZ-Python\Day15\笔记\text.csv")
4.2写文件

代码演示:

import  csv

#1.从列表写入数据
def writeCsv1(path):
    infoList = [['username', 'password', 'age', 'address'],['zhangsan', 'abc123', '17', 'china'],['lisi', 'aaabbb', '10', 'england']]

    #1.打开文件
    #注意:如果不设置newline,每一行会自动有一个空行
    csvFile = open(path,"w",newline="")

    #2.将文件对象封装成一个可迭代对象
    writer = csv.writer(csvFile)

    #3.写入数据
    for i in range(len(infoList)):
        writer.writerow(infoList[i])

    #4.关闭文件
    csvFile.close()

writeCsv1("file3.csv")

#2.从字典写入文件
def writeCsv2(path):
    dic = {"张三":123,"李四":456,"王麻子":789}
    csvFile = open(path, "w", newline="")
    writer = csv.writer(csvFile)

    for key in dic:
        writer.writerow([key,dic[key]])

    csvFile.close()

#3.简写形式
def writeCsv3(path):
    infoList = [['username', 'password', 'age', 'address'], ['zhangsan', 'abc123', '17', 'china'],
                ['lisi', 'aaabbb', '10', 'england']]
    with open(path, "w", newline="") as f:
        writer = csv.writer(f)

        for rowData in infoList:
            writer.writerow(rowData)

相关文章

网友评论

      本文标题:12-多态&文件操作

      本文链接:https://www.haomeiwen.com/subject/bldqhqtx.html