第三章 Python基础——文件操作&函数

3.1三元运算

三元运算又称三目运算,是对简单条件的简写

if 条件成立:
    val=1
else:
    val=2

改成三元运算:

val=1 if条件成立 else 2

3.2字符编码转换

编码的种类情况:

 ASCLL占1个字符,只支持英文

 GB2312占2个字节,支持6700+汉字

 GBK GB2312的升级版,支持21000+汉字

 Shift-JIS日本字符

 ks_c_5601-1987韩国编码

 TIS-620泰国编码

万国码:Unicode

两个作用:1.支持全球的所有语言,每个国家都可以用Unicode。

     2.unicode包含了跟全球所有国家编码的映射关系。

总之:UTF是为Unicode编码设计的一种在储存和传输时节省空间的编码方案

注意:无论什么编码在内存里显示字符,存在硬盘里都是二进制。

编码的转换:

GBK中文编码←→Unicode←→Shift-JIS

(GBK   decode到Unicode,Unicode encode到Shift-JIS    decode解码、encode编码)

Python bytes类型

bytes类型,即字节类型, 它把8个二进制一组称为一个byte,用16进制来表示。

Python 2 搞了一个新的字符类型,就叫unicode类型,比如你想让你的中文在全球所有电脑上正常显示,在内存里就得把字符串存成unicode类型。

PY3 除了把字符串的编码改成了unicode, 还把str 和bytes 做了明确区分, str 就是unicode格式的字符, bytes就是单纯二进制啦。

3.4文件处理

python处理文件

例一:

f=open(file'D:/工作日常/兼职白领学生空姐模特护士联系方式.txt',mode='r',encoding='utf-8')
data=f.read()
f.close()

上边的语法解释:
f=open(file'D:/工作日常/兼职白领学生空姐模特护士联系方式.txt' 表示文件路径
mode='r'                                                             表示只读(可以改为其他)
encoding=’uft-8'                                                  表示将硬盘上的0101010按照uft的规则“断句”后的每一段0101010转换成unicode的01010101,unicode对照表中有01010101和字符的对应关系。
f.read()                                                               表示读取所有内容,内容是已经转换完毕的字符串

f.close()                                                               表示关闭文件

注意:此处的encoding必须和文件在保存时设置的编码一致,不然“断句”会不准确从而造成乱码。

例二:

f = open(file='D:/工作日常/兼职白领学生空姐模特护士联系方式.txt',mode='rb')
data = f.read()
f.close()


上边语法解释:
file='D:/工作日常/兼职白领学生空姐模特护士联系方式.txt'      表示文件路径
mode='rb'                                            表示只读(可以修改为其他)
f.read()                                             表示读取所有内容,内容是硬盘上原来以某种编码保存的 010101010,即:某种编码格式的字节类型
f.close()                                            表示关闭文件

例一与例二的区别:在于示例2打开文件时并未指定encoding,直接以rb模式打开了文件 ,rb是指二进制模式,数据读到内存里直接是bytes格式。

注意:

  • 文件操作时,以 “r”或“rb” 模式打开,则只能读,无法写入;
  • 硬盘上保存的文件都是某种编码的0101010,打开时需要注意:
    • rb,直接读取文件保存时原生的0101010,在Python中用字节类型表示
    • r和encoding,读取硬盘的0101010,并按照encoding指定的编码格式进行断句,再将“断句”后的每一段0101010转换成unicode的 010101010101,在Python中用字符串类型表示

循环文件

f=open("兼职白领学生空姐模特护士联系方式。txt",'r',encoding="uft-8")

for line in f:
     print(line)

f.close()

写文件

f.=open(file=‘D:/工作日常/兼职白领学生空姐模特护士联系方式.txt,mode='w',encoding='uft-8')
f.write('北大本科美国留学一次50,微信号:xxxxx')
f.close()


上边语法解释:
file='D:/工作日常/兼职白领学生空姐模特护士联系方式.txt  表示文件路径
mode='w'                                             表示只写
encoding='utf-8'                                     将要写入的unicode字符串编码成utf-8格式
f.write(...)                                         表示写入内容,写入的内容是unicode字符串类型,内部会根据encoding转换为制定编码的 01101010101,即:字节类型
f.close()

二进制写

f = open(file='D:/工作日常/兼职白领学生空姐模特护士联系方式.txt',mode='wb')
f.write('北大本科美国留学一次50,微信号:xxxxx'.encode('utf-8'))
f.close()
 上边语法解释:
file='D:/工作日常/兼职白领学生空姐模特护士联系方式.txt'      表示文件路径
mode='wb'                                             表示只以2进制模式写
f.write(...)                                          表示写入内容,写入的内容必须字节类型,即:是某种编码格式的0101010
f.close()

注意:

文件操作时,以 “w”或“wb” 模式打开,则只能写,并且在打开的同时会先将内容清空。

写入到硬盘上时,必须是某种编码的0101010,打开时需要注意:

  • wb,写入时需要直接传入以某种编码的0100101,即:字节类型
  • w 和 encoding,写入时需要传入unicode字符串,内部会根据encoding制定的编码将unicode字符串转换为该编码的 010101010

追加:把内容追加到文件底部

f = open("兼职白领学生空姐模特护士联系方式.txt",'a',encoding="gbk")

f.write("\n杜姗姗 北京  167 49 13324523342")
f.close()

注意:

文件操作时,以 “a”或“ab” 模式打开,则只能追加,即:在原来内容的尾部追加内容

写入到硬盘上时,必须是某种编码的0101010,打开时需要注意:

  • ab,写入时需要直接传入以某种编码的0100101,即:字节类型
  • a 和 encoding,写入时需要传入unicode字符串,内部会根据encoding制定的编码将unicode字符串转换为该编码的 010101010

读写模式

f = open("兼职白领学生空姐模特护士联系方式.txt",'r+',encoding="gbk")
data = f.read() #可以读内容 
print(data)
f.write("\nblack girl  河北  167 50  13542342233") #可以写
f.close()

不能添加到任意位置,W+会把之前的内容清除。

文件操作的其他功能;

def fileno(self, *args, **kwargs): # real signature unknown
        返回文件句柄在内核中的索引值,以后做IO多路复用时可以用到

    def flush(self, *args, **kwargs): # real signature unknown
        把文件从内存buffer里强制刷新到硬盘

    def readable(self, *args, **kwargs): # real signature unknown
        判断是否可读

    def readline(self, *args, **kwargs): # real signature unknown
        只读一行,遇到\r or \n为止

    def seek(self, *args, **kwargs): # real signature unknown
        把操作文件的光标移到指定位置
        *注意seek的长度是按字节算的, 字符编码存每个字符所占的字节长度不一样。
        如“路飞学城” 用gbk存是2个字节一个字,用utf-8就是3个字节,因此以gbk打开时,seek(4) 就把光标切换到了“飞”和“学”两个字中间。
        但如果是utf8,seek(4)会导致,拿到了飞这个字的一部分字节,打印的话会报错,因为处理剩下的文本时发现用utf8处理不了了,因为编码对不上了。少了一个字节

    def seekable(self, *args, **kwargs): # real signature unknown
        判断文件是否可进行seek操作

    def tell(self, *args, **kwargs): # real signature unknown
        返回当前文件操作光标位置 

    def truncate(self, *args, **kwargs): # real signature unknown
        按指定长度截断文件
        *指定长度的话,就从文件开头开始截断指定长度,不指定长度的话,就从当前位置到文件尾部的内容全去掉。

    def writable(self, *args, **kwargs): # real signature unknown
        判断文件是否可写

修改文件

f1 = open("luffy.txt",'w',encoding="utf-8")

f1.write("[路飞学城]")

f1.close()

f = open("luffy.txt",'r+',encoding="utf-8")

f.write("alex")

f.close()

占硬盘方式的文件修改代码示例

f_name = "兼职白领学生空姐模特护士联系方式utf8.txt"
f_new_name = "%s.new" % f_name

old_str = "乔亦菲"
new_str = "[乔亦菲 Yifei Qiao]"

f = open(f_name,'r',encoding="utf-8")
f_new = open(f_new_name,'w',encoding="utf-8")

for line in f:

    if old_str in line:
        new_line = line.replace(old_str,new_str)
    else:
        new_line = line

    f_new.write(new_line)

f.close()
f_new.close()

上面的代码,会生成一个修改后的新文件 ,原文件不动,若想覆盖原文件

import os

f_name = "兼职白领学生空姐模特护士联系方式utf8.txt"
f_new_name = "%s.new" % f_name

old_str = "乔亦菲"
new_str = "[乔亦菲 Yifei Qiao]"

f = open(f_name,'r',encoding="utf-8")
f_new = open(f_new_name,'w',encoding="utf-8")

for line in f:

    if old_str in line:
        new_line = line.replace(old_str,new_str)
    else:
        new_line = line

    f_new.write(new_line)

f.close()
f_new.close()

os.rename(f_new_name,f_name) #把新文件名字改成原文件 的名字,就把之前的覆盖掉了,windows使用os.replace # 帮助文档说明replace会覆盖原文件

 

3.4函数

函数在BASIC中叫做subroutine(子过程或子程序),在Pascal中叫做procedure(过程)和function,在C语言当中只有function,在JAVA中叫做method。

定义:函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可

特性:

1.减少重复代码

2.使程序变得可扩展

3.使程序变得易维护

语法定义

def sayhi():#函数名
      print(“Hello,I‘m nobody!”)

sayhi()#调用函数

有参数的情况下

#下边这段代码a,b=5,8
c=a**b
print(c)


#改成用函数写
def calc(x,y):
      res=x**y
      return res #返回执行函数结果

c=calc(a,b) #结果赋值给C变量
print(C)

函数参数

形参变量:只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量。

实参:可以是常量、表达式、函数等,无论是何种类型的量,在进行函数调用时,他们都必须有确定的值,以便把这些值传给形参。因此应预先用赋值,输入等办法使参数获得确定值。

def calc(x,y):     #x y 为形参
      res=x**y
      return res
c=calc(a,b)         #a  b为实参
print(c)

默认参数

把一个名词变成默认参数:

def stu_register(name,age,course,country="CN")

这样这个参数在调用时不指定,那就是默认的CN,指定的话,就是你指定的值。

注:把CN变成默认参数后把他的位置放在最后。

关键参数正常情况下,给函数传函数要按顺序,不想按顺序就可以用关键参数,只需指定参数名即可。指定参数名的参数就叫关键参数),但记住有一个要求就是,关键参数必须放在位置参数(以

位置顺序确定对应关系的参数)之后。

例如,调用时这样用

stu_register("王山炮“,course='PY',age=22,country='JP')

不可以这样用

stu_register("王山炮“,course='PY',22,country='JP')

更不能这样

stu_register("王山炮“,22,age=25,country='JP')

这样相当于两次给age赋值,会会报错。

非固定参数

若你的函数定义时不确定用户想传入多少个参数,就可以使用非固定函数

def stu_register(name,age,*args):#*args会把多传入的参数变成一个元素形式
      print(name,age,args)

stu-register("Alex",22)
#输出
#Alex 22()#后边这个()就是args,只是因为没传值,所以为空


stu-register(“Jack”,32,“CN”,“Python")
#输出
#jack 32 ('CN','Python')

还有一种**kwargs

def stu_register(name,age,*args,**kwargs): # *kwargs 会把多传入的参数变成一个dict形式
    print(name,age,args,kwargs)

stu_register("Alex",22)
#输出
#Alex 22 () {}#后面这个{}就是kwargs,只是因为没传值,所以为空

stu_register("Jack",32,"CN","Python",sex="Male",province="ShanDong")
#输出
# Jack 32 ('CN', 'Python') {'province': 'ShanDong', 'sex': 'Male'}

返回值

函数外边的代码要想获取函数的执行结果,就可以在函数里用return语句把结果返回。

def stu_register(name, age, course='PY' ,country='CN'):
    print("----注册学生信息------")
    print("姓名:", name)
    print("age:", age)
    print("国籍:", country)
    print("课程:", course)
    if age > 22:
        return False
    else:
        return True

registriation_status = stu_register("王山炮",22,course="PY全栈开发",country='JP')

if registriation_status:
    print("注册成功")

else:
    print("too old to be a student.")

注意:

1.函数执行过程中只要遇到return语句,就会停止执行并返回结果,那么也可以理解为return语句代表函数的结束。

2.如果未在函数中指定return,那么函数的返回值为None

全局与局部变量

name="Alex Li“

def change_name(name):
      print("before change:",name)
       name="金角大王,一个有的tesla的男人”
       print("after change",name)


change_name(name)

print("在外边看看name改了吗?“,naem)

输出

before change:ALex Li
after change 金角大王,一个有tesla的男人
在外边看看name改了吗?Alex Li
name = "Alex Li"


def change_name():
    name = "金角大王,一个有Tesla的男人"
    print("after change", name)


change_name()

print("在外面看看name改了么?", name)

但是不能这样改:

  • 在函数中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。
  • 全局变量作用域是整个程序,局部变量作用域是定义该变量的函数。
  • 当全局变量与局部变量同名时,在定义局部变量的函数内,局部变量起作用;在其它地方全局变量起作用。

作用域

作用域(scope),程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。

在函数里修改全局变量:

name = "Alex Li"

def change_name():
    global name
    name = "Alex 又名 金角大王,路飞学城讲师"
    print("after change", name)


change_name()

print("在外面看看name改了么?", name)

global name的作用就是要在函数里声明全局变量name ,意味着最上面的name = "Alex Li"即使不写,程序最后面的print也可以打印name

嵌套函数

name = "Alex"

def change_name():
    name = "Alex2"

    def change_name2():
        name = "Alex3"
        print("第3层打印", name)

    change_name2()  # 调用内层函数
    print("第2层打印", name)


change_name()
print("最外层打印", name)

输出

第3层打印 Alex3
第2层打印 Alex2
最外层打印 Alex

匿名函数

匿名函数就是不需要显示的制定函数名

#这段代码
def calc(x,y):
    return x**y

print(calc(2,5))

#换成匿名函数
calc = lambda x,y:x**y
print(calc(2,5))

高阶函数

变量可以指向函数,函数的参数可以接受变量,那么一个函数就可以接受另一个函数作为参数,这种函数称之为高阶函数。

def add(x,y,f):
    return f(x) + f(y)


res = add(3,-6,abs)
print(res)

只需满足一下任意一个条件就是高阶函数

接受一个或多个函数作为输入

return返回另外一个函数

递归

在函数内部,可以调用其他函数。如果一个函数的内部调用自身本身,这个函数就是递归函数。

def calc(n):
    print(n)
    if int(n/2) ==0:
        return n
    return calc(int(n/2))

calc(10)

输出

10
5
2
1

递归特性:

  1. 必须有一个明确的结束条件
  2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
  3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

内置函数

几个古怪内置方法的提醒

#compile
f = open("函数递归.py")
data =compile(f.read(),'','exec')
exec(data)


#print
msg = "又回到最初的起点"
f = open("tofile","w")
print(msg,"记忆中你青涩的脸",sep="|",end="",file=f)


# #slice
# a = range(20)
# pattern = slice(3,8,2)
# for i in a[pattern]: #等于a[3:8:2]
#     print(i)
#
#


#memoryview
#usage:
#>>> memoryview(b'abcd')
#<memory at 0x104069648>
#在进行切片并赋值数据时,不需要重新copy原列表数据,可以直接映射原数据内存,
import time
for n in (100000, 200000, 300000, 400000):
    data = b'x'*n
    start = time.time()
    b = data
    while b:
        b = b[1:]
    print('bytes', n, time.time()-start)

for n in (100000, 200000, 300000, 400000):
    data = b'x'*n
    start = time.time()
    b = memoryview(data)
    while b:
        b = b[1:]
    print('memoryview', n, time.time()-start)

 

posted on 2018-08-28 21:36  大王!  阅读(176)  评论(0编辑  收藏  举报