《Python编程轻松进阶》干货整理
最近把《Python编程轻松进阶》看完了,看得过程中顺便整理了一些自己觉得比较重要的点,分享出来,共同进步!
文章目录
第一章 处理错误和寻求帮助
1.1 如何查看模块版本
import django
django.__version__
第二章 环境设置和命令行
2.1 使用pathlib库可以让Python脚本跨平台兼容
或者使用r’路径名’的形式
>>> from pathlib import Path
>>> Path('spam') / 'bacon' / 'eggs'
WindowsPath('spam/bacon/eggs')
2.2 Path常用命令
获取主目录
# 获取主目录
Path.home()
# 获取当前目录
Path.cwd()
os.getcwd()
# 更改当前目录
os.chdir('路径名')
.\ 指代当前目录,…\ 指代父目录
2.3 命令行参数
如果文件名包含空格,需要用""括起来——cd “my path”
2.3.1 /?
xx /?用于呈现xx命令的相关信息
2.3.2 python -c
python -c用于运行无需保留的python代码
python -c “print(‘Hello World’)”
2.3.3 help()
查询指定函数的输出
python -c "help(len)"
2.3.4 py -版本号
运行指定版本的python
py -3.6 -c "import sys;print(sys.version)"
2.3.5 subprocess模块
用于在python程序内运行shell命令(对应书中第23页)
2.3.6 doskey/history
命令行输入doskey/history可以查看命令历史记录
2.4 常用命令
2.4.1 通配符 * and ?
*用于匹配任意数量的字符,?用于匹配任何单个字符
dir *.py——查看当前目录下的所有.py文件
2.4.2 列举文件夹内容
Tips:多行代表上面为windows命令,下面为linux命令
显示当前目录以及子目录下的文件
dir /s [文件名]
find . -name [文件名]
2.4.3 复制文件/文件夹
copy [源文件] [目标文件]
cp [源文件] [目标文件]
2.4.4 移动文件/文件夹
move [源文件] [目标文件]
mv [源文件] [目标文件]
2.4.5 重命名文件/文件夹
ren [文件/文件夹] [新名称]
mv [文件/文件夹] [新名称]
2.4.6 删除文件/文件夹
del 不会删除任何子文件夹中的文件
# 对文件夹用,仅删除文件
del [文件/文件夹]
# 删除文件夹以及其中的文件
rd /s /q [文件夹] # windows
rm -r [文件夹] # linux
# 仅删除文件夹,且必须保证里面是空的
rd [源文件夹] # windows
rmdir [源文件夹] # linux
2.4.7 创建文件夹
md [新文件夹]
mkdir [新文件夹]
2.4.8 查找程序
where [程序名]
which [程序名]
2.4.9 清除终端内容
cls
clear
2.5 环境变量和path
查看环境变量列表
set
查看单个环境变量的值
echo %HOMEPATH%
echo $HOME
修改当前终端窗口的环境变量(仅在当前窗口有效)
path [文件夹路径];%PATH%
PATH=[文件夹路径]:$PATH
永久修改系统PATH变量(需要管理员身份运行命令行)
setx /M PATH "[文件夹路径];%PATH%" # windows
export [文件夹路径];%PATH% # linux,修改.bashrc文件
第五章 揪出代码的坏味道
5.1 创建日志文件
import logging
logging.basicConfig(filename='logging_filename.txt',
level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s')
logging.debug('This is a log message')
5.2 如果类中只包含静态方法,推荐编写函数
第六章 编写Python风格的代码
6.1 timeit模块衡量性能
import timeit
print(timeit.timeit('a=42;b=101;a,b=b,a;'))
# 测试生成1千万个随机数要多久
print(timeit.timeit('random.randint(1,100)','import random', number=10000000))
6.2 with open代替open()和close()
with open会自动调用close
with open() as filename:
filename.write()
6.3 字典的妙用
6.3.1 为字典中不存在的键设置默认值
dict_test = {'a': 1}
dict_test.setdefault('b', 0)
dict_test['b'] += 1
需要对任意键设置默认值,推荐使用collections.defaultdict
from collections import defaultdict
dict_test = defaultdict(int)
==判断值是否相同
is判断身份是否相同,x is y 相当于id(x) == id(y)
第七章 编写Python风格的代码
class语句创建自定义数据类型时,只要实现__iter__和__next__两个特殊方法,就能用for循环遍历
SDK是指软件开发套件(software development kit, SDK),包括代码库、文档和软件工具
第八章 常见的Python陷阱
Python的赋值是复制了对象的引用,而非对象本身
如果想复制对象本身,需要用copy.copy()或者copy.deepcopy()
import copy
bacon = [1, 2, 3]
ham = copy.copy(bacon)
# 注意,如果列表中嵌套了列表,那么copy()不会复制嵌套列表的本身,因此推荐使用deepcopy()
bacon = [[1, 2], [3, 4]]
ham = copy.deepcopy(bacon)
8.1 不要通过字符串连接创建字符串
字符串是不可变对象,每次修改字符串相当于新建了一个对象
因此循环中对字符串进行连接时,可以考虑将字符串append到列表中,最后对列表进行’'.join()操作,速度会快很多
8.2 通过sort(key=str.lower())实现按照字母排序
8.3 通过decimal.Decimal()可以描述精确的浮点数
书中P133
第九章 Python的奇妙难懂之处
False == False in [False]
# 相当于 (False == False) and (False in [False]),返回True
单下划线开头的变量、函数或方法代表伪私有,双下划线代表真正的私有
class Product:
def __init__(self, price):
self.price = price
@property
def price(self):
return self.__price
# 不设置setter表示Price是一个只读属性
@price.setter
def price(self, value):
if value < 0:
raise ValueError("Price cannot be negative.")
self.__price = value
9.1 抽象基类无法实例化
from abc import ABC, abstractmethod
class Stream(ABC):
@abstractmethod
def read(self):
pass
class MemoryStream(Stream):
pass
stream = Stream() # 会报错,抽象基类不准实例化
memory_stream = MemoryStream() # 会报错,因为子类没有实现read这个抽象方法
9.2 Python可以很方便地扩展基本类型
class Text(str):
def duplicate(self):
return self + self
class TrackableList(list):
def append(self, __object):
print("Append called")
super().append(__object)
lst = TrackableList()
lst.append(1)
text = Text("Python")
print(text.duplicate())
9.3 如果类只有数据没有方法,可以使用namedtuple来减少代码编写
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p1 = Point(x=1, y=2)
p2 = Point(x=1, y=2)
print(p1 == p2) # True
p1.x = 10 # 会报错,不能设置属性的值
9.4 pathlib模块
from pathlib import Path
path = Path("foo/__init__.py")
path.exists()
path.is_file()
path.is_dir()
print(path.name) # 返回文件名
print(path.stem) # 返回文件前缀
print(path.suffix) # 返回文件后缀
print(path.parent)
# 修改文件名
path = path.with_name("foo.txt")
print(path)
# 修改path后缀
path = path.with_suffix(".py")
print(path)
9.5 zipfile模块
from zipfile import ZipFile
with ZipFile("files.zip") as zip:
print(zip.namelist())
zip.extractall("extract") # 解压到指定目录
第十一章 注释、文档字符串和类型提示
11.1 如果想要类型包含NoneType,可以使用Optional
Optional[str]代替Union[str, None]
第十二章 通过Git管理项目
12.1 将提交历史缩减到一行
git log --oneline
12.2 输出指定数目的提交
git log --oneline -n 3
12.3 撤销未提交的本地修改
一旦运行了,就不能撤销这个操作
git restore [文件名]
12.4 取消暂存的文件
git add之后,如果想将其从暂存区中移除
git restore --staged [文件名]
12.5 回滚到指定数目之前的提交
其中3是要回滚的提交数量
git revert -n HEAD~3..HEAD
12.6 回滚单个文件的某次提交
回滚完这个文件之后,要add + commit
git checkout [commit hash] -- [文件名]
12.7 将已经存在的仓库推送至github
git remote add origin https://github.com/williamklzz/wizcoin.git
git push -u origin master
第十三章 性能测量和大O算法分析
13.1 cProfile分析器
用于测量程序的运行时间和程序内各个函数调用消耗的时间——Page 206
import time, cProfile
def add_up_numbers():
total = 0
for i in range(1, 1000001):
total += i
cProfile.run('add_up_numbers()')
第十五章 面向对象编程和类
>> type(42)
>> <class 'int'>
>> type(42).__qualname__ # 使结果更可读,常用来覆盖__repr__()方法
>> 'int'
第十六章 面向对象编程和类
>> isinstance(42, (int, str, bool)) # 检查42是否是3种类型的其中一种
>> True
类特性是从属于类的变量,所有类对象共享这个特性(类特性很少使用)
from tictactoe_with_OOP import *
>> print(HybridBoard.mro()) # 多继承时获取类方法的调用顺序
>> [<class 'tictactoe_with_OOP.HybridBoard'>, <class 'tictactoe_with_OOP.HintBoard'>, <class 'tictactoe_with_OOP.MiniBoard'>, <class 'tictactoe_with_OOP.TTTBoard'>, <class 'object'>]
第十七章 属性和魔术方法
17.1 什么时候要使用属性(@property)(P 291)
# 当我希望每次访问这个特性时,使用赋值语句修改或del删除时,都能运行一段代码
# _some_attribute被称为幕后变量,getter、setter、deleter应该总是作用于幕后变量
# some_attribute是属性
class ClassWithProperties:
def __init__(self):
self.some_attribute = 'some initial value'
@property
def some_attribute(self): # 这是getter方法
return self._some_attribute
@some_attribute.setter
def some_attribute(self, value): # 这是setter方法
self._some_attribute = value
@some_attribute.deleter
def some_attribute(self): # 这是deleter方法
del self._some_attribute
obj = ClassWithProperties()
print(obj.some_attribute)
obj.some_attribute = 'change value'
print(obj.some_attribute)
del obj.some_attribute
# 最佳实践,当WizCoin类被误用时抛出异常,如果抛出了其他异常,说明不是使用的问题,而是类本身的问题
# value.__class__相当于type(value),.__qualname__可以省去class,让输出更简洁
class WizCoinException(Exception):
"""当wizcoin模块被错误使用时,抛出此错误"""
pass
class WizCoin:
def __init__(self, galleons: int, sickles: int, knuts: int):
self.galleons = galleons
self.sickles = sickles
self.knuts = knuts
@property
def galleons(self):
return self._galleons
@galleons.setter
def galleons(self, value):
if not isinstance(value, int):
raise WizCoinException(
f'galleons attr must be set to an int, not a {value.__class__.__qualname__}'
)
if value < 0:
raise WizCoinException(
f'galleons attr must be a positive int, not {value.__class__.__qualname__}'
)
self._galleons = value
# 通过添加property可以让属性变为只读属性
@property
def value(self) -> int:
return (self.galleons * 17 * 29) + (self.sickles * 29) + self.knuts
def weight_in_grams(self) -> float:
"""返回硬币的重量,单位为克"""
return self.galleons * 31.103 + self.sickles * 11.34 + self.knuts * 5.0
17.2 字符串魔术方法
# __repr__和__str__
class WizCoin:
--snip--
def __repr__(self):
"""返回一个可以重新创建该对象的表达式的字符串"""
return f'{self.__class__.__qualname__}{self.galleons, self.sickles, self.knuts}'
def __str__(self):
"""返回一个可以重新创建该对象的表达式的字符串"""
return f'{self.galleons}g, {self.sickles}s, {self.knuts}k'
17.3 数值魔术方法
不应该在数值魔术方法里改变对象本身,而是应该创建一个新对象
class WizCoin:
--snip--
def __add__(self, other):
"""将两个WizCoin对象中的硬币数量相加"""
if not isinstance(other, WizCoin):
return NotImplemented # NotImplemented 是一个信号,表示某个操作或方法尚未实现或不支持当前的操作数类型
return WizCoin(
self.galleons + other.galleons,
self.sickles + other.sickles,
self.knuts + other.knuts,
)
def __mul__(self, other: int) -> 'WizCoin':
"""将硬币的数量乘以一个非负整数"""
if not isinstance(other, int):
return NotImplemented
if other < 0:
# 不能乘复数
raise WizCoinException('cannot multiply with negative integers')
return WizCoin(self.galleons * other, self.sickles * other, self.knuts * other)
# 如果符合交换律,可以直接调用__mul__方法
def __rmul__(self, other):
"""反射数值魔术方法,将硬币乘以非负整数"""
return self.__mul__(other)
17.3.1 P296 全部数值魔术方法表
17.4 反射数值魔术方法 P299
当对象在数学运算符的左边时,Python调用数值魔术方法,而当对象在数学运算符的右边时,Python调用反射数值魔术方法
# 如果不写__rmul__方法
>> wiz_coin = WizCoin(5, 10, 10)
>> wiz_coin * 10 # 正常乘
>> 10 * wiz_coin # 会报错,TypeError: unsupported operand type(s) for *: 'int' and 'WizCoin'
17.5 原地魔术方法
增强赋值运算符(+=、*=)是原地修改对象
class WizCoin:
--snip--
def __iadd__(self, other: 'WizCoin'):
"""将另一个WizCoin对象加到当前对象中"""
if not isinstance(other, WizCoin):
return NotImplemented
# 原地修改self
self.galleons += other.galleons
self.sickles += other.sickles
self.knuts += other.knuts
return self # 原地魔术方法大多数情况下返回self
def __imul__(self, other: int):
"""将硬币的数量乘以一个非负整数"""
if not isinstance(other, int):
return NotImplemented
if other < 0:
return WizCoinException('cannot multiply with negative integers')
self.galleons *= other
self.sickles *= other
self.knuts *= other
return self