函数式编程
1、几个高阶函数
(1)mapmap(函数,Iterable)
结果是一个Iterator,Iterator是惰性序列,因此通过list()函数让它把整个序列都计算出来并返回一个list。
将传入的函数依次作用到序列的每个元素
例子:
>>> def f(x):
… return x * x
…
>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> list(r)
[1, 4, 9, 16, 25, 36, 49, 64, 81]
(2)reducereduce(函数,Iterable)
除了函数必须是两个参数,其他都和map函数相同
(3)filtersfilters(函数,Iterable)
类似于map()
把传入的函数依次作用于每个元素,根据返回值是True还是False决定每个元素的去留
其余的和map一样
(4)sorted对list进行排序
接收一个key函数来实现自定义的排序
>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]
>>> sorted([‘bob’, ‘about’, ‘Zoo’, ‘Credit’], key=str.lower)
[‘about’, ‘bob’, ‘Credit’, ‘Zoo’]
>>> sorted([‘bob’, ‘about’, ‘Zoo’, ‘Credit’], key=str.lower, reverse=True)
[‘Zoo’, ‘Credit’, ‘bob’, ‘about’]
2、返回函数和闭包一个函数可以返回一个计算结果,也可以返回一个函数。
返回一个函数时,牢记该函数并未执行,返回函数中不要引用任何可能会变化的变量。
返回函数(廖雪峰)
3、匿名函数(lambda)lambda 函数参数:函数体
例子:lambda x : x * x
4、装饰器在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
例子:装饰器
5、偏函数当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。
模块
这里只笔记一个我自己平常混淆的点:
模块搜索路径
默认情况下,Python解释器会搜索当前目录、所有已安装的内置模块和第三方模块,搜索路径存放在sys模块的path变量中:
>>> import sys
>>> sys.path
[”, ‘/Library/Frameworks/Python.framework/Versions/3.6/lib/python36.zip’, ‘/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6’, …, ‘/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages’]
如果我们要添加自己的搜索目录,有两种方法:
一是直接修改sys.path,添加要搜索的目录,这种方法是在运行时修改,运行结束失效。
>>> import sys
>>> sys.path.append(‘/Users/michael/my_py_scripts’)
第二种方法是设置环境变量PYTHONPATH,该环境变量的内容会被自动添加到模块搜索路径中。设置方式与设置Path环境变量类似。注意只需要添加你自己的搜索路径,Python自己本身的搜索路径不受影响。
面向对象编程面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行。为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度。
而面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。
面向对象的抽象程度又比函数要高,因为一个Class既包含数据,又包含操作数据的方法
1 类和实例实例的创建:实例=类名()
__init__方法:第一个参数永远是self,表示创建的实例本身,因此在__init__方法内部,就可以绑定各种属性,因此有了__init__方法,在创建实例的饿时候就必须传入和self方法匹配的参数,self不需要穿,python解释器会自动吧实例变量传进去.
和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,并且,调用时,不用传递该参数。除此之外,类的方法和普通函数没有什么区别,所以,你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。
数据封装:在类内部定义访问数据的函数,这样就相当于把数据封装起来了.
2 访问限制(单下划线,双下划线,首位双下划线)
在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑。如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问.这样就确保了外部代码不能随意修改对象内部的状态,这样通过访问限制的保护,代码更加健壮.
在Python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,
以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。
3 继承和多态子类—–基类/父类/超类
当子类和父类都存在相同的run()方法时,我们说,子类的run()覆盖了父类的run(),在代码运行的时候,总是会调用子类的run()。这样,我们就获得了继承的另一个好处:多态。
在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。但是,反过来就不行
继承可以把父类的所有功能都直接拿过来,这样就不必重零做起,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写。
4 获取对象信息type():基本类型,函数或者类,判断一个对象是否是函数怎么办?可以使用types模块中定义的常量
>>> import types
>>> def fn():
… pass
…
>>> type(fn)==types.FunctionType
True
>>> type(abs)==types.BuiltinFunctionType
True
>>> type(lambda x: x)==types.LambdaType
True
>>> type((x for x in range(10)))==types.GeneratorType
Trueisinstance(),可以用type() 判断的基本类型也可以用这个方法进行判断,并且还可以判断一个变量是否是某系变量的一种.
dir(),获得一个对象的所有属性和方法
getattr()、setattr()以及hasattr(),可以直接操作一个对象的状态
5 实例属性和类属性给实例绑定属性的方法是通过实例变量,或者通过self变量
类本身需要绑定可以直接在class中定义属性,这种属性是类属性,归Student类所有,但是所有的实例都可以访问.
实例属性属于各个实例所有,互不干扰;
类属性属于类所有,所有实例共享一个属性;
不要对实例属性和类属性使用相同的名字,否则将产生难以发现的错误。
面向对象高级编程给类/实例绑定属性和方法,可以在程序运行的过程中动态绑定,这个是动态语言的好处,在静态语言中很难实现.
1 使用__slots__限制实例的属性:
class Student(object):
__slots__ = (‘name’, ‘age’)
但是__slots__定义的属性仅仅对当前类实例起作用,对继承的子类不起作用.除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__。
2 @property广泛应用在类义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。
3 多重继承通过多重继承,一个子类可以同时获得多个父类所有的功能.
在设计类的继承关系时,通常,主线都是单一继承下来的,例如,Ostrich继承自Bird。但是,如果需要“混入”额外的功能,通过多重继承就可以实现,比如,让Ostrich除了继承自Bird外,再同时继承Runnable。这种设计通常称之为MixIn。
MixIn的目的就是给一个类增加多个功能,这样,在设计类的时候,我们优先考虑通过多重继承来组合多个MixIn的功能,而不是设计多层次的复杂的继承关系。
4 定制类
Python的class允许定义许多定制方法,可以让我们非常方便地生成特定的类。
__str__
__iter__
__getitem__
__getattr__:在没有找到属性的情况下,才调用__getattr__,已有的属性,比如name,不会在__getattr__中查找.
__call__:任何类,只需要定义一个__call__()方法,就可以直接对实例进行调用
class Student(object):
def __init__(self, name):
self.name = name
def __call__(self):
print(‘My name is%s.’ % self.name)
>>> s = Student(‘Michael’)
>>> s() # self参数不要传入
My name is Michael.
5 使用枚举类\
Enum可以把一组相关常量定义在一个class中,且class不可变,而且成员可以直接比较。
6 使用元类
错误 调试 测试
错误try:
except:
except:
else:
finally:
logging
raise
调试
(1)print 直接打印出来查看
(2)assert,断言.AssertionError,启动Python解释器时可以用-O参数来关闭assert:python -O err.py,关闭后,你可以把所有的assert语句当成pass来看
(3)logging,不会抛出错误,而且可以输出到文件
import logging
logging.basicConfig(level=logging.INFO)
这就是logging的好处,它允许你指定记录信息的级别,有debug,info,warning,error等几个级别,当我们指定level=INFO时,logging.debug就不起作用了。同理,指定level=WARNING后,debug和info就不起作用了。这样一来,你可以放心地输出不同级别的信息,也不用删除,最后统一控制输出哪个级别的信息。
(4)pdb
启动Python的调试器pdb,让程序以单步方式运行,可以随时查看运行状态python -m pdb err.py
输入命令-l来查看代码
输入命令n可以单步执行代码
输入命令p 变量名来查看变量
输入命令q结束调试,退出程序
pdb.set_trace()
这个方法也是用pdb,但是不需要单步执行,我们只需要import pdb,然后,在可能出错的地方放一个pdb.set_trace(),就可以设置一个断点:
# err.py
import pdb
s = ‘0’
n = int(s)
pdb.set_trace() # 运行到这里会自动暂停
print(10 / n)
可以用命令p查看变量,或者用命令c继续运行
$ python err.py
> /Users/michael/Github/learn-python3/samples/debug/err.py(7)()
-> print(10 / n)
(Pdb) p n
0
(Pdb) c
Traceback (most recent call last):
File “err.py”, line 7, in
print(10 / n)
ZeroDivisionError: division by zero
(5)IDE
单元测试
文档测试
进程和线程
1多进程
2 多线程
3 TreadLocal
4 进程 vs 线程
5 分布式进程
IO编程
1 文件读写
2 StringIO和BytesIO
3 操作文件和目录
4 序列化
正则表达式
常用的内建模块