python第三章函数

第三章、三元运算、文件处理、函数

三元运算

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

简单条件语句:

if 条件成立:
    val = 1
else:
    val = 2
# 可以写成如下:
val = 1 if 条件成立 else 2

文件处理

读,写,修改

    • f = open(file='d:/*.txt', mode='r', encoding='utf-8')
      date = f.read()
      f.close()
      
    • r是只读模式,rb是以二进制读文件

第三方模块 chardet检测二进制内容可能是什么编码

使用pip安装第三方库,py3就用pip3 install chardet

[图片上传失败...(image-9970b8-1529681325214)]

import chardet

chardet.detect(data)

{'encoding':'GB2312','confidence':0.823045,'language':'Chinese'}

  • 循环文件

    • f = open("*.txt", "r", encoding="gbk")
      for line in f:
          print(line)
      f.close()
      

print每次执行之后会自动换行

  • 写文件

    • 模式 w 写模式,wb二进制写模式

    • f.write("路飞".encoding("gbk"))
      

      以wb模式写的时候需要指定以什么编码写

    • w写模式会先清空文件,然后去写,相当于直接覆盖文件原有的内容

    • w就是一个创建模式

  • 追加

    • a 追加模式,,ab二进制追加模式
  • 读写混合模式

    • r+ 读写模式,先读后写,读完可以追加.

      f.read()读完之后会将指针指向文件内容末尾,再次执行f.read()就读到是空

    • w+写读模式,先写后读,先往里覆盖写,再去读你写的内容.(相当于先创建了一个空文件替换掉原来的,然后可以读这次新写的内容,几乎用不到)

  • 文件操作的其他功能方法

    • def fileno(self, *args, **kwargs):  
              返回文件句柄在内核中的索引值,以后做IO多路复用时可以用到
      
      def flush(self, *args, **kwargs):  
              把文件从内存buffer里强制刷新到硬盘
      
      def readable(self, *args, **kwargs):  
              判断是否可读
      
      def readline(self, *args, **kwargs):  
              只读一行,遇到\r or \n为止,指针会指向下一行开头.
      
      def seek(self, *args, **kwargs):  
              把操作文件的光标移到指定位置
              *注意seek的长度是按字节算的, 字符编码存每个字符所占的字节长度不一样。
              如“路飞学城” 用gbk存是2个字节一个字,用utf-8就是3个字节,因此以gbk打开时,seek(4) 就把光标切换到了“飞”和“学”两个字中间。
              但如果是utf8,seek(4)会导致,拿到了飞这个字的一部分字节,打印的话会报错,因为处理剩下的文本时发现用utf8处理不了了,因为编码对不上了。少了一个字节
      
      def seekable(self, *args, **kwargs):  
              判断文件是否可进行seek操作
      
      def tell(self, *args, **kwargs):  
              返回当前文件操作光标位置,按字节单位
      
      def truncate(self, *args, **kwargs):  
              按指定长度截断文件
              *指定长度的话,就从文件开头开始截断指定长度,不指定长度的话,就从当前位置到文件尾部的内容全去掉。模式必须可写
      
      def writable(self, *args, **kwargs):  
              判断文件是否可写
      
    • f.tell() 返回当前光标位

    • f.seek(0) 将光标移到文件开头

    f.tell()和f.seek(0)都是以字节为单位

    f.read(1)是以字符为单位,gbk中一个中文字符2个字节,utf-8中一个中文字符3个字节

  • 修改文件

    • f = open("兼职白领学生空姐模特护士联系方式utf8.txt",'r+',encoding="utf-8")
      f.seek(6)
      f.write("[路飞学城]")
      f.close()
      
    • 王心[路飞学城]9    46    1381234424
      马纤羽     深圳    173    50    1374423423
      乔亦菲     广州    172    52    1582342525
      罗梦竹     北京    175    49    1862343421
      刘诺涵     北京    170    48    1862343765
      岳妮妮     深圳    177    54    1883524553
      贺婉萱     深圳    174    52    1893344452
      叶梓萱    上海    171    49    1804242324
      杜姗姗 北京  167 49 13324523342
      black girl  河北  167 50  13542342233
      
    • 确实从第3个字开始改的,但是[路飞学城] 把后面的内容覆盖了

练习题

练习题1 —— 全局替换程序:

  • 写一个脚本,允许用户按以下方式执行时,即可以对指定文件内容进行全局替换

      `python your_script.py old_str new_str filename`
    
  • 替换完毕后打印替换了多少处内容

# -*- coding:utf-8 -*-
# !/usr/bin/env python
# Author:dc0012

import sys

old_str = sys.argv[1]  # 接受被替换文本参数
new_str = sys.argv[2]  # 接收新文本
file_name = sys.argv[3]  # 接收需要处理的文件名字

f = open(file_name, "r+", encoding="utf-8")

content = f.read().replace(old_str, new_str)  # 替换后的文件全部内容给conten
f.seek(0)  #将指针移到文件开头
f.write(content)  # 将替换后的文件内容写入文件
f.truncate(f.tell())  # 防止新内容比旧内容少,将多出来的截取出去

f.close()

例: python your_script.py 北京 陕西 f_test

将f_test文件中的北京替换为陕西.

练习题2 —— 模拟登陆:

  • 用户输入帐号密码进行登陆
  • 用户信息保存在文件内
  • 用户密码输入错误三次后锁定用户,下次再登录,检测到是这个用户也登录不了
# -*- coding:utf-8 -*-
# !/usr/bin/env python
# Author:dc0012

import sys
with open("lock_account", "r+") as f_lock:
    with open("account", "r") as f_account:
        count = 0
        _username = input("username:").strip()
        for i in f_lock:
            if _username == i.strip():
                print("This account was locked....")
                sys.exit()
        for i in f_account:
            username, password = i.strip().split(",")
            if _username == username:
                while count < 3:
                    _password = input("password:")
                    if _password == password:
                            print("Welcome %s login..." % _username)
                            sys.exit()
                    else:
                        print("Wrong password...")
                        count += 1
                        continue
                else:
                    print("You have tried too many times.This username will be locked")
                    f_lock.write(_username + "\n")
                    sys.exit()
        print("No such this username....")
        sys.exit()

account存放用户名密码一行为一个用户,用","隔开用户名密码,例:dc,123

lock_account存放被锁定的用户名,一行一个用户名.

函数

定义:

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

特性:

  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)
      

函数参数

参数可以让你的函数更灵活,不知能做死的动作,还可以根据调用时传参的不同来决定函数内部的执行流程

形参变量:

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

实参:

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

[图片上传失败...(image-1deb4d-1529681325214)]

默认参数:

  • 在定义函数的时候赋予参数一个默认的值,如果调用的时候不给这个参数赋值,它就会调用默认的参数进行处理

默认参数必须放在位置参数后面

定义默认参数要牢记一点:默认参数必须指向不变对象!比如:如果默认参数是个空列表,而一旦更改了这个默认空列表的值,在下次调用时就会以更改后的列表作为参数来调用.

关键参数:

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

赋值的时候指定对象赋值的参数叫关键参数

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

调用可以这样

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

但绝不可以这样

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

当然这样也不行

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

这样相当于给age赋值2次,会报错!

非固定参数:

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

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'}
  • **kwargs 接收关键字参数,自动转换为字典.

如果定义函数的参数前出现了*,那么这个函数传递的参数就可以不再是固定个数,传过来的所有参数打包成一个元组

>>> nums = [1, 2, 3]
>>> calc(*nums)
14

*nums表示把nums这个list的所有元素作为可变参数传进去。这种写法相当有用,而且很常见。

函数返回值

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

注意

  • 函数在执行过程中只要遇到return语句,就会停止执行并返回结果,so 也可以理解为 return 语句代表着函数的结束
  • 如果未在函数中指定return,那这个函数的返回值为None

函数永远只能返回一个值,这个值可以是一个元组,一个列表,一个字典

局部变量

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

在函数里修改全局变量

  • 在函数内部使用global 变量名 ,来声明此变量为全局变量,进行修改

一般不建议在函数内部更改全局变量

  • 字典,列表,集合,对象,类里面的对象是可以在函数内部直接修改的
  • 全局变量如果是字符串,整型的话,是不能在函数内部直接更改的.

函数小结:

  • 定义函数时,需要确定函数名和参数个数;
  • 如果有必要,可以先对参数的数据类型做检查;
  • 函数体内部可以用return随时返回函数结果;
  • 函数执行完毕也没有return语句时,自动return None
  • 函数可以同时返回多个值,但其实就是一个tuple。

嵌套函数

  1. 函数内部可以再次定义函数
  2. 执行需要被调用
age = 19
def func1():
    # global age 定义全局变量后就不会出错
    def func2():
        print(age)
    func2()
    age = 73 
func1()
# 这种调用会导致出错

作用域

  • python中一个函数就是一个作用域
  • 局部变量放置在其作用域中
  • 定义完成后,作用域已经生成,作用域链向上查找

匿名函数

声明一个匿名函数

lamdba x, y: x*y   # 声明一个匿名函数
  • lambda只支持简单的逻辑,最多支持三元运算语法

    • def func1(x, y):
          if x < y:
              return x * y
          else:
              return x / y
      # 上面的函数换成lambda就是下面的格式
      func2 = lambda x, y: x * y if x < y else x / y
      
  • 和其他方法搭配使用,用完就丢弃了

作用:

  1. 节省代码量
  2. 看着高级

高阶函数

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

只需要满足以下任意一个条件,即是高阶函数:

  1. 接收一个或多个函数作为输入
  2. return返回另外一个函数

递归函数

递归特性:

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

先举个简单的例子:计算1到100之间相加之和;通过循环和递归两种方式实现

#!/usr/bin/env python3
# 1-100 sum

import sys
def sum_cycle(n):
    '''
    1 to n,The sum function
    '''
    sum = 0
    for i in range(1,n + 1):
        sum += i
    return sum

def sum_recu(n):
    '''
    1 to n,The sum function
    '''
    if n > 0:
        return n + sum_recu(n - 1)    #调用函数自身
    else:
        return 0
print("循环求和:",sum_cycle(100))
print("递归求和:",sum_recu(100))
执行结果:
[root@localhost tmp]# ./sum.py
循环求和: 5050
递归求和: 5050

递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。

***使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。

把上面的递归求和函数的参数改成10000就导致栈溢出!

[root@localhost tmp]# ./sum.py
循环求和: 5050
Traceback (most recent call last):
  File "./sum.py", line 23, in <module>
    print("递归求和:",sum_recu(1000))
  File "./sum.py", line 19, in sum_recu
    return n + sum_recu(n - 1)
  File "./sum.py", line 19, in sum_recu
    return n + sum_recu(n - 1)
  File "./sum.py", line 19, in sum_recu
    return n + sum_recu(n - 1)
  [Previous line repeated 994 more times]
  File "./sum.py", line 18, in sum_recu
    if n > 0:
RecursionError: maximum recursion depth exceeded in comparison

***解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。

尾递归优化:http://www.open-open.com/lib/view/open1480494663229.html

二分法查找大家应该听说过;就是一种快速查找的方法,时间复杂度低,逻辑简单易懂,总的来说就是不断的找出中间值,用中间值对比你需要找的实际值;若中间值大,则继续找左边;若中间值小,则继续找右边;可以看出二分法就是不断重复此上过程,所以就可以通过递归方式来实现二分法查找了!

小结

  • 使用递归函数的优点是逻辑简单清晰,缺点是过深的调用会导致栈溢出。
  • 针对尾递归优化的语言可以通过尾递归防止栈溢出。尾递归事实上和循环是等价的,没有循环语句的编程语言只能通过尾递归实现循环。
  • Python标准的解释器没有针对尾递归做优化,任何递归函数都存在栈溢出的问题。
#!/usr/bin/env python3

#The binary search function

def  Binary_Search(data_source,find_n):
    if len(data_source) >= 1:                                           #判断列表长度是否大于1,小于1就是一个值
        mid = int(len(data_source)/2)                                   #获取列表中间索引;奇数长度列表长度除以2会得到小数,通过int将转换整型
        if find_n > data_source[-1]:                                    #判断查找值是否超出最大值
            print('{}查找值不存在!'.format(find_n))
            exit()
        elif find_n < data_source[0]:                                   #判断查找值是否超出最小值
            print('{}查找值不存在!'.format(find_n))
            exit()
        if data_source[mid]  > find_n:                                  #判断列表中间值是否大于查找值
            #print('查找值在 {} 左边'.format(data_source[mid]))
            Binary_Search(data_source[:mid],find_n)                     #调用自己,并将中间值左边所有元素做参数
        elif data_source[mid] < find_n:                                 #判断列表中间值是否小于查找值
            #print('查找值在 {} 右边'.format(data_source[mid]))           #调用自己,并将中间值右边所有元素做参数
            Binary_Search(data_source[mid:],find_n)
        else:
            print('找到查找值',data_source[mid])                          #找到查找值
    else:
        print('{}查找值不存在!'.format(find_n))                          #特殊情况,返回查找不到

Data = [22,12,41,99,101,323,1009,232,887,97]
Data.sort()                                                             #列表从小到大排序
Binary_Search(Data,323)                                                 #查找323
执行结果:
[root@localhost tmp]# ./binary_search.py 
找到查找值 323

内置方法

函数名 作用
abs() 取一个数的绝对值
dict() 把一个数据转换成字典类型
help() 帮助
min() 取一组整型数据中最小的
max() 取最大数
seattr()
all() 检查所有元素是不是都是True,否则返回False,用all来判断空列表会返回True
any() 检查所有元素只要有一个是True就返回True,判断空列表会返回False
dir() 打印当前程序中存在的所有变量
hex() 转换16进制
next() 执行迭代器.....
slice() 切片,class slice(start, stop[, step])
divmod() divmod(10,3)返回商和余数
sorted() sorted(d.items(), key = lambda x:x[1], reverse=True)可以定义排序规则
ascii() 转换为unicode编码
oct() 转换8进制
staticmethod()
bin() 转换二进制
evel() 按解释器规则把字符转转换为代码运行,只能处理单行代码,可以拿到运行结果
exec() 按解释器规则把字符转转换为代码运行,可以执行多行代码,拿不到函数返回值或者程序运行结果
isinstance() isinstance("a", str) ---> True
ord() 把字符串转换为ascii码
sum() 求和
bytearray() 将byte类型转换为bytearray类型,可以进行内存地址修改,达到修改字符串的目的,用于更改大字符串.
filter() 用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。 该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。
map() map(lambda x: x*x, [1,2,3,4,5,6])将列表每个元素进行自乘
reduce() import functools,functools.reduce()
bytes()
pow() 返回多少次方
print() 屏幕输出
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • 〇、前言 本文共108张图,流量党请慎重! 历时1个半月,我把自己学习Python基础知识的框架详细梳理了一遍。 ...
    Raxxie阅读 18,934评论 17 410
  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,766评论 0 38
  • 1.有时候,想要和亲人们的距离在接近,让我们之间的感情变的好一些,可是哭于没有什么好的方法,说话,与他们聊什么,自...
    沐星之星星阅读 666评论 0 0
  • 当年有幸与您逢, 一生梦中情依浓。 不求朝夕成伴侣, 只愿初情藏心中! 八里初职刻心屝, 精密常是影伴归。 如今青...
    黄晓红阅读 263评论 0 4
  • 微服务架构 微服务利弊 适用性
    白马王朗阅读 172评论 0 0