Python3代码示例:基本操作

发布于:2018-02-07 | 分类:python/vba/cpp


链式比较

区间判断时可以使用更为直观的链式比较:

score = 88
if 80<score<90:
    print("come on...")
# come on...

解压可迭代对象

使用赋值语句可以解压可迭代对象(元组、列表、字符串等)并将各个元素分别赋值给多个变量。

x,y = 3,5
x,y = y,x
# x=5, y=3
x,y = y, x+y
# x=3, y=8

L = [1,2,(3,4)]
a,b,c = L
# a=1,b=2,c=(3,4)

变量的数量必须跟序列元素的数量一样,否则会产生ValueError异常。

p = (4, 5)
x, y, z = p
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: need more than 2 values to unpack

当确实需要以较少数量的变量去解压更多元素的可迭代对象时,可以使用 星号表达式。其效果类似于函数的可变位置参数 *argv

x,*y,z = [3,5,7,9]
# x=3, y=[5,7], z=9

# 注意解压出的变量y为列表类型,即便元素数量可能为0
x,*y,z = [3,5]
# x=3, y=[], z=5

# *x将x解压为(1,2,3), (4,5,6), (7,8,9)
# 然后作为zip的参数
x=[[1,2,3],[4,5,6],[7,8,9]]
[list(item) for item in zip(*x)]
# [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

如果只想解压一部分而丢弃其他的值,可以使用任意变量名占位:

L = [1,2,(3,4)]
_, _, x = L
# x=(3,4)

遍历列表/元组

直接使用for...in语句遍历,结合reversed()sorted()函数可以按照需求顺序遍历:

colors = ['red', 'green', 'blue', 'yellow']

# 遍历列表
for color in colors:
    print(color)

# 反向遍历
for color in reversed(colors):
    print(color)

# 按字母排序遍历
for color in sorted(colors):
    print(color)

# 按字母逆序遍历
for color in sorted(colors, reverse=True):
    print(color)

# 自定义排序(例如字符串长度)遍历
for color in sorted(colors, key=len): # key可以使用lambda表达式
    print(color)    

使用enumerate()获取遍历元素的索引,使用zip()同时遍历多个列表:

colors = ['red', 'green', 'blue', 'yellow']
bodies = ['sphere', 'cylinder', 'block']

for i, color in enumerate(colors, start=100):
    print(i, '--->', color)    
# 100 ---> red
# 101 ---> green
# 102 ---> blue
# 103 ---> yellow

for body, color in zip(bodies, colors):
    print(body, '--->', color)
# sphere ---> red
# cylinder ---> green
# block ---> blue

遍历字典

# 从两个列表创建字典
colors = ['red', 'green', 'blue', 'yellow']
bodies = ['sphere', 'cylinder', 'block']
d = dict(zip(bodies, colors))
# d = {'sphere':'red', 'cylinder':'green', 'block':'blue'}

# 遍历字典
for k, v in d.items():
    print(k, '--->', v)

集合运算

集合的交、差、并运算:

x=set([1,2,4])
y=set([3,4,5])

x&y # 交集
# {4}
x-y # 差集
# {1, 2}
x|y # 并集
# {1, 2, 3, 4, 5}

字典是 键集合值集合 的映射关系。字典的keys()方法返回一个展现键集合的键视图对象。键视图也支持集合操作,所以可以直接使用键视图对象执行普通的集合操作。

a = {'x' : 1, 'y' : 2, 'z' : 3}
b = {'w' : 10, 'x' : 11, 'y' : 2}

# 两个字典的公共键
a.keys() & b.keys() # { 'x', 'y' }

# 仅在字典a中存在的键
a.keys() - b.keys() # { 'z' }

# 两个字典的公共元素
a.items() & b.items() # { ('y', 2) }

字典的items()方法同理,但是由于不能保证values()方法的所有值互不相同,故不能直接进行集合操作——不过可以先将值集合转换成 set,然后再执行集合运算。

列表推导式

列表推导式(List Comprehensions)是Python内置的一种生成列表的简洁方式,同理可以使用字典推导式、集合推导式。注意不存在元组推导式。

# 列表推导式:生成1-100的奇数
odd = [i for i in range(1, 100) if i%2]

# 字典推导式:统计字符数
word = 'hello word'
letter_counts = {letter: word.count(letter) for letter in word if letter.strip()}
# {'d': 1, 'w': 1, 'e': 1, 'r': 1, 'o': 2, 'l': 2, 'h': 1}

# 生成器推导式
# 
num_generator = (number for number in range(1, 6))
type(num_generator) # <class 'generotor'>
for number in num_generator:
    print(number)

列表推导式的一个潜在缺陷是当输入非常大时会产生一个非常大的结果集,占用大量内存;对应措施为使用生成器(generator)表达式。

  • 生成器表达式的一个非常优雅的应用是先转换或过滤数据,然后作为聚集函数如sum()min()max()的参数进行计算
  • 生成器仅在运行中产生值,再次使用时已被擦除
# 求平方和
nums = [1, 2, 3, 4, 5]
s = sum(x * x for x in nums)

# 判断是否存在某类型文件
import os
files = os.listdir('dirname')
if any(name.endswith('.py') for name in files):
    print('There be python!')
else:
    print('Sorry, no python.')   

当过滤规则比较复杂,不能简单地在列表推导式或生成器表达式中表达出来(例如过滤规则涉及异常)时,可以将过滤代码放到一个函数中,然后使用内建的filter()函数。filter()函数返回一个迭代器。

values = ['1', '2', '-3', '-', '4', 'N/A', '5']
def is_int(val):
    try:
        x = int(val)
        return True
    except ValueError:
        return False

ivals = list(filter(is_int, values))
# ['1', '2', '-3', '4', '5']

命名切片

过多的硬编码索引值将导致代码可读性和可维护性降低,使用内置的slice()函数创建切片对象,可以用在任何允许进行切片操作的地方。

items = [0, 1, 2, 3, 4, 5, 6]
last_two = slice(-2, None)
items[last_two]
# [5, 6]

else子句

for/while/try语句中的else子句将在循环/异常检测正常运行结束,即不是通过break/return语句或是异常退出时执行。

pools = [2,4,6]
for num in pools:
    if num%2:
        break
else:
    print("nothing found...")
# nothing found...    
# 如果try块仅需要防守dangerous_call()可能出现的错误,
# 那么为了清晰明确,after_call()应放在else子句执行
try:
    dangerous_call()
    after_call()
except OSError:
    log('OSError...')

# better    
try:
    dangerous_call()
except OSError:
    log('OSError...')
else:
    after_call()

上下文管理器

我们通常使用with...as语句来自动处理文件的打开和关闭,并且**上下文管理器可以同时管理多个资源**。

with open('input.txt', 'r') as source, open('output.txt', 'w') as target:
    target.write(source.read())

备注一下以上open()函数对于不同操作系统换行符的识别问题:

Unix和Windows中的换行符分别是\n\r\n,Python默认会以统一模式处理换行符——读取文本的时候,识别所有的普通换行符并将其转换为单个\n字符;输出文本时,将换行符\n转换为系统默认的换行符。

如果不希望这种默认的处理方式,可以给open()函数传入参数newline=''。例如Linux下执行如下代码:

with open('hello.txt', 'rt') as f:
    print(f.read())
# 'hello world!\n'

with open('hello.txt', 'rt', newline='') as f:
    print(f.read())
# 'hello world!\r\n'

自定义比较/排序

max()/min()/sorted()等全局函数可以通过key关键字指定比较/排序的标准。list的内置函数sort也具有类似使用方式:

# 统计列表中频数最高的元素
num = [1,2,2,3,3,3,4,4,4,4]
x = max(set(num), key=num.count)
# x=4

# 排序列表并获取排序后对应原来的索引
data = [2,4,5,3]
zip_data = list(zip(data, range(len(data))))
zip_data.sort(key=lambda x: x[0])
sorted_data, sorted_index = zip(*zip_data)
# sorted_data=(2, 3, 4, 5)
# sorted_index=(0, 3, 1, 2)