函数
基本概念
如果Python达到函数的尾部仍然没有遇到return语句就会自动返回None
def my_function(x, y, z=1.5):
if x > 0:
return x * y * z
else:
return x * y * (1 - z)
调用方法
my_function(1, 2, 10)
my_function(1, 2, -3)
my_function(1, 2)
函数参数包括位置参数和关键字参数。
1、位置参数指 x,y
2、关键字参数指 z,可以是默认值或可选参数
3、关键字参数必须跟在位置参数之后
4、按下述方式调用函数,可不必按照函数参数的顺序
my_function(x=1, y=2, z=10)
my_function(x=1, y=2)
def func():
a = []
for i in range(5):
a.append(i)
# 无法 print(a) 函数结束后 a 被销毁
# 正确写法
a = []
def func():
for i in range(5):
global a
# 必须加入global a 否则a为[]
a.append(i)
print(a)
返回多个值
def f():
a = 5
b = 6
c = 7
return a, b, c
# 实际返回了一个 (a, b, c)的元组
# 元组拆包
a, b, c = f()
print("a = {0} b = {1} c = {2}".format(a, b, c))
# 不拆包
return_value = f()
print(return_value)
a = 5 b = 6 c = 7
(5, 6, 7)
函数是对象
当清理一些凌乱数据时,常规方法如下:
import re
states = [' Alabama ', 'Georgia!!', 'georgia', 'south American#', 'West?']
def clean_strings(strings):
result = []
for value in strings:
value = value.strip()
# strip() 去除首尾所有空格 str.strip('0') 去除首位所有 0
value = re.sub('[!?#]', '', value)
# sub() 替代所有!?#
value = value.title()
# "标题化"字符串,就是说所有单词都是以大写开始,其余字母均为小写
result.append(value)
return result
print(clean_strings(states))
更好的写法,将函数看做对象放入列表,逐步完成函数,可以增强代码的复用性和通用性。
def remove_punctuation(value):
return re.sub('[!?#]', '', value)
clean_ops = [str.strip, remove_punctuation, str.title]
# 注意:无括号,不是strip() title()
def clean_strings(strings):
result = []
for value in strings:
for function in clean_ops:
function(value)
result.append(value)
return result
print(clean_strings(states))
也可以使用map()函数,map(function, iterable) 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值
for x in map(remove_punctuation, states):
print(x)
# map(function, iterable) 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。
匿名(Lambda)函数
匿名函数在数据分析中非常方便,将他作为函数参数进行传至,代码量小。
def apply_to_list(some_list, f):
return [f(x) for x in some_list]
ints = [1, 2, 3, 4, 5]
print(apply_to_list(ints, lambda x: x * x))
# f(x)可通过lambda改变
按照不同字母数量排序
strings = ['foo', 'card', 'car', 'aaaa', 'ababa', 'bar']
strings.sort(key=lambda x: len(set(list(x))))
# set过滤相同字母
print(strings)
柯里化
柯里化表示通过部分参数应用的方式从已有的函数中衍生出新的函数。
例如:有一个将两个数相加的函数,当我们定义x是5,那么y对于这个函数来说就柯里化了。
def add_numbers(x, y):
return x + y
add_five = lambda y: add_numbers(5, y)
print(add_five(3))
使用 functools 模块的 partial 可简化至下述代码:
from functools import partial
add_five = partial(add_numbers, 5)
迭代器
通过一致的方式遍历序列,这是Python的一个重要特性,例如:
tup = (1, 2, 3, 4, 5)
for value in tup:
pass
当写下 for value in tup 的语句时,Python解释器首先尝试根据 tup 生成一个迭代器:
tup_iterator = iter(tup)
迭代器就是一种用于在上下文中向Python解释器生成对象的对象。
print(list(tup_iterator))
[1, 2, 3, 4, 5]
生成器
生成器是构建新的可遍历对象的一种非常简洁的方式。普通函数执行并一次返回单个结果,而生成器则“惰性”地返回一个多结果序列,在每一个元素产生之后暂停,直到下一个请求。
如需创建一个生成器,只需要在函数中将返回关键字 return 替换为 yield 关键字:
def squares(n=10):
print('Generating squares from 1 to {0}'.format(n ** 2))
for i in range(1, n+1):
yield i**2
实际调用生成器时,代码并不会立即执行
gen = squares()
直到你请求生成器中的元素时,他才会执行他的代码:
for x in gen:
print(x, end=' ')
Generating squares from 1 to 100
1 4 9 16 25 36 49 64 81 100
生成器表达式
用生成器表达式来创建生成器更为简单。生成器表达式与列表、字典、集合的推导式很类似。
def squares(n=10):
print('Generating squares from 1 to {0}'.format(n ** 2))
for i in range(1, n+1):
yield i**2
等价于
gen = (x**2 for x in range(100))
在很多情况下,生成器表达式可以作为函数参数用于替代列表推导式:
dict = dict((i, i**2) for i in range(5))
print(dict)
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
itertools 模块
itertools 适用于大多数数据算法的生成器集合
如下按照首字母分类
import itertools
first_letter = lambda x: x[0]
names = ['Alan', 'Adam', 'Wes', 'Will', 'Steven']
for letter, names in itertools.groupby(names, first_letter):
print(letter, list(names))
A ['Alan', 'Adam']
W ['Wes', 'Will']
S ['Steven']
错误和异常
f = open(path,'w')
try:
write_to_file(f)
except:
# 出现异常时执行
print('Failed')
else:
# 成功运行时执行
print('Succeeded')
finally:
# 最后执行
f.close()
文件和操作系统
默认情况下,文件是以只读模式 ‘r’ 打开的
path = 'examples/a.txt'
f = open(path)
# 之后我们可以像处理列表一样处理文件
for line in f:
pass
# 等价于 ↓
lines = [x for x in f]
print(lines)
f.close()
等价于下述代码,with代码块结束后,会自动关闭文件,即 f.close()
with open(path) as f:
# f = open(path)
lines = [x for x in f]
访问模式 | 说明 |
---|---|
mode=‘r’ | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 |
mode=‘w’ | 打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
mode=‘a’ | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
mode=‘rb’ | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。 |
mode=‘wb’ | 以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
mode=‘ab’ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
mode=‘r+’ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
mode=‘w+’ | 打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
mode=‘a+’ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
mode=‘rb+’ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。 |
mode=‘wb+’ | 以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
mode=‘ab+’ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
对于可读文件,最常用的方法如下:
方法 | 用途 |
---|---|
read([size]) | 从文件中读取size个字节或字符的内容返回。若省略[size],则读取到文件的末尾,即一次读取文件所有内容。 |
readline() | 从文本文件中读取一行内容。 |
readlines() | 把文本文件中每一行都作为独立的字符串对象,并将这些对象放入到列表返回。 |
write(str) | 将字符串str内容写入文件。 |
writelines(s) | 将字符串列表s写入文本文件,不添加换行符。 |
tell() | 返回文件指针的当前位置。 |
flush() | 把缓冲区的内容写入文件,但不关闭文件。 |
close() | 把缓冲区内容写入文件,同时关闭文件,释放文件对象相关资源。 |
truncate([size]) | 不论指针在什么位置,只留下指针前size个字节的内容,其余全部删除;如果没有传入size,则当指针当前位置到文件末尾内容全部删除。 |
seek(offset[,whence]) | 把文件指针移动到新的位置 |
# 文本内容:姓名姓名姓名姓名姓名1234567890
with open(path) as f:
print(f.read(10))
print(f.tell())
f.seek(20)
print(f.read(10))
姓名姓名姓名姓名姓名
20
1234567890
尽管我们从文件中读取了10个字符,但是当前句柄的位置是20,这是因为使用默认编码的情况下需要这么多字节来对10个字符进行解码。