《Python编程轻松进阶》干货整理

《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

17.6 比较魔术方法 P305

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值