Python技巧笔记

Python技巧总结

  1. 正确使用True和False的判断
false_value = [
	[],
	{},
	False,
	'',
	0,
	0.0,
	None,
]


for x in false_value:
	print(True if value else False)

  1. 正确返回None值
    一个函数里面可能多个返回值都为True或False,这时候就要用is明确指定返回值,如None

  2. if条件优化

  • 直接判断——效率最低
  • in list 列表判断——效率最高,推荐
  • in set 集合——效率居中
  1. 字符串格式化技巧
  • 直接拼接
  • '{}'.format
  • '%s'%()
  • python3.6+, f'I'm {age}'推荐
  1. Flat is better than nested
  • import this可以打印python之禅
  • nested 指的是if 嵌套、一层层包裹,不推荐
  • flat要代码扁平化,用if、 elif,避免多个if,不满足条件直接返回,推荐
  1. 列表解析,也就是列表推导式
    除了减少代码量之外,还能提高运行效率,时间接近原来的一半
    示例:
[item for item in items if item%2 == 0]
  1. 字典解析
    示例:
a = [1, 2, 3, 4, 5, 6]
{item:str(item) for item in a}
  1. 字典合并
  • 循环添加,也可以字典解析,但并不推荐
  • update更新,d1.update(d2)
  • python3.5+, {**d1, **d2, **d3}推荐
  1. 字典安全访问
  • try-except抛出异常
  •   # 默认空返回None,也可以设置
      d.get('name','unkown')
       ```推荐
    
  • python内置defaultdict
from collection import defaultdict
d_new = defaultdict(lamda:'missing', d)
d_new['name'] # 返回name对应的
d_new['asdf'] # 不存在则返回missing
  1. 关于for循环,类中实现for循环
  • 示例
class A:
	def __init__(self):
		self.data = []
	def add(self, x):
		self.data.append(x)

	def __iter__(self):
		# return self.data.__iter__()
		# 这里也可以加一个for循环
		for item in self.data:
			yield item

class B():
	def __init__(self, x, y):
		self.x = x
		self.y = y

b1 = B(x=1, y=2)
b2 = B(x=3, y=4)

a = A()
a.add(b1)
a.add(b2)

for item in a:
	print(item.x, item.y)
  1. 为什么要使用yield
    一次性读取可能会占用太多内存,yield可以提高效率

  2. 如何在递归调用中使用yield
    示例:

import os
path = ''
def get_file(folder_name):
	for item in os.listdir(folder_name):
		full_path = os.path.join(folder_name, item)
		if os.path.isfile(full_path):
			yield full_path
		elif os.path.isdir(full_path):
			# 方法一
			for item in get_file(full_path):
				yield item
			# 方法二,python3
			yield from get_file(full_path)
for file_name in get_file(path):
	print(file_name)
  1. 巧用lambda
    函数参数为函数时,可以考虑能否用lambda实现
    Jupyter shift+tab可以查看信息,比如sort排序传入key

  2. 处理程序中的异常
    try-except,可以具体抛出某些异常。
    总的如except Exception as e:
    具体的如except DNSError:

  3. 函数默认参数
    为函数参数设置默认值

  4. 可变数量参数

def function(x, *args):
	print(args)

function(1,2,3,4)
# 结果
[2, 3, 4]

# 注意: 使用```*args```之后,x就不能赋值了,否则会报错SyntaxError
# 当如下形式时,x必须赋值,否则会报错TypeError:

def function(*args, x):
	print(args, x)

function(1,2,x=3)
  1. 字典和**kwargs的关系
    实现可变数量位置参数
def function(x, **kwargs):
	print(x, kwargs)

function(x=1, a=2, b=3, c=4)

# 运行结果
1 {'a':2, 'b':3, 'c':4}

def sum1(x, y):
	print(x+y)

sum(x=1, y=2)

sum(**{'x':1, 'y':'2'})
传入参数```**{'x':1, 'y':2}```与传入参数```x=1, y=2```返回结果一样
  1. 默认参数陷阱
    不建议用列表作为参数
def bad_default_arg(s, time, target=[]):
	for _ in range(time):
		target.append(a)
	return target

bad_default_arg(s='a', time=3) # 返回 ['a', 'a', 'a']
bad_default_arg(s='b', time=3, target='a') # 返回 ['a', 'b', 'b', 'b']
bad_default_arg(s='AB', time=2) # 返回 ['a', 'a', 'a', 'AB', 'AB']
# 使用列表作为参数时,假如不指定,则会使用上一次的默认值
bad_default_arg(s='F', time=2) # 返回 ['a', 'a', 'a', 'AB', 'AB', 'F', 'F']

解决方法:

def good_default_arg(s, time, target=None):
	if target is None:
		target = []
	for _ in range(time):
		target.append(a)
	return target
  1. 尽量避免使用from xxx import *
    库中方法可能与已命名方法重名,建议用什么引入什么

  2. 合理使用virtualenv与pip

    • 进入文件,virtualenv --python3.6 env 创建虚拟环境
    • 激活环境, source env/bin/activate
    • 安装使用的库
    • pip freeze,把已安装的库写入txt文件里
    • 退出环境, deactivate
    • pip install -r xxx.txt 安装所有的依赖
  3. 类的属性和实例属性

    • class类中定义属性,尽量在__init__下定义
    • 或者在class下定义
  4. 类实例的受保护属性和私有属性

    • 加一个下划线_,仍然可以被访问,即受保护
    • 加两个下划线__,无法被访问,即私有,但是实际上还是可以访问的,只不过名字编程了_类名__属性名
class A(object):
	"""docstring for A"""
	def __init__(self, name, age):
		super(A, self).__init__()
		self.__name = name
		self.__age = age 

a = A(name='python', age=27)

a.__age  # 无法被访问
		
  1. 使用类的property
    访问类的属性,需要property,但是是只读的
    要修改的话,可以定义setter
class B:
	def __init__(self, name, age):
		self.__name = name
		self.__age = age

	@property
	def name(self):
		return self._name
	
	@property
	def age(self):
		return self._age
	
	@age.setter
	def age(self, value):
		self.__age = value

	def __str__(self):
		print('My name is {} and my age is {}'.format(self.__name, self.__age))

b = B('Demo', 30)
print(b)

b.age = 40 # 可以修改
  1. tuple元组技巧
    • 同时赋值,保证个数一致
    • enumerate(),将列表变为元组
a = [1, 2, 3, 4]
for item in enumerate(a):
	print(item)

# 返回01)
(12)
(23)
(34
  1. 特殊元组namedtuple
import collections
Student = collections.namedtuple('Student', 'id, name, score')
students = [
	Student(1, 'ABC', 90),
	Student(2, 'XYZ', 85),
	Student(3, 'asdf', 80)
]

# 调用
for s in students:
	print('name={}, id={}, score={}'.format(s.name, s.id, s.score))

提高可读性及可维护性,效率并无太大区别

  1. dict和zip
    创建字典
# 1
dict(a=1,b=2)

# 2
data = (('a':1), ('b':2)) # 只要是可迭代对象都行
dict(data)

# 3
# 两个元素数量相同的列表
dict(zip(x,y))  # 生成对应字典
  1. 字典按照key/value大小排序

    dict(sorted(d.items(), key=lambda x:x[1], reverse=True))

  2. 通过debug学习Python生成器
    yield生成器

  3. string操作技巧

s = ' Last Checkpoint: a few seconds ago (unsaved changes) '
最好是链条式做完,而不是一个一个做
  1. 列表解析取代map和filter

  2. 上下文管理
    with open

  3. 一个单独的下划线可以怎么用

    • for循环中,不使用i,可用_代替
    • 输入1+2返回3,实际上3就赋值给了_
    • 取用列表或元组的元素时,无关紧要的可用_代替
  4. __str__和__repr__区别

class Person:
	def __init__(self, name, age):
		self.name = name
		self.age = age
	def __str__(self):
		return f'name={self.name}, age={self.age}'
	def __repr__(self):
		return f'name:{self.name}, age:{self.age}'

p = Person('Python', 27)
print(p)  # 先找__str__没有再找__repr__,都没有打印地址

p # 命令行中输入p,有__repr__才能返回值,否则返回地址
  1. 定义自己的exception
from exception import NameTooShort

def validate(name):
	if len(name) < 10:
		raise NameTooShort('Name is too short.')

try:
	validate('test')
except NameTooShort as e:
	print(e)

# exceprion.py 文件下
class NameTooShort(ValueError):
	pass
# 多个错误可以定义一个基类继承自Exception,其他错误都继承这个基类
  1. mypy做静态类型检查
def sum(x: int, y: int) -> int: # x、y都是int对象,函数返回int对象
    return x + y

if __name__ == '__main__':
    print(sum('1', '2')) # 并不会报错,用mypy会提示希望是int,但却是str类型

  1. 改进的namedtuple
# python3.6+
from typing import NmaedTuple

class Car(NmaedTuple):
	color: str
	mileage: float
	automatic: bool
	# 以上类型只是建议,不用对应的类型也不会报错,mypy会报错

car = Car('red', '100.01', False)
car.mileage = 100 # 会报错,因为不支持修改数据

  1. 用哪种数据结构存储数据

    • 为了简单用dict或tuple,字典数据得不到保护,元组数据顺序不能乱
    • class,灵活,但是普通class属性还是可以改变的,也可以添加属性
    • NamedTuple,定义子类,得到有效保护
  2. Python3.7+ Data Class

from dataclasses import dataclass

@dataclass
class NewPeple:
	name: str
	age: int
	# 仅仅是提示

p1 = NewPeple('A', 20)
p2 = NewPeple('A', 20)

print(p1, p2) # 普通类还要重写__str__ ,__repr__
print('p1=p2?', p1==p2) # 普通类需要重写__eq__


你可能感兴趣的:(Python)