Python基础学习(四)

2021/05/05 Python 共 19286 字,约 56 分钟

模块

在前面我们脚本是用Python解释器来编程,如果你从Python解释器退出再进入,那么你定义的所有的方法和变量就都消失了。

为此Python提供了一个办法,把这些定义存放在文件中,为一些脚本或者交互式的解释器实例使用,这个文件被称为模块(Module)。

模块是一个包含所有你定义的函数和变量的文件,其后缀名是py。模块可以被别的程序引入,以使用该模块中的函数等功能。这也是使用Python标准库的方法。

什么是模块

  1. 容器->数据的封装
  2. 函数->语句的封装
  3. 类->方法和属性的封装
  4. 模块->程序文件
# hello.py
def hi():
    print('Hi everyone, I love lsgogroup!')

命名空间

命名空间因为对象的不同,也有所区别,可以分为如下几种:

  1. 内置命名空间(Built-in Namespaces):Python运行起来,它们就存在了。内置函数的命名空间都属于内置命名空间,所以,我们在任何程序中直接运行它们,比如id(),不需要做什么操作,拿过来就直接使用了。
  2. 全局命名空间(Module:Global Namespace):每个模块创建它自己所拥有的全局命名空间,不同模块的全局命名空间彼此独立,不同模块中相同名称的命名空间,也会因为模块的不同而不相互干扰。
  3. 本地命名空间(Function&Class: Local Namespaces):模块中有函数或者类,每个函数或者类所定义的命名空间就是本地命名空间。如果函数返回了结果或者抛出异常,则本地命名空间也结束了。

上述三种命名空间的关系:

image-20210505.png

程序在查询上述三种命名空间的时候,就按照从里到外的顺序,即:Local Namespaces–>Global Namespaces–>Built-in Namespaces

import hello

hello.hi()
hi()   # NameError: name 'hi' is not defined!

导入模块

# TemperatureConversion.py
def c2f(cel):
    fah = ce1 * 1.8 + 32
    return fah

def f2c(fah):
    cel = (fah-32)/1.8
    return cel

第一种:import 模块名

import TemperatureConversion

print('32摄氏度 = %.2f华氏度'% TemperatureConversion.c2f(32))
print('99华氏度 = %.2f摄氏度'% TemperatureConversion.f2c(99))

第二种:from 模块名 import 变量名

from TemperatureConversion import c2f,f2c

print('32摄氏度 = %.2f华氏度'%c2f(32))
print('99华氏度 = %.2f摄氏度'%f2c(99))

下面的方式不推荐

from TemperatureConversion import *

print('32摄氏度 = %.2f华氏度'%c2f(32))
print('99华氏度 = %.2f摄氏度'%f2c(99))

第三种:import 模块名 as 新名字

import TemperatureConversion as tc

print('32摄氏度 = %.2f华氏度'%tc.c2f(32))
print('99华氏度 = %.2f摄氏度'%tc.f2c(99))

if __name__ == '__main__'

对于很多编程语言来说,程序都必须要有一个入口,而Python则不同,它属于脚本语言,不像编译型语言那样先将程序编译成二进制再运行,而是动态的逐行解释运行。也就是从脚本第一行开始运行,没有统一的入口。

假设我们有一个const.py文件,内容如下:

PI = 3.14

def main():
    print("PI:",PI)
    
main()

现在,我们写一个用于计算圆面积的area.py文件,area.py文件需要用到const.py文件中的PI变量。从const.py中,我们把PI变量导入area.py:

from const import PI

def calc_round_area(radius):
    return PI*(radius**2)

def main():
    print('round area:',calc_round_area(2))
    
main()

我们看到const.py中的main函数也被运行了,实际上我们不希望它被运行,因为const.py提供的main函数只是为了测试常量定义。这是if __name__ == '__main__'派上了用场,我们把const.py改一下,添加if __name__ == '__main__':

PI = 3.14

def main():
    print("PI:",PI)
    
if __name__ == '__main__':
    main()

运行const.py,输出如下:

PI: 3.14

运行area.py,输出如下:

round area: 12.56

__name__:是内置变量,可用于表示当前模块的名字。

import const

print(__name__)  # __main__
print(const.__name__)  # const

由此我们可知:如果一个.py文件(模块)被直接运行时,其__name__值为__main__,即模块名为__main__

所以,if __name__=='__main__'的意思是;当.py文件被直接运行时,if __name__=='__main__'之下的代码块将被运行;当.py文件以模块形式被导入时,if __name__ == '__main__'之下的代码块不被运行。

搜索路径

当解释器遇到import语句,如果模块在当前的搜索路径就会被导入。

import sys

print(sys.path)
['/Users/alexandreaswiftie/Documents', '/Users/alexandreaswiftie/opt/anaconda3/lib/python38.zip', '/Users/alexandreaswiftie/opt/anaconda3/lib/python3.8', '/Users/alexandreaswiftie/opt/anaconda3/lib/python3.8/lib-dynload', '', '/Users/alexandreaswiftie/.local/lib/python3.8/site-packages', '/Users/alexandreaswiftie/opt/anaconda3/lib/python3.8/site-packages', '/Users/alexandreaswiftie/opt/anaconda3/lib/python3.8/site-packages/aeosa', '/Users/alexandreaswiftie/opt/anaconda3/lib/python3.8/site-packages/IPython/extensions', '/Users/alexandreaswiftie/.ipython']

我们使用import语句的时候,Python解释器是怎样找到对应的文件的呢?

这就涉及到Python的搜索路径,搜索路径是由一系列目录名组成的,Python解释器就依次从这些目录中去寻找所引入的模块。

这看起来很像环境变量,事实上,也可以通过定义环境变量的方式来确定搜索路径。

搜索路径是在Python编译或安装的时候确定的,安装新的库应该也会修改。搜索路径被存储在sys模块中的path变量中。

包(package)

包是一种管理Python模块命名空间的形式,采用”点模块名称”。

创建包分为三个步骤:

  1. 创建一个文件夹,用于存放相关的模块,文件夹的名字即包的名字。
  2. 在文件夹中创建一个__init__.py的模块文件,内容可以为空。
  3. 将相关的模块放入文件夹中。

不妨假设你想设计一套统一处理声音文件和数据的模块(或者称之为一个“包”)。

现存很多种不同的音频文件格式(基本是都是通过后缀名区分的,例如:.wav, .aiff, .au),所以你需要有一组不断增加的模块,用来在不同的格式之间转换。

并且针对这些音频数据,还有很多不同的操作(比如混音,添加回声,增加均衡器功能,创建人造立体声效果),所以你还需要一组怎么也写不完的模块来处理这些操作。

这里给出了一种可能的包结构(在分层的文件系统中):

sound/                       顶层包
    __init__.py              初始化sound包
    formats/                 文件格式转换子包
        __init__.py
        wavread.py
        wavwrite.py
        aiffread.py
        aiffwrite.py
        auread.py
        auwrite.py
        ...
    effects/                 声音效果子包
        __init__.py
        echo.py
        surround.py
        reverse.py
        ...
    filters/                 filters子包
        __init__.py
        equalizer.py
        vocoder.py
        karaoke.py
        ...

在导入一个包的时候,Python会根据sys.path中的目录来寻找这个包中包含的子目录。

目录只有包含一个叫做__init__.py的文件才会被认作是一个包,最简单的情况,放一个空的__init__.py就可以了。

import sound.effcts.echo

这将会导入子模块sound.effects.echo。它必须使用全名去访问:

sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)

还有一种导入子模块的方法是:

from sound.effects import echo

这同样会导入子模块:echo,并且它不需要哪些冗长的前缀,所以它可以这样使用:

echo.echofilter(input, output, delay=0.7, atten=4)

还有一种变化就是直接导入一个函数或者变量:

from sound.effects.echo import echofilter

同样的,这种方法会导入子模块:echo,并且可以直接使用它的echofilter()函数:

echofilter(input, output, delay=0.7, atten=4)

注意当使用from package import item这种形式的时候,对应的item既可以是包里面的子模块(子包),或者包里面定义的其他名称,比如函数,类或者变量。

设想一下,如果我们使用from sound.effects import *会发生什么?

Python会进入文件系统,找到这个包里面所有的子模块,一个一个的把它们都导入进来。

导入语句遵循如下规则:如果包定义文件__init__.py存在一个叫做__all__的列表变量,那么在使用from package import *的时候就把这个列表中的所有名字作为包内容导入。

这里有一个例子,在sounds/effects/__init__.py中包含如下代码:

__all__ = ['echo','surround','reverse']

这表示当你使用from sound.effects import *这种用法时,你只会导入包里面这三个模块。

如果__all__真的没有定义,那么使用from sound.effects import *这种语法的时候,就不会导入包sound.effects里的任何子模块。它只是把包sound.effects和它里面定义的所有内容导入进来(可能运行__init__.py里定义的初始化代码).

这会把__init__.py里面定义的所有名字导入进来。并且它不会破坏掉我们在这句话之前导入的所有明确指定的模块。

import sound.effects.echo
import sound.effects.surround
from sound.effects import *

这个例子中,在执行from...import之前,包sound.effects中的echosurround模块都别导入到当前的命名空间中了。

通常我们并不主张使用*这种方法来导入模块,因为这种方法经常会导致代码的可读性降低。

datetime模块

datetime是Python中处理日期的标准模块,它提供了4种对日期和时间进行处理的类:datetime、date、timetimedelta

datetime类

class datetime(date):
    def __init__(self,year,month,day,hour,minute,second,microsecond,tzinfo):
        pass
    def now(cls,tz=None):
        pass
    def timestamp(self):
        pass
    def fromtimestamp(cls,t,tz=None):
        pass
    def date(self):
        pass
    def time(self):
        pass
    def year(self):
        pass
    def month(self):
        pass
    def day(self):
        pass
    def hour(self):
        pass
    def minute(self):
        pass
    def second(self):
        pass
    def isoweekday(self):
        pass
    def strftime(self,fmt):
        pass
    def combine(cls,date,time,tzinfo=True):
        pass
  1. datetime.now(tz=None)获取当前的日期时间,输出顺序为:年、月、日、时、分、秒、微秒。
  2. datetime.timestamp()获取以1970年1月1日为起点记录的秒数。
  3. datetime.fromtimestamp(tz=None)使用unixtimestamp创建一个datetime。

【例子】如何创建一个datetime对象?

import datetime

dt = datetime.datetime(year=2021,month=4,day=27,hour=12,minute=29,second=57)
print(dt)
print(dt.timestamp())

dt = datetime.datetime.fromtimestamp(1593055439.0)
print(dt)
print(type(dt))

dt = datetime.datetime.now()
print(dt)
print(type(dt))
2021-04-27 12:29:57
1619497797.0
2020-06-25 11:23:59
<class 'datetime.datetime'>
2021-04-27 12:31:06.192661
<class 'datetime.datetime'>
  1. datetime.strftime(fmt)格式化datetime对象。
符号说明
%a本地简化星期名称(如星期一,返回Mon)
%A本地完整星期名称(如星期一,返回Monday)
%b本地简化的月份名称(如一月,返回Jan)
%B本地完整的月份名称(如一月,返回January)
%c本地相应的日期表示和时间表示
%d月内中的一天(0-31)
%H24小时制小时数(0-23)
%I12小时制小时数(01-12)
%j年内的一天(001-366)
%m月份(0-12)
%M分钟数(00-59)
%p本地A.M.或P.M.的等价符
%S秒(00-59)
%U一年中的星期数(00-53)星期天为星期的开始
%w星期(0-6),星期天为星期的开始
%W一年中的星期数(00-53)星期一为星期的开始
%x本地相应的日期表示
%X本地相应的时间表示
%y两位数的年份表示 (00-99)
%Y四位数的年份表示(0000-9999)
%Z当前时区的名称(如果是本地时间,返回空字符串)
%%%号本身

【例子】如何将datetime对象转换为任何格式的日期?

import datetime

dt = datetime.datetime(year=2020,month=6,day=25,hour=11,minute=51,second=49)
s = dt.strftime("'%Y/%m/%d %H:%M:%S'")
print(s)

s = dt.strftime('%d %B, %Y, %A')
print(s)
'2020/06/25 11:51:49'
25 June, 2020, Thursday

【练习】如何将给定日期转换为“mmm-dd,YYYY”的格式?

import datetime

d1 = datetime.date(2010,9,28)
s = d1.strftime('%m-%d, %Y')
print(s)
09-28, 2010
  1. datetime.date() return the date part.
  2. datetime.time() return the time part, with tzinfo None.
  3. datetime.year
  4. datetime.month
  5. datetime.day
  6. datetime.hour 小时
  7. datetime.minute 分钟
  8. datetime.second
  9. datetime.isoweekday 星期几

【例子】datetime对象包含很多与日期时间相关的实用功能

import datetime

dt = datetime.datetime(year=2020,month=6,day=25,hour=11,minute=51,second=49)
print(dt.date())
print(type(dt.date()))
print(dt.time())
print(type(dt.time()))
print(dt.year)
print(dt.month)
print(dt.day)
print(dt.hour)
print(dt.minute)
print(dt.second)
print(dt.isoweekday())
2020-06-25
<class 'datetime.date'>
11:51:49
<class 'datetime.time'>
2020
6
25
11
51
49
4

在处理含有字符串日期的数据集或表格时,我们需要一种自动解析字符串的方法,无论它是什么格式的,都可以将其转化为datetime对象。这时,就要使用到dateutil中的parser模块。

  1. parser.parse(timestr,parserinfo=None,**kwargs)

【例子】如何在Python中将字符串解析为datetime对象?

from dateutil import parser

s = '2020-06-25'
dt = parser.parse(s)
print(dt)
print(type(dt))

s = 'March 31, 2010, 10:51pm'
dt = parser.parse(s)
print(dt)
print(type(dt))
2020-06-25 00:00:00
<class 'datetime.datetime'>
2010-03-31 22:51:00
<class 'datetime.datetime'>

【练习】如何将字符串日期解析为datetime对象?

from dateutil import parser

s1 = "2010 Jan 1"
s2 = "31-1-2000"
s3 = 'October10, 1996, 10:40pm'

dt1 = parser.parse(s1)
dt2 = parser.parse(s2)
dt3 = parser.parse(s3)

print(dt1)
print(dt2)
print(dt3)
2010-01-01 00:00:00
2000-01-31 00:00:00
1996-10-10 22:40:00

【练习】计算以下列表中连续的天数。

import numpy as np
from dateutil import parser

dateString = ['Oct, 2, 1869','Oct, 10, 1869','Oct, 15, 1869','Oct, 20, 1869','Oct, 23, 1869']
dates = [parser.parse(i) for i in dateString]
td = np.diff(dates)
print(td)
d = [i.days for i in td]
print(d)
[datetime.timedelta(days=8) datetime.timedelta(days=5)
 datetime.timedelta(days=5) datetime.timedelta(days=3)]
[8, 5, 5, 3]

date类

class date:
    def __init__(self, year, month, day):
        pass
    def today(cls):
        pass
  1. date.today()获取当前日期信息。

【例子】如何在Python中获取当前日期和时间?

import datetime

d = datetime.date(2020,6,25)
print(d)
print(type(d))

d = datetime.date.today()
print(d)
print(type(d))
2020-06-25
<class 'datetime.date'>
2021-04-28
<class 'datetime.date'>

【练习】如何统计两个日期之间有多少个星期六?

import datetime

d1 = datetime.date(1869,1,2)
d2 = datetime.date(1869,10,2)
dt = (d2-d1).days
print(dt)
print(d1.isoweekday())
print(dt//7+1)
273
6
40

time类

class time:
    def __init__(self, hour, minute, second, microsecond, tzinfo):
        pass

【例子】如何使用datetime.time()类?

import datetime

t = datetime.time(12,9,23,12980)
print(t)
print(type(t))
12:09:23.012980
<class 'datetime.time'>

注意:

  1. 1秒 = 1000毫秒(milliseconds)
  2. 1毫秒 = 1000微秒(microseconds)

【练习】如何将给定日期转换为当天开始的时间?

import datetime

date = datetime.date(2019,10,2)
dt = datetime.datetime(date.year,date.month,date.day)
print(dt)

dt = datetime.datetime.combine(date, datetime.time.min)
print(dt)
2019-10-02 00:00:00
2019-10-02 00:00:00

timedelta类

timedelta表示具体时间实例中的一段时间。你可以把它们简单想象成两个日期或时间之间的间隔。

它常常被用来从datetime对象中添加或移除一段特定的时间。

class timedelta(SupportsAbs[timedelta]):
    def __init__(self,days,seconds,microseconds,miliseconds,minutes,hours,weeks,):
        pass
    def days(self):
        pass
    def total_seconds(self):
        pass

【例子】如何使用datetime.timedelta()类?

import datetime

td = datetime.timedelta(days=30)
print(td)
print(type(td))
print(datetime.date.today())
print(datetime.date.today()+td)

dt1 = datetime.datetime(2020,1,31,10,10,0)
dt2 = datetime.datetime(2019,1,31,10,10,9)
td = dt1-dt2
print(td)
print(type(td))

td1 = datetime.timedelta(days=30)
td2 = datetime.timedelta(weeks=1)
td = td1 - td2
print(td)
print(type(td))
30 days, 0:00:00
<class 'datetime.timedelta'>
2021-04-28
2021-05-28
364 days, 23:59:51
<class 'datetime.timedelta'>
23 days, 0:00:00
<class 'datetime.timedelta'>

如果将两个datetime对象相减,就会得到表示该时间间隔的timedelta对象。

同样地,将两个时间间隔相减,可以得到另一个timedelta对象。

【练习】

  1. 距离你出生那天过去多少天了?
  2. 距离你今年的下一个生日还有多少天?
  3. 将距离你今年的下一个生日的天数转换为秒数。
from dateutil import parser
import datetime

bDay = 'Oct 13, 1995'
dt1 = parser.parse(bDay).date()
dt2 = datetime.date.today()
dt3 = datetime.date(dt2.year, dt1.month, dt1.day)
print(dt1)
print(dt2)
print(dt3)

td = dt2-dt1
print(td.days)
td = dt3 - dt2
print(td.days)
print(td.days*24*60*60)
print(td.total_seconds())
1995-10-13
2021-04-28
2021-10-13
9329
168
14515200
14515200.0

文件与文件系统

打开文件

  1. open(file, mode='r', buffering=None, encoding=None, errors=None, newline=None, closefd=True)

    Open file and return a stream. Raise OSError upon failure.

    a. file:必需,文件路径(相对或者绝对路径)。

    b. mode:可选,文件打开模式

    c. buffering:设置缓冲

    d. encoding:一般使用utf8

    e. errors:报错级别

    f. newline:区分换行符

常见的mode如下表所示:

打开模式执行操作
‘r’以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
‘w’打开一个文件只用于写入。
如果该文件已存在则打开文件,并从开头开始编辑。
即原有内容会被删除。
如果该文件不存在,创建新文件。
‘x’写模式,新建一个文件,如果该文件已存在则会报错。
‘a’追加模式,打开一个文件用于追加。
如果该文件已存在,文件指针将会放在文件的结尾。
也就是说,新的内容将会被写入到已有内容之后。
如果该文件不存在,创建新文件进行写入。
‘b’以二进制模式打开文件。一般用于非文本文件,如:图片。
‘t’以文本模式打开(默认)。一般用于文本文件,如:txt。
’+’可读写模式(可添加到其他模式中使用)

【例子】打开一个文件,并返回文件对象,如果该文件无法被打开,会抛出OSError

f = open('将进酒.txt')
print(f)

for each in f:
    print(each)
<_io.TextIOWrapper name='将进酒.txt' mode='r' encoding='UTF-8'>
君不见,黄河之水天上来,奔流到海不复回。



君不见,高堂明镜悲白发,朝如青丝暮成雪。



人生得意须尽欢,莫使金樽空对月。



天生我材必有用,千金散尽还复来。



烹羊宰牛且为乐,会须一饮三百杯。



岑夫子,丹秋生,将进酒,杯莫停。



与君歌一曲,请君为我倾耳听。



钟鼓馔玉不足贵,但愿长醉不愿醒。



古来圣贤皆寂寞,惟有饮者留其名。



陈王昔时宴平乐,斗酒十千恣欢谑。



主人何为言少钱,径须沽取对君酌。



五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。

文件对象方法

  • fileObject.close()用于关闭一个已打开的文件。关闭后的文件不能再进行读写操作,否则会触发ValueError错误。
f = open("将进酒.txt")
print('FileName:',f.name)
f.close()
FileName: 将进酒.txt
  • fileObject.read([size])用于从文件读取指定的字符数,如果为给定或为负则读取所有。
f = open('将进酒.txt','r')
line = f.read(20)
print("读取的字符串:%s"% line)
f.close()
读取的字符串:君不见,黄河之水天上来,奔流到海不复回。
  • fileObject.readline()读取整行,包括”\n”字符。
f = open('将进酒.txt','r')
line = f.readline()
print("读取的字符串: %s"%line)
f.close()
读取的字符串: 君不见,黄河之水天上来,奔流到海不复回。
  • fileObject.readlines()用于读取所有行(直到结束符EOF)并返回列表,该列表可以由Python的for...in...结构进行处理。
f = open('将进酒.txt','r')
lines = f.readlines()
print(lines)

for each in lines:
    each.strip()
    print(each)
f.close()
['君不见,黄河之水天上来,奔流到海不复回。\n', '\n', '君不见,高堂明镜悲白发,朝如青丝暮成雪。\n', '\n', '人生得意须尽欢,莫使金樽空对月。\n', '\n', '天生我材必有用,千金散尽还复来。\n', '\n', '烹羊宰牛且为乐,会须一饮三百杯。\n', '\n', '岑夫子,丹秋生,将进酒,杯莫停。\n', '\n', '与君歌一曲,请君为我倾耳听。\n', '\n', '钟鼓馔玉不足贵,但愿长醉不愿醒。\n', '\n', '古来圣贤皆寂寞,惟有饮者留其名。\n', '\n', '陈王昔时宴平乐,斗酒十千恣欢谑。\n', '\n', '主人何为言少钱,径须沽取对君酌。\n', '\n', '五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。']
君不见,黄河之水天上来,奔流到海不复回。



君不见,高堂明镜悲白发,朝如青丝暮成雪。



人生得意须尽欢,莫使金樽空对月。



天生我材必有用,千金散尽还复来。



烹羊宰牛且为乐,会须一饮三百杯。



岑夫子,丹秋生,将进酒,杯莫停。



与君歌一曲,请君为我倾耳听。



钟鼓馔玉不足贵,但愿长醉不愿醒。



古来圣贤皆寂寞,惟有饮者留其名。



陈王昔时宴平乐,斗酒十千恣欢谑。



主人何为言少钱,径须沽取对君酌。



五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。
  • fileObject.tell()返回文件的当前位置,即文件指针当前位置。
f = open('将进酒.txt','r')
line = f.readline()
print(line)
pos = f.tell()
print(pos)
f.close()
君不见,黄河之水天上来,奔流到海不复回。

61
  • fileObject.seek(offset[,whence])用于移动文件读取指针到指定位置。

    a. offset:开始的偏移量,也就是代表需要移动偏移的字节数,如果是负数表示从倒数第几位开始。

    b. whence:可选,默认值为0。给offset定义一个参数,表示要从哪个位置开始偏移:0代表从文件开头开始算起,1表示从当前位置开始算起,2代表从文件末尾算起。

f = open('将进酒.txt','r')
line = f.readline()
print(line)
line = f.readline()
print(line)
f.seek(0,0)
line = f.readline()
print(line)
f.close()
君不见,黄河之水天上来,奔流到海不复回。



君不见,黄河之水天上来,奔流到海不复回。
  • fileObject.write(str)用于向文件中写入指定字符串,返回的是写入的字符长度。
f = open('workfile.txt','wb+')
print(f.write(b'0123456789abcdef'))  # 返回的16是字符个数
print(f.seek(5))
print(f.read(1))
print(f.seek(-3,2))    # 返回的13是16-3
print(f.read(1))
16
5
b'5'
13
b'd'

在文件关闭前或缓冲区刷新前,字符串内容存储在缓冲区中,这时你在文件中是看不到写入的内容的。

如果文件打开模式带b,那写入文件内容时,str(参数)要用encode方法转为bytes形式,否则报错:TypeError: a bytes-like object is required, not 'str'

str = '...'
# 文本=Unicode字符序列
# 相当于string类型

str = b'...'
# 文本=八位序列(0到255之间的整数)
# 字节文字总是以'b'或'B'作为前缀;它们产生一个字节类型的实例,而不是str类型。
# 相当于byte[]

f = open('将进酒.txt','r+')
str = '\n作者:李白'
f.seek(0,2)
line = f.write(str)
f.seek(0,0)
for each in f:
    print(each)
f.close()
君不见,黄河之水天上来,奔流到海不复回。



君不见,高堂明镜悲白发,朝如青丝暮成雪。



人生得意须尽欢,莫使金樽空对月。



天生我材必有用,千金散尽还复来。



烹羊宰牛且为乐,会须一饮三百杯。



岑夫子,丹秋生,将进酒,杯莫停。



与君歌一曲,请君为我倾耳听。



钟鼓馔玉不足贵,但愿长醉不愿醒。



古来圣贤皆寂寞,惟有饮者留其名。



陈王昔时宴平乐,斗酒十千恣欢谑。



主人何为言少钱,径须沽取对君酌。



五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。

作者:李白
  • fileObject.writelines(sequence)向文件写入一个序列字符串列表,如果需要换行则要自己加入每行的换行符\n
f = open('test.txt','w+')
seq = ['小马的程序人生\n','老马的程序人生']
f.writelines(seq)
f.seek(0,0)
for each in f:
    print(each)
f.close()
小马的程序人生

老马的程序人生

简洁的with语句

一些对象定义了标准的清理行为,无论系统是否成功的使用了它,一旦不需要它了,那么这个标准的清理行为就会执行。关键词with语句就可以保证诸如文件之类的对象在使用完之后一定会正确的执行它的清理方法。

try:
    f = open('myfile.txt','w')
    for line in f:
        print(line)
except OSError as error:
    print('出错啦!%s' % error)
finally:
    f.close()
出错啦!not readable

这段代码执行完毕后,就算在处理过程中出问题了,文件f总是会关闭。

try:
    with open('myfile.txt','w') as f:
        for line in f:
            print(line)
except OSError as error:
    print('出错啦!%s'%error)
出错啦!not readable

with起到的效果和上述一样,更简洁。

OS模块中关于文件/目录常用的函数

我们所知道常用的操作系统就有:Windows,Mac OS,Linux,Unix等,这些操作系统底层对于文件系统的访问工作原理是不一样的,因此你可能就要针对不同的系统来考虑使用哪些文件系统模块……,这样的做法是非常不友好且麻烦的,因为这样就意味着当你的程序运行环境一改变,你就要相应的去修改大量的代码来应对。

有了OS(Operation System)模块,我们不需要关心什么操作系统下使用什么模块,OS模块会帮你选择正确的模块并调用。

  1. os.getcwd()用于返回当前工作目录。
  2. os.chdir(path)用于改变当前工作目录到指定的路径。
import os

path = '/Users'
print("当前工作目录:%s"%os.getcwd())
os.chdir(path)
print("目录修改成功:%s"%os.getcwd())
当前工作目录:/Users/alexandreaswiftie/Documents
目录修改成功:/Users
  • listdir(path='.')返回path指定的文件夹包含的文件或文件夹的名字的列表。
import os

dirs = os.listdir()
for item in dirs:
    print(item)
.localized
Shared
Guest
alexandreaswiftie
  • os.mkdir(path)创建单层目录,如果该目录已存在抛出异常。
import os 

path = '/Users/alexandreaswiftie/Documents'
os.chdir(path)
if os.path.isdir(r'./b') is False:   # windows是\
    os.mkdir(r'./B')
    os.mkdir(r'./B/A')
    
os.mkdir(r'./C/A')
---------------------------------------------------------------------------

FileNotFoundError                         Traceback (most recent call last)

<ipython-input-57-e015202a9ab9> in <module>
      7     os.mkdir(r'./B/A')
      8 
----> 9 os.mkdir(r'./C/A')


FileNotFoundError: [Errno 2] No such file or directory: './C/A'
  • os.makedirs(path) 用于递归创建多层目录,如果该目录已存在抛出异常。
import os 
os.makedirs(r'./E/A')
  • os.remove(path) 用于删除指定路径的文件。如果指定的路径是一个目录,将抛出OSError

【例子】首先创建.\E\A\test.txt 文件,然后进行删除。

import os 

print("目录为:%s"%os.listdir(r'./E/A'))
os.remove(r'./E/A/test.txt')
print("目录为:%s"%os.listdir(r'./E/A'))
目录为:[]



---------------------------------------------------------------------------

FileNotFoundError                         Traceback (most recent call last)

<ipython-input-59-3b8a3c5fb5dc> in <module>
      2 
      3 print("目录为:%s"%os.listdir(r'./E/A'))
----> 4 os.remove(r'./E/A/test.txt')
      5 print("目录为:%s"%os.listdir(r'./E/A'))


FileNotFoundError: [Errno 2] No such file or directory: './E/A/test.txt'
  • os.rmdir(path)用于删除单层目录。仅当这文件夹是空的才可以,否则,抛出OSError

【例子】首先创建.\E\A目录,然后进行删除。

import os

print("目录为:%s"%os.listdir(r'./E'))
os.rmdir(r'./E/A')
print("目录为:%s"%os.listdir(r'./E'))
目录为:['A']
目录为:[]
  • os.removedirs(path)递归删除目录,从子目录到父目录逐层尝试删除,遇到目录非空则抛出异常。

【例】首先创建.\E\A目录,然后进行删除。

import os 

print("目录为:%s"%os.listdir(os.getcwd()))
os.removedirs(r'./E/A')
print("目录为:%s"%os.listdir(os.getcwd()))
  • os.rename(src,dst)方法用于命名文件或目录,从srcdst,如果dst是一个存在的目录,将抛出OSError

【例】把test.txt文件重命名为test2.txt。

import os 

print("目录为:%s"%os.listdir(os.getcwd()))
os.rename("test.txt","test2.txt")
print("重命名成功。")
print("目录为:%s"%os.listdir(os.getcwd()))
  • os.system(command)运行系统的shell命令(将字符串转化成命令)

【例】先自行创建一个a.py的文件,然后由shell命令打开。

import os 

path = os.getcwd() + "/a.py"  # windows是'\\a.py'
a = os.system(r'python %s'%path)

os.system('calc')  # 打开计算器
32512
  1. os.curdir指代当前目录(.
  2. os.pardir指代上一级目录(..
  3. os.sep输出操作系统指定的路径分隔符(win下为\\,Linux下为/
  4. os.linesup当前平台使用的行终止符(win下为\r\n,Linux下为\n
  5. os.name指代当前使用的操作系统(包括:’mac’,’nt’)
import os 

print(os.curdir)
print(os.pardir)
print(os.sep)
print(os.linesep)
print(os.name)
.
..
/


posix
  1. os.path.basename(path)去掉目录路径,单独返回文件名
  2. os.path.dirname(path)去掉文件名,单独返回目录路径
  3. os.path.join(path1[,path2[,...]])path1,path2各部分组合成一个路径名
  4. os.path.split(path)分割文件名与路径,返回(f_path,f_name)元组。如果完全使用目录,它会将最后一个目录作为文件名分离,且不会判断文件或者目录是否存在。
  5. os.path.splitext(path)分离文件名与扩展名,返回(f_path,f_name)元组。
import os 

# 返回文件名
print(os.path.basename(r'C:\test\lsgo.txt'))  # lsgo.txt
# 返回目录路径
print(os.path.dirname(r'C:\test\lsgo.txt'))   # C:\test
# 将目录和文件名合成一个路径
print(os.path.join('C:\\','test','lsgo.txt')) # C:\test\lsgo.txt
# 分割文件名与路径
print(os.path.split(r'C:\test\lsgo.txt'))     # ('C:\\test','lsgo.txt')
# 分割文件名与扩展名
print(os.path.splitext(r'C:\test\lsgo.txt'))  # ('C:\\test\\lsgo','.txt')
  1. os.path.getsize(file)返回指定文件大小,单位是字节
  2. os.path.getatime(file)返回指定文件最近的访问时间
  3. os.path.getctime(file)返回指定文件的创建时间
  4. os.path.getmtime(file)返回指定文件的最新的修改时间
  5. 浮点型秒数,可用time模块的gettime()localtime()函数换算
import os 
import time 

file = r'.\lsgo.txt'
print(os.path.getsize(file))
print(os.path.getatime(file))
print(os.path.getctime(file))
print(os.path.getmtime(file))
print(time.gmtime(os.path.getctime(file)))
print(time.localtime(os.path.getctime(file)))
  1. os.path.exists(path)判断指定路径(目录或文件)是否存在
  2. os.path.isabs(path)判断指定路径是否为绝对路径
  3. os.path.isdir(path)判断指定路径是否存在且是一个目录
  4. os.path.isfile(path)判断指定路径是否存在且是一个文件
  5. os.path.islink(path)判断指定路径是否存在且是一个符号链接
  6. os.path.ismount(path)判断指定路径是否存在且是一个悬挂点
  7. os.path.samefile(path1,path2)判断path1和path2两个路径是否指向同一个文件
import os 

print(os.path.ismount('D:\\'))  
print(os.path.ismount('D:\\Test'))

序列化与反序列化

Python的pickle模块实现了基本的数据序列和反序列化。

  1. 通过pickle模块的序列化操作,我们能够将程序中运行的对象信息保存到文件中去,永久存储。
  2. 通过pickle模块的反序列化操作,我们能够从文件中创建上一次程序保存的对象。

pickle模块中最常用的函数为:

pickle.dump(obj,file,[,protocol])obj对象序列化存入已经打开的file中。

  1. obj:想要序列化的obj对象。
  2. file:文件名称
  3. protocol:序列化使用的协议。如果该项省略,则默认为0。如果为负值或HIGHEST_PROTOCOL,则使用最高的协议版本。

pickle.load(file)file中的对象序列化读出。

  • file:文件名称。
import pickle 

dataList = [[1,1,'yes'],
            [1,1,'yes'],
            [1,0,'no'],
            [0,1,'no'],
            [0,1,'no']]

dataDic = {0:[1,2,3,4],
           1:('a','b'),
           2:{'c':'yes','d':'no'}}

# 使用dump()将数据序列化到文件中
fw = open(r'.\dataFile.pkl','wb')

# pickle the list using the highest protocol available
pickle.dump(dataList,fw,-1)

# pickle dictionary using protocol 0.
pickle.dump(dataDic,fw)
fw.close()

# 使用load()将数据从文件中序列化读出
fr = open('dataFile.pkl','rb')
data1 = pickle.load(fr)
print(data1)
data2 = pickle.load(fr)
print(data2)
fr.close()

文档信息

Search

    Table of Contents