这里归纳了一些自己目前不够熟悉的Python基础知识/特性
切片
Python可切片对象的索引方式:
切片操作基本表达式:object[start_index:end_index:step]
step:正负数均可,其绝对值大小决定了切取数据时的‘‘步长”,而正负号决定了“切取方向”,正表示“从左往右”取值,负表示“从右往左”取值。当step省略时,默认为1,即从左往右以增量1取值。
start_index:表示起始索引(包含该索引本身);该参数省略时,表示从对象“端点”开始取值,至于是从“起点”还是从“终点”开始,则由step参数的正负决定,step为正从“起点”开始,为负从“终点”开始。
end_index:表示终止索引(不包含该索引本身);该参数省略时,表示一直取到数据“端点”,至于是到“起点”还是到“终点”,同样由step参数的正负决定,step为正时直到“终点”,为负时直到“起点”。
切片返回目标对象的浅拷贝
迭代
使用for k, v in d.items()可以同时迭代dict中的key和value:
使用enumerate()可以同时迭代元组的索引和元素:
>>> for i, value in enumerate(['A', 'B', 'C']):
... print(i, value)
...
0 A
1 B
2 C
生成器
迭代器
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator
可以使用isinstance()判断一个对象是否是Iterator对象
高阶函数
map/reduce
map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回
reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
filter
和map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素
sorted
Python内置的sorted()函数可以对list进行排序
sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序:
>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]
key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序。
偏函数
functools.partial()可以用来创建一个偏函数
python中偏函数的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。
>>> int('12345', base=8)
5349
>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
OOP访问限制
实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问:
class Student(object):
def __init__(self, name, score):
self.__name = name
self.__score = score
def print_score(self):
print('%s: %s' % (self.__name, self.__score))
多态
当子类和父类存在相同名称的方法时,子类的同名方法将覆盖父类的对应方法
调试
最简单的调试方法是使用print()来查看变量信息
print()的缺点是它将产生大量垃圾代码
所以,更进一步的方法是使用断言(assert)来替代print():
assert n != 0, 'n is zero!'
assert会检查后面的表达式的布尔值。如果为false,assert会抛出AssertionError
最成熟的调试方式是使用logging
import logging
logging.basicConfig(level=logging.INFO) # 配置控制台日志输出级别
logging.info("xxx")
单元测试
python自带的单元测试模块为:unittest
Python高级OOP
slots
Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性:
class Student(object):
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
>>> s = Student() # 创建新的实例
>>> s.name = 'Michael' # 绑定属性'name'
>>> s.age = 25 # 绑定属性'age'
>>> s.score = 99 # 绑定属性'score'
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'Student' object has no attribute 'score'
@property
为了实现既能检查参数,又可以用类似属性这样简单的方式来访问类的变量,Python提供了内置的@property装饰器来实现方法到属性的转换:
class Student(object):
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值
只定义getter方法,不定义setter方法就是一个只读属性
多继承
多继承又被称作MixIn
MixIn的目的就是给一个类增加多个功能,这样,在设计类的时候,我们优先考虑通过多重继承来组合多个MixIn的功能,而不是设计多层次的复杂的继承关系
Python自带的很多库也使用了MixIn。
Python自带了TCPServer和UDPServer这两类网络服务,而要同时服务多个用户就必须使用多进程或多线程模型,这两种模型由ForkingMixIn和ThreadingMixIn提供。通过组合,我们就可以创造出合适的服务来
比如,编写一个多进程模式的TCP服务,定义如下:
class MyTCPServer(TCPServer, ForkingMixIn):
pass
- 编写一个多线程模式的UDP服务,定义如下:
class MyUDPServer(UDPServer, ThreadingMixIn):
pass
定制类(魔法方法)
看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的
类似的方法还有:
len()方法能让class作用于len()函数
str()方法用于变更实例的print()内容
repr()方法用于变更实例在控制台的输出结果
iter()方法可以让实例变成迭代器
枚举类
元类
使用type,我们可以在程序中动态地创建类型,包括类,对象和函数等
元类的一个典型应用场景是ORM:
ORM全称“Object Relational Mapping”,即对象-关系映射,就是把关系数据库的一行映射为一个对象,也就是一个类对应一个表,这样,写代码更简单,不用直接操作SQL语句
要编写一个ORM框架,所有的类都只能动态定义,因为只有使用者才能根据表的结构定义出对应的类来