0 os模块:一个与操作系统有关的模块
这个模块内容很多,切忌死记硬背,需要使用的时候查询即可
1 sys模块:一个与python解释器有关的模块
使用同上
2 序列化模块
序列化:将其他数据类型转化成字符串类型(一般用于写文件和网络传输中)
反序列化:将字符串类型转化成其他数据类型
序列化模块主要有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模块:这个模块目前不太成熟,了解即可
3 模块
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函数
4 包
包是一种通过使用‘.模块名’来组织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()
5 异常处理
try:
ret = int(input('number>>>>>'))
print(ret*'*')
except ValueError:
print('你的输入有误,请输入一个数字')
except Exception:
print('抗压吧务团队1')
else:
print('---------')
finally:
print('nmsl')
当程序执行遇到错误时,后面的程序就不会执行
#使用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))
6 面向对象三大特性之继承
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有什么区别????
7 接口类和抽象类
接口类:
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(接口)来实现
7 面向对象三大特性之多态
多态指的是一类事物有多种形态
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()等函数。
8 面向对象三大特性之封装
class Person:
__key = 123 # 私有的静态属性
def __init__(self, name, password):
self.name = name
self.__password = password # 私有属性
def __get_password(self):
return self.__password
def login(self):
self.__get_password() # 私有方法
alex = Person('水月雨', 'blessing2')
print(alex.name)
print(alex._Person__password)
加上双__就会变成私有的,在类外部不能调用
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)想保护这个属性,不被子类继承
在类中修改私有属性:
class People:
def __init__(self, name):
self.__name = name
@property
def name(self):
return self.__name + 'sb'
@name.setter
def name(self, newname):
self.__name = newname
tiger = People('泰哥')
print(tiger.name)
tiger.name = '全班'
print(tiger.name)
在类中删除私有属性:
class People:
def __init__(self, name):
self.__name = name
@property
def name(self):
return self.__name
@name.deleter
def name(self):
print('我爱你')
del self.__name
tiger = People('泰哥')
print(tiger.name)
del tiger.name
print(tiger.name)
9 类方法
class Goods:
__discount = 0.8
def __init__(self, name, price):
self.name = name
self.__price = price
@property
def price(self):
return self.__price * Goods.__discount
@classmethod # 把一个方法变成一个类的方法,这个方法就可以直接被类调用, 不需要任何依托
def change_discount(cls, newdiscount):
cls.__discount = newdiscount
apple = Goods('苹果', 5)
print(apple.price)
Goods.change_discount(0.5)
print(apple.price)
10 静态方法
如果一个函数既和类没有关系,也和对象没有关系,就用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 代表这个类
静态方法没有默认参数, 就和普通函数一样