每天一点动力——python基础(四)

前言

    记录一下复习python的过程,有不对的地方欢迎在评论区批评指正,感谢!!

一、函数

    函数可能是在使用python过程中用的最多的一种语法结构了,而在使用函数过程中,也有很多需要值得注意、容易出错的地方。
    函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。python中有很多内置函数,比如dir()、print()、abs()……,我们也可以自己定义函数去实现我们想要的功能。
    在python中,定义一个函数有以下几个规则:

  • 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
  • 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
  • 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
  • 函数内容以冒号起始,并且缩进。
  • return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。

注:yield关键字也是用于返回值的,所不同的是,如果一个函数中有yield关键字,那么这个函数就成了一个生成器。

    函数基本语法如下:

def 函数名(参数):
	函数体

    函数的写法以及调用在这里我就不记录了,主要是记录一下函数中需要注意的几个地方。

1.参数传递

    在python中,一切皆对象。也就是说,传入函数的参数只有可更改对象和不可更改对象。
    在python中,不可更改对象包括:string、number、triple等;可更改对象包括:list、dict等。

  • 不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a。
  • 可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。

python 函数的参数传递:

  • 不可变类型:类似 c++ 的值传递,如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。

  • 可变类型:类似 c++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响

1.1 不可变对象传递

def func(a):
    a = 10
    print(f"a = {a}")


b = 2
func(b)
print(f"b = {b}")

执行结果:

a = 10
b = 2

    可以看出,在这个函数中,并没有改变不可变对象b的值。我们可以这样理解:首先定义了一个int对象b=2,然后将b传递到函数func中,此时,将b复制给a,而在func函数中,又将a指向了另一个int对象10,此时a=2就被抛弃,所以结果a是10,b是2。
    那我们传入的是一个列表呢?

2.可变对象传递

def func(a):
    a.extend([4, 5, 6])
    print(f"a = {a}")


b = [1, 2, 3]
func(b)
print(f"b = {b}")

执行结果:

a = [1, 2, 3, 4, 5, 6]
b = [1, 2, 3, 4, 5, 6]

    程序执行结果中,a=[1,2,3,4,5,6]我们可以理解,因为传入到函数中的是[1,2,3],而在函数中又执行了extend([4,5,6]),所以函数内部的a结果就是[1,2,3,4,5,6]。但同时我们可以发现,b的值也改变了。
    这里就涉及到了参数传递的知识,python在传入可变对象的时候,其实是将这个对象本身传递到了函数中,所以函数体内对传入的参数进行修改时,其实是修改的这个对象本身,而不是将b复制给啊。

在这一部分需要注意的就是可变对象和不可变对象传入函数时的区别,可变对象传入函数后,修改的是其本身,而不可变对象传入函数后,并不会修改其本身。

2.函数中的参数

    调用函数时可使用的正式参数类型有:

  • 必须参数;
  • 关键字参数;
  • 默认参数;
  • 不定长参数。

在这里,主要记录一下不定长参数,其他参数可以参考菜鸟教程-函数
    一个星号*的参数会以元组的形式进行导入,存放所有未命名的变量参数。

def func(*args):
    print(*args)
    print(args)
    print(args[0])


func(12, 23, 45)		# 这三个参数以元组的形式导入到函数中
print('*' * 30)
func((25, 12, 45), [12, 44, 66])	# 一个元组,一个列表,分别将这两部分看成一个元素,然后将两个元素以元组的形式传递给函数

执行结果:

12 23 45
(12, 23, 45)
12
******************************
(25, 12, 45) [12, 44, 66]
((25, 12, 45), [12, 44, 66])
(25, 12, 45)

    两个星号**是将参数以字典的形式导入:

def func(**kwargs):	
    print(kwargs)		# kwargs是一个字典:{'a':45,'b'}
    print(kwargs['a'])
    print(kwargs['b'])
    print(kwargs.keys())


func(a=45, b=56)

执行结果:

{'a': 45, 'b': 56}
45
56
dict_keys(['a', 'b'])

一个*传递参数时,参数是未命名的,而两个星号传递参数时,参数必须是命名的。因为一个星号的参数是以元组的形式导入到函数中的,而两个星号是以字典的形式导入到函数中的,字典必须要key和value一一对应,即必须有key,而这个key在传参时需要定义,即参数的名字。

3.匿名函数

    匿名函数也是经常用到的一个知识点。python中以lambda来创建匿名函数。
    匿名函数就是没有名字的函数,所以也不用return进行返回,匿名函数的返回值就是其表达式的结果。
    匿名函数的语法结构如下:

lambda 参数:表达式

例如:

func = lambda x:x*x

这个函数就等同于:

def func(x):
	return x*x

    既然普通函数就能解决的问题,为什么还要用匿名函数呢?
    有些时候,并不需要显示的定义函数,传入匿名函数会更加方便。
    匿名函数的使用:

func = lambda x: x * x
res = func(5)
print(res)

执行结果:

25

    匿名函数中还可以进行三元运算:

func = lambda a, b: a * b if a > b else a + b

print(func(5, 6))
print(func(6, 5))

执行结果:

11
30

使用匿名函数的好处:

  • 匿名函数不需要特意去定义一个函数名,可能这个函数只是某个地方临时用一下,后面就不会再用了;
  • 匿名函数一般都是和其他方法搭配使用,使得代码更加简洁.

    匿名函数配合map()一起使用:
map()函数的介绍:

map(func, *iterables) --> map object

简单来说:map()接收一个函数和一个可迭代对象,并通过函数作用到可迭代对象的每一个元素上,生成一个新的可迭代对象,以列表为例:

a = [1, 2, 3, 4, 5, 6]
func = lambda x: x ** 2

b = map(func, a)        # 返回a中每一个元素的平方,b是一个可迭代对象
print(b)
print(list(b))          # 用list将可迭代对象变为列表

执行结果:

<map object at 0x000001FAF0B181C8>
[1, 4, 9, 16, 25, 36]

注意:map中传入的函数参数不仅仅是匿名函数,还可以是普通函数:

a = [1, 2, 3, 4, 5, 6]


def func(x):
    return x ** 2


b = map(func, a)  # 返回a中每一个元素的平方,b是一个可迭代对象
print(b)
print(list(b))  # 用list将可迭代对象变为列表

执行结果:

<map object at 0x0000016F5C5281C8>
[1, 4, 9, 16, 25, 36]

可以看到和使用匿名函数的结果是一样的,只不过匿名函数更加简洁。如果我们只是实现一个特定的小功能,且这个功能用的较少,可以考虑使用匿名函数。

4.嵌套函数

    函数中还可以嵌套函数,例如:

def func1(a, b):
    c = a + b

    def func2(x):
        return x ** 2

    return func2(c)


print(func1(2, 3))

执行结果:

25

    装饰器其实就是函数嵌套函数来完成的。

python程序的执行顺序是从上往下执行,当遇到函数时候,先将其放入内存,等这个函数被调用的时候再去执行。

二、错误和异常

    在编写程序的过程中,不论是语法错误还是逻辑错误,有时候都是不可避免的。尤其是在做一个比较大的功能的时候,不可避免的会出现一些预料不到的错误。为了不影响程序的正常使用,经常会用一些特殊的语法规则来捕获这些错误,保证程序的正常使用。

2.1 try……except

    python中使用try语句来捕获异常:

try:
	执行代码
except:
	发生异常时执行的代码

try语句的工作流程为:

  • 首先,执行try字句(在try和except之间的代码行);
  • 如果没有异常发生,则不执行except语句,try字句执行完后try……except结束;
  • 如果在执行 try 子句的过程中发生了异常,那么 try 子句余下的部分将被忽略。如果异常的类型和 except 之后的名称相符,那么对应的 except 子句将被执行;
  • 如果一个异常没有与任何的 except 匹配,那么这个异常将会传递给上层的 try 中。

例如:
首先来看一个try字句没有异常的情况:

try:
    a = 2
    b = 3

    c = a + b
    print(c)

except Exception as e:		
    print(e)

执行结果:

5

再看一个发生异常的代码:

try:
    a = 'a'
    b = 3

    c = a + b		# a是一个字符串而b是一个数字,不能直接相加
    print(c)

except Exception as e:
    print(e)

执行结果:

can only concatenate str (not "int") to str

在这个执行结果中,其实是执行的except下的字句:print(e),而e是我们捕获到的异常。

2.2 try/except……else

    还有一种写法是:

try:
	执行代码
except:
	发生异常时执行的代码
else:
	没有异常时执行的代码

    这种写法的代码执行流程是:先执行try字句,如果try字句没有异常,则执行else语句,如果try字句有异常,则执行except字句(此时else语句是不执行的)。例如:
    没有异常的情况:

try:
    a = 2
    b = 3

    c = a + b
    print(c)

except Exception as e:
    print(e)

else:
    print(f"a = {a}\tb = {b}")

执行结果:

5
a = 2	b = 3

发生异常的情况:

try:
    a = 'a'
    b = 3

    c = a + b
    print(c)

except Exception as e:
    print(e)

else:
    print(f"a = {a}\tb = {b}")

执行结果:

can only concatenate str (not "int") to str

2.3 finally

try:
	执行代码
except:
	发生异常时执行的代码
else:
	没有异常时执行的代码
finally:
	不管有没有异常都会执行的代码

2.4 assert 断言

    Python assert(断言)用于判断一个表达式,在表达式条件为 false 的时候触发异常。(assert语句我也经常用到,经常是在数据预处理过程中)。
    这个知识点会用就可以了:

def func(a, b):
    assert a == b		# 如果a==b,就继续向下执行,如果a!=b,即a==b为False,则触发异常,程序停止
    return a + b

c = func(1, 2)
print(c)

执行结果:

Traceback (most recent call last):
  File "E:/python/echart练习/1111.py", line 6, in <module>
    c = func(1, 2)
  File "E:/python/echart练习/1111.py", line 2, in func
    assert a == b
AssertionError

def func(a, b):
    assert a == b
    return a + b


c = func(2, 2)
print(c)

执行结果:

4

个人认为,除非是必须使得某一个表达式为True才往下执行程序,其他情况还是慎用assert。

2.5 异常类型

    python中的异常类型比较多,具体可以参考Python的官网,在平时使用过程中,如果不确定程序的异常会是哪一种,那就直接使用Exception 来捕获异常。

三、文件操作

    文件涉及到的相关操作主要就是读和写:open()、write()。

3.1 open()

    ope()的完整语法格式为:

open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
  • file: 必需,文件路径(相对或者绝对路径)。
  • mode: 可选,文件打开模式
  • buffering: 设置缓冲
  • encoding: 一般使用utf8
  • errors: 报错级别
  • newline: 区分换行符
  • closefd: 传入的file参数类型

    在我平时做文本处理时,一般用到的参数有file、mode、encoding。
    mode参数可以参考菜鸟教程-File,这里就不再进行一一记录了。

需要注意的是,在使用open打开文件时,在操作结束后一定要保证文件关闭,即一定要调用close()。

    在很多时候,我们经常会忘记写file.close(),为了避免文件没有关闭,在打开文件的时候,我们可以使用with方法进行文件的打开。

with open(file,'r',encoding='utf-8') as fr:
	fr.readlines()
	……

    一般情况下,在读取文件内容的时候常用的三个方法就是read(),readline()和readlines(),这三个的区别与用法可以参考我的另一篇博客:python读取文件:read().readline(),readlines().

3.2 write()

    write方法是文件的写入操作,其基本语法结构为:

open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
  • file: 必需,文件路径(相对或者绝对路径)。
  • mode: 可选,文件打开模式
  • buffering: 设置缓冲
  • encoding: 一般使用utf8
  • errors: 报错级别
  • newline: 区分换行符
  • closefd: 传入的file参数类型
        文件的写入操作同样在操作结束后,调用close()方法,与open()方法一样,可以使用with语句进行简化:
with open(file,'w',encoding='utf-8') as fw:
	fw.write()
	……

    文件操作过程中,不论是读还是写,需要注意的就是编码文件的编码格式,编码格式是最容易出错的地方。

3.3 os模块

    os模块在平时操作文件和目录中也是非常常用的一个模块,该模块提供了很多方法用于满足我们在变成过程中的各种文件目录操作的需求。
    具体方法可以参考菜鸟教程-os模块。具体方法就不记录了。

写在最后

    本文是个人的一些学习笔记,如有侵权,请及时联系我进行删除,谢谢大家.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值