这个模块内容很多,切忌死记硬背,需要使用的时候查询即可
使用同上
序列化:将其他数据类型转化成字符串类型(一般用于写文件和网络传输中) 反序列化:将字符串类型转化成其他数据类型 序列化模块主要有json模块,pickle模块,shelve模块,接下来将一一讲解: 0)json模块:通用的序列化格式,只有一小部分数据类型可以通过json模块转换成字符串类型,json模块一般有4种方法:dumps();loads();dump();load() dumps()和loads()的使用: import json
dic = {'a': '100', 'b': '20'} lis = json.dumps(dic) print(lis, type(lis)) dic_ = json.loads(lis) print(dic_, type(dic_))dump()和load()的使用:(对文件句柄进行操作) json.dump()用于将dict类型的数据转成str,并写入到json文件中。 json.load()用于从json文件中读取数据。
import json dic = {'a': '100', 'b': '20'} with open('fff.txt', 'w', encoding='utf-8') as f: json.dump(dic, f)#如果字典中有中文,稍微有所变化
import json dic = {'a': '中国', 'b': '20'} with open('fff.txt', 'w', encoding='utf-8') as f: json.dump(dic, f, ensure_ascii=False)注意:dump和load一次只能处理一个字典,如果需要多次,必须绕过dump和load
import json l = [{'k1': '111'}, {'k2': '111'}] f = open('ttt.txt', 'w') for i in l: str_dic = json.dumps(i) f.write(str_dic + '\n') f.close() f = open('ttt.txt') new_l = [] for line in f: dic = json.loads(line) new_l.append(dic) f.close() pickle模块:所有的数据类型都能通过pickle模块转化成字符串数据类型,但是pickle序列化后的内容只有python才能理解,且部分反序列化依赖python代码(这句话目前不能理解) pickle模块和json一样,同样提供了dumps();loads();dump();load()方法,但是在使用过程中稍微有所区别 在dump()的时候必须以‘wb’的方式打开 ,在load()的时候必须以‘rb’的方式打开 import pickle dic = {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'} str_dic = pickle.dumps(dic) print(str_dic, type(str_dic)) #一串二进制内容 dic2 = pickle.loads(str_dic) print(dic2, type(dic2))一个关于dump和load的使用案例:
import pickle import time struct_time = time.localtime(1000000000) print(struct_time) f = open('pickle_file', 'wb') pickle.dump(struct_time, f) f.close() f = open('pickle_file', 'rb') struct_time2 = pickle.load(f) print(struct_time2.tm_year)2) shelve模块:这个模块目前不太成熟,了解即可
0)模块的导入 当导入一个模块时,先从sys.modules中看是否被导入,如果没有被导入,就从sys.path路径寻找模块,再创建这个模块的命名空间,把文件中的名字全部放到命名空间上去,这也就是模块不会被重复导入的原因 1)模块的别名 当几个模块执行的功能相同时,可以将这几个模块起同一个别名,这样使用起来就会很方便 2)模块的顺序 导入模块时,要将模块写在程序的最开始,且最好使用 import a import b import c 不推荐使用 import a, b, c 顺序一般为:
内置模块
扩展模块
自己写的模块 3)从某个模块中调用某个方法 from a import b 比如:from time import sleep
import 模块名 模块名.方法名 和本文件中的变量名完全不冲突
import 模块名 as 重命名的模块名 #提高代码的兼容性
from 模块名 import 方法名 #直接使用方法名就可以完成操作 #如果本文件中有相同的变量名会发生冲突 #from 模块名 import 变量名 as 重命名的变量名
from 模块名 import 方法名1,方法名2 from 模块名 import * #将模块中的所有方法名都放到内存中 #如果本文件中有相同的变量名会发生冲突
#import * 和__all__是一对 如果没有__all__, 模块里面的所有方法都被导入 如果有__all__, __all__里有的方法会被导入
在模块中,有一个变量__name__ 当我们直接执行这个模块的时候,name == ‘main’ 当我们在其他模块中引用这个模块的时候,name == ‘模块名’
与上文无关,但是关于__name__ == 'main’有点想要补充的 这句话是python程序的入口,相当于c语言中的main函数
包是一种通过使用‘.模块名’来组织python模块名称空间的方式。 一个完整的python程序通常不只包含一个python文件,一个完整的python程序如下所示:
conf里面放配置文件,让用户可以看懂的 core 核心代码 db 数据 lib 自己写的模块 log 记录的过程 当调用python包时,会自动执行该包下的__init__文件
os.makedirs('glance/api') os.makedirs('glance/cmd') os.makedirs('glance/db') l = [] l.append(open('glance/__init__.py','w')) l.append(open('glance/api/__init__.py','w')) l.append(open('glance/api/policy.py','w')) l.append(open('glance/api/versions.py','w')) l.append(open('glance/cmd/__init__.py','w')) l.append(open('glance/cmd/manage.py','w')) l.append(open('glance/db/models.py','w')) l.append(open('glance/db/__init__.py','w')) map(lambda f:f.close() ,l) #文件内容 #policy.py def get(): print('from policy.py') #versions.py def create_resource(conf): print('from version.py: ',conf) #manage.py def main(): print('from manage.py') #models.py def register_models(engine): print('from models.py: ',engine)执行get文件的两种方法: import glance.api.policy glance.api.policy.get() from glance.api.policy import get get() 如果想调用import glance 然后使用policy versions等功能怎么办呢? 在glance的__init__文件里导入如下模块,利用了自动执行__init__这个功能 from glance import api from glance import cmd from glance import db 分别在api,cmd,db的__init__文件里导入如下模块 from glance.api import policy from glance.api import versions ———————————————— from glance.cmd import manage
———————————————— from glance.db import models
经过尝试 import glance glance.api.policy.get() 例如:我们在glance/api/version.py中想要导入glance/cmd/manage.py
#在glance/api/version.py #绝对导入 from glance.cmd import manage manage.main() #相对导入 from ..cmd import manage manage.main()当程序执行遇到错误时,后面的程序就不会执行 #使用try和except就能处理异常 #try是我们需要处理的代码 #except后跟一个错误类型,当代码发生错误且类型相同时,就会执行except的内容 #except 支持多分支(进行一个分支后就不会进入其他分支,在上述程序中,如果发生ValueError,就不会进入Exception) 有没有一个能处理所有错误的类型:Exception #有了万能的处理机制仍然需要将能预测到的错误单独讨论 #单独处理的内容必须放在万能异常前面 #else:没有异常时会执行else的代码 #finally;不管代码是否异常,都会执行 #finally和return相遇的时候,仍然会执行 #做一些收尾工作
一个简单的程序:
c = [] while True: a = input('请输入数字(退出请输入b):') if a == 'b': break else: try: c.append(int(a)) except Exception as e: print('你存在如下错误', e) print(sum(c)) print(len(c)) print(sum(c)/len(c))0)一个类可以被多个类继承 1)一个类可以继承多个负类(多继承),只在python中存在 2)在python3中,所有的类都有其父类,如果没有继承,默认它的父类就是object(顶级类)
class A: pass class B(A): pass print(A.__base__) print(B.__base__).__base__方法可以查询父类
如何更形象地理解继承?
class Animal: def __init__(self, name, hp, aggr): self.name = name self.hp = hp self.aggr = aggr class Person(Animal): def __init__(self, name, hp, aggr, sex): Animal.__init__(self, name, hp, aggr) self.sex = sex # 派生属性 self.money = 0 # 派生属性 def attack(self, dog): dog.hp -= self.aggr class Dog(Animal): def __init__(self, name, hp, aggr, kind): Animal.__init__(self, name, hp, aggr) self.kind = kind # 派生属性 def bite(self, person): person.hp -= self.aggr jin = Dog('泰迪', 500, 200, '看家') alex = Person('陈叔', 999, 111, '男') print(jin.kind) print(alex.sex)小结: 当在自己的类中找不到__init__时,就会到父类里面找__init__ 子类中有而父类中没有的属性,叫做派生属性 子类中有而父类中没有的方法, 叫做派生方法 当调用时,先再子类里面找,找不到再在父类里面找 既想实现新的功能,又想调用父类的功能,就需要在子类中调用父类的功能(上述的代码就用了这点,建议好好研究)
一个关于super()的实例:
class A: def hahaha(self): print('A') class B(A): def hahaha(self): super().hahaha() print('B') a = A() b = B() b.hahaha()子类调用父类的方法时,可以使用super() 这种方法可以少传入一个self参数
class Animal: def __init__(self, name, hp, aggr): self.name = name self.hp = hp self.aggr = aggr class Person(Animal): def __init__(self, name, hp, aggr, sex): super().__init__(name, hp, aggr) self.sex = sex # 派生属性 self.money = 0 # 派生属性 def attack(self, dog): dog.hp -= self.aggr class Dog(Animal): def __init__(self, name, hp, aggr, kind): super().__init__(name, hp, aggr) self.kind = kind # 派生属性 def bite(self, person): person.hp -= self.aggr jin = Dog('泰迪', 500, 200, '看家') alex = Person('陈叔', 999, 111, '男') print(jin.kind) print(alex.sex)super()一般都是在类内部使用,如果super要在类外部使用该如何做呢? Super在类外部使用的时候, super(类名,对象名).(方法)使用
组合是 “有”的关系 继承是 “是”的关系 多继承(找大爹) 钻石继承
class A: def func(self): print('A') class B(A): def func(self): print('B') class C(A): def func(self): print('C') class D(B, C): def func(self): print('D') d = D() print(D.mro())mro()方法可以将继承顺序列出来 Super的本质不是直接找父类,而是根据调用者的节点位置广度优先顺序来判断的
class A: def func(self): print('A') class B(A): def func(self): super().func() print('B') class C(A): def func(self): super().func() print('C') class D(B, C): def func(self): super().func() print('D') d = D() d.func()如何在终端上运行点py文件呢? 目前还存在一个疑问:shell和terminal有什么区别????
接口类:
from abc import abstractmethod, ABCMeta class Payment(metaclass=ABCMeta): @abstractmethod def pay(self, money): pass class Wechat(Payment): def pay(self, money): print("已经使用微信支付了%s元" % money) class Ali(Payment): def pay(self, money): print("已经使用阿里支付了%s元" % money) class Apple(Payment): def pay1(self, money): print("已经使用苹果支付了%s元" % money) def pay(pay_obj, money): # 接口 pay_obj.pay(money) wechat = Wechat() ali = Ali() apple = Apple()上述写法是一种规范:当某个类中没有pay方法时,就会在实例化的时候报错 接口类:支持多继承,但是接口类中的方法都不能实现(不能理解) 抽象类:不支持多继承,但是抽象类中的方法有一些可以实现(不能理解) abc类是一个抽象类 接口类也存在多继承 接口类和抽象类都不能实例化 java中没有多继承,但是为了实现多继承,可以用interface(接口)来实现
多态指的是一类事物有多种形态
from abc import abstractmethod, ABCMeta class Animal(metaclass=ABCMeta): #同一类事物:动物 @abstractmethod def talk(self): pass class People(Animal): #动物的形态之一:人 def talk(self): print('say hello') class Dog(Animal): #动物的形态之二:狗 def talk(self): print('say wangwang') class Pig(Animal): #动物的形态之三:猪 def talk(self): print('say aoao') peo = People() dog = Dog() pig = Pig() #peo、dog、pig都是动物,只要是动物肯定有talk方法 #于是我们可以不用考虑它们三者的具体是什么类型,而直接使用 peo.talk() dog.talk() pig.talk() #更进一步,我们可以定义一个统一的接口来使用 def func(obj): obj.talk() func(pig)Python崇尚鸭子类型,即‘如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子。 python程序员通常根据这种行为来编写程序。例如,如果想编写现有对象的自定义版本,可以继承该对象 也可以创建一个外观和行为像,但与它无任何关系的全新对象,后者通常用于保存程序组件的松耦合度(类之间的相关程度)。
关于多态的深入理解:
class Animal(object): def run(self): print('Animal is running...') class Dog(Animal): def run(self): print('Dog is running1...') def eat(self): print('Eating meat...') class Cat(Animal): def run(self): print('Cat is running2...') def eat(self): print('Eating meat...') dog = Dog() dog.run() cat = Cat() cat.run() a = list() # a是list类型 b = Animal() # b是Animal类型 c = Dog() # c是Dog类型 def run_twice(animal): animal.run() animal.run() run_twice(cat) class Tortoise(Animal): def run(self): print('Tortoise is running slowly...') run_twice(Tortoise())你会发现,新增一个Animal的子类,不必对run_twice()做任何修改,实际上,任何依赖Animal作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态。 多态的好处就是,当我们需要传入Dog、Cat、Tortoise……时,我们只需要接收Animal类型就可以了,因为Dog、Cat、Tortoise……都是Animal类型,然后,按照Animal类型进行操作即可。由于Animal类型有run()方法,因此,传入的任意类型,只要是Animal类或者子类,就会自动调用实际类型的run()方法,这就是多态的意思: 对于一个变量,我们只需要知道它是Animal类型,无需确切地知道它的子类型,就可以放心地调用run()方法,而具体调用的run()方法是作用在Animal、Dog、Cat还是Tortoise对象上,由运行时该对象的确切类型决定,这就是多态真正的威力:调用方只管调用,不管细节,而当我们新增一种Animal的子类时,只要确保run()方法编写正确,不用管原来的代码是如何调用的。这就是著名的“开闭”原则: 对扩展开放:允许新增Animal子类; 对修改封闭:不需要修改依赖Animal类型的run_twice()等函数。
加上双__就会变成私有的,在类外部不能调用
class Room: def __init__(self, name, length, width): self.__name = name self.__length = length self.__width = width def area(self): return self.__length * self.__width def get_name(self): return self.__name def set_name(self, newname): if type(newname) is str and newname.isdigit() == False: self.__name = newname jin = Room('陈叔', 10, 7) print(jin.area()) jin.set_name('lux') print(jin.get_name())经过测试:父类中的私有属性(私有方法)在子类中也不能调用 所以能用到私有(封装)的场景有: 0)隐藏一个属性,不想在外部被调用 1)想要保护一个属性,不想让这个属性被随意改变 2)想保护这个属性,不被子类继承
如果一个函数既和类没有关系,也和对象没有关系,就用staticmethod伪装成静态方法
class Login: def __init__(self, name, password): self.name = name self.pwd = password print('这把点了') def login(self): pass @staticmethod def get_info(): user = input('请输入用户名:') pwd = input('请输入密码:') Login(user, pwd) Login.get_info()关于类方法和静态方法的总结: 类方法和静态方法,都是通过类调用的 对象也可以调用类方法和静态方法,不过推荐通过类来调用 类方法有一个默认参数 cls 代表这个类 静态方法没有默认参数, 就和普通函数一样
