python学习笔记(自用)

笔记

删除列表的重复元素:

	list(set(list_1))//先转化成集合,再换回数组
  1. Python的变量没有数据类型,变量也不需要声明,但使用前要初始化
  2. type()函数:返回类型
    isinstance(数据,数据类型): 判断数据类型是否一致
  3. 优先级:算数>比较>逻辑
    算数中,幂运算>正负号>二元运算
    (1)** :幂运算,x ** y=x的y次幂
    (2)\ :地板除,向下取整
    (3)divmod(x,y):返回x除以y的地板除和余数
    分支、循环
    三元运算符:a = x if 条件 else y
    断言:assert,条件为假时崩溃,用于测试
  • for循环:
    for 变量 in 可迭代对象
    循环体
  • range函数,参数为整型,返回可迭代对象
    (1)range(stop): 0 ~ stop-1
    (2)range(start,stop): start ~ stop-1
    (3)range(start,stop,step): start ~ stop-1,间隔(步长)为step
    else也可以用于循环,遇到break语句时有用

列表、元组、字符串

python学习笔记(自用)_第1张图片
python学习笔记(自用)_第2张图片

  1. 列表类似更强大的数组。(python列表不能实现取某一列的功能,而numpy的array数字可以)

  2. 元组:
    ① 只可访问,不可修改
    ② 访问方法同列表
    ③ 拼接,重复,关系,逻辑,成员关系操作符都同列表
    ④ tuple所谓的“不变”是说,tuple的每个元素,指向永远不变。即指向’a’,就不能改成指向’b’,指向一个list,就不能改成指向其他对象,但指向的这个list本身是可变的!

  3. 字符串
    ① 同元组一样不可修改,但同样可以用拼接+切片的方法
    ② 其余几乎都与元组一样
    ③ 有更多内置方法
    ④ 格式化
    python学习笔记(自用)_第3张图片

  4. 序列:列表、元组、字符串

字典(dict)

  1. {键:值}(key:value)
  2. 默认迭代返回的是,需要返回键值对需要用dict.item()方法,需要返回需要用dict.vallue()方法
  3. 和list比较,dict有以下几个特点: 查找和插入的速度极快,不会随着key的增加而变慢; 需要占用大量的内存,内存浪费多。
  4. 注意:key一定是不可变对象
  5. 通过key计算位置的算法称为哈希算法(Hash)

python学习笔记(自用)_第4张图片

输入输出:

1.输入:input()。eg: a = input(‘请输入:’)
注意:input()返回的数据类型是str,str不能直接和整数比较,必须先把str转换成整数
函数式编程:
返回函数:返回的不是结果,而是函数,当调用此函数时才会计算最终结果。
闭包:返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
类和对象

集合

set

元素是不可变对象,自动过滤重复对象

删除:remove()方法

增加:add()方法

不可变对象:

指向是不会变的,但是指向的元素可以是可变对象,

元组是不可变对象,不能增删改,但是元素可以是可变对象,例如元组的元素可以是列表

对于不可变对象,调用自身的方法不会改变自身,相当于新建了一个对象,如:replace()方法

函数

函数可以起别名

空函数:pass语句

函数可以同时返回多个值,但其实就是一个tuple,不过可以省略括号

内置函数

数学运算类:
python学习笔记(自用)_第5张图片
python学习笔记(自用)_第6张图片
集合类操作:
python学习笔记(自用)_第7张图片
在这里插入图片描述
逻辑判断:
python学习笔记(自用)_第8张图片
反射:
python学习笔记(自用)_第9张图片
python学习笔记(自用)_第10张图片
python学习笔记(自用)_第11张图片
python学习笔记(自用)_第12张图片

函数参数
  • 位置参数:个数顺序得一一对应

  • 默认参数:必选参数在前,默认参数在后。 定义默认参数要牢记一点:默认参数必须指向不变对象

  • 可变参数:传入参数个数可变。定义函数时,在参数前加一个*函数内部自动组装成一个tuple,其余代码不变。如果已经有一个list或tuple,调用可变参数,则在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去

  • 关键字参数:允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。定义函数时,**在参数前加一个**,**如果已经有一个dict,调用关键字参数,则在dict前面加一个**号,把dict的元素变成关键字参数传进去他,但不会改变原来的dict。

  • 命名关键字参数:限制关键字参数。命名关键字参数需要一个特殊分隔符**后面的参数被视为命名关键字参数。

    def person(name, age, *, city, job):
        print(name, age, city, job)
    

    调用方法:命名关键字参数必须传入参数名

    >>> person('Jack', 24, city='Beijing', job='Engineer')
    Jack 24 Beijing Engineer
    

    如果函数定义中已经有可变参数,则后面的命名关键字参数不需要再加特殊分隔符*

递归

防止栈溢出——尾递归优化:尾递归事实上和循环是等价的,没有循环语句的编程语言只能通过尾递归实现循环。

Python标准的解释器没有针对尾递归做优化,任何递归函数都存在栈溢出的问题。

循环

for ... in 可迭代对象

如果要对list实现类似Java那样的下标循环怎么办?Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身:

>>> for i, value in enumerate(['A', 'B', 'C']):
...     print(i, value)
...
0 A
1 B
2 C

python的循环可以同时引用两个变量,比如下面的代码:

>>> for x, y in [(1, 1), (2, 4), (3, 9)]:
...     print(x, y)
...
1 1
2 4
3 9
列表生成式:

[表达式 for in ]

可以多层循环,也可以加if判断,可以使用多个变量

iffor后时,不能加else; 是筛选条件

iffor前时,必须加else; 是表达式

生成器:generator

要创建一个generator,有很多种方法。

方法一:只要把一个列表生成式的[]改成(),就创建了一个generator:

(表达式 for in )

可以通过next()函数获得generator的下一个返回值,但基本不用(太蠢),正确方法应该是用for循环 :

g = (x * x for x in range(10))
for n in g:
	print(n)

方法二:generator函数

如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator函数,调用一个generator函数将返回一个generator:

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return 'done'
>>> f = fib(6)
>>> f
<generator object fib at 0x104feaaa0>

注:generator函数和普通函数的执行流程不一样。普通函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

generator函数的调用实际返回一个generator对象

调用generator函数会创建一个generator对象,多次调用generator函数会创建多个相互独立的generator。

函数式编程

匿名函数lambda是指一类无需定义标识符(函数名)的函数或子程序。
lambda 函数可以接收任意多个参数 (包括可选参数) 并且返回单个表达式的值。

lambda [arg1 [,arg2,.....argn]]:expression

冒号前是参数,可以有多个,用逗号隔开,冒号右边的为表达式(只能为一个)。其实lambda返回值是一个函数的地址,也就是函数对象

高阶函数

函数本身也可以赋值给变量,即:变量可以指向函数。

函数名其实就是指向函数的变量

定义:一个函数接收另一个函数作为参数,这种函数就称之为高阶函数。

map()函数:

输入:两个参数,一个是函数,一个是Iterable

输出:返回Iterator将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。Iterator是惰性序列,因此通过list()函数让它把整个序列都计算出来并返回一个list。

reduce()函数:

输入:两个参数,一个是函数,一个是Iterable

输出:返回计算结果。reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
filter()函数:过滤

输入:两个参数,一个是函数,一个是Iterable

输出:返回Iteratorfilter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

sort()函数:排序

输入:三个参数 —— 序列,key函数,reserve(默认不反转)

sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序,然后sorted()函数按照keys进行排序,并按照对应关系返回list相应的元素。

例如:忽略大小写来比较字符串(只要都变成小写/大写就能实现)

>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
['about', 'bob', 'Credit', 'Zoo']

返回函数

闭包

使用闭包时,对外层变量赋值前,需要先使用nonlocal声明该变量不是当前函数的局部变量。不然会把它当做局部变量,报错。

装饰器

代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)
本质上,decorator就是一个返回函数的高阶函数
我们要借助Python的@语法,把decorator置于函数的定义处:把@log放到now()函数的定义处,相当于执行了语句:
now = log(now) 由于log()是一个decorator,返回一个函数,所以,原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数,于是调用now()将执行新函数

偏函数

当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。
创建偏函数时,实际上可以接收函数对象、*args和**kw这3个参数
eg:实现转换成二进制的整数

int2 = functools.partial(int, base=2)

模块

模块 —— py.文件,命名不要使用中文、特殊字符
—— 模块的集合(必须包含__init__.py模块,否则是普通的目录)

使用模块

导入模块:import
作用域:

  1. 公开
  2. 特殊:__xxx__ 可以被直接引用,但是有特殊用途,如__author____name__``__doc__,我们自己的变量一般不要用这种变量名;
  3. 非公开: _xxx__xxx

第三方模块

安装第三方模块,是通过包管理工具pip完成的

面向对象编程

:class 类名(父类)

函数或方法

  1. 判断类型: type()函数isinstance()
    区别:isinstance()认为子类也是父类
    用法:type(数据)返回数据类型; isinstance(数据,类型)返回布尔类型
    使用 dir()
  2. 如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list
  3. getattr()函数,setattr()以函数及hasattr()函数: (内置函数)我们可以直接操作一个对象的状态

面向对象高级编程

给实例绑定属性和方法

绑定属性:

>>> s = Student()
>>> s.name = 'Michael' # 动态给实例绑定一个属性
>>> print(s.name)
Michael

绑定方法:

>>> def set_age(self, age): # 定义一个函数作为实例方法
...     self.age = age
...
>>> from types import MethodType
>>> s.set_age = MethodType(set_age, s) # 给实例绑定一个方法
>>> s.set_age(25) # 调用实例方法
>>> s.age # 测试结果
25

为了给所有实例都绑定方法,可以给class绑定方法:

>>> def set_score(self, score):
...     self.score = score
...
>>> Student.set_score = set_score

__slots__():
给class限制属性:

class Student(object):
    __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称

注:__slots__()只对当前类的实例起限制作用,对其子类不起作用

@property

@property装饰器:把一个方法变成属性调用的,既能检查参数,又可以用类似属性这样简单的方式来访问类的变量
把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值,也可以不用setter方法,只用@property,就变成只读属性:

class Student(object):

    @property
    def birth(self):
        return self._birth

    @birth.setter
    def birth(self, value):
        self._birth = value

    @property
    def age(self):
        return 2015 - self._birth//age只读属性

然后就变成可控的属性了(检查参数),调用方法如:

>>> s = Student()
>>> s.score = 60 # OK,实际转化为s.set_score(60)
>>> s.score # OK,实际转化为s.get_score()
60
>>> s.score = 9999
Traceback (most recent call last):
  ...
ValueError: score must between 0 ~ 100!

要特别注意:属性的方法名不要和实例变量重名(会无限递归)

多重继承

通过多重继承,一个子类就可以同时获得多个父类的所有功能。
对于需要Runnable功能的动物,就多继承一个Runnable,例如Dog:

class Dog(Mammal, Runnable):
    pass

MixIn

定制类

这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的

  • __slots__:限制类的属性
  • __len__()方法:让class作用于len()函数
  • __str__()方法:打印实例时返回更好看的字符串:
>>> class Student(object):
...     def __init__(self, name):
...         self.name = name
...     def __str__(self):
...         return 'Student object (name: %s)' % self.name
...
>>> print(Student('Michael'))
Student object (name: Michael)

__repr__()返回程序开发者看到的字符串,也就是说,__repr__()是为调试服务的。直接显示变量调用的不是__str__(),而是__repr__()

>>> s = Student('Michael')
>>> s
<__main__.Student object at 0x109afb310>

解决办法:修改完__str__()后加一个__repr__ = __str__

  • __iter__:
    如果一个类想被用于for … in循环,类似list或tuple那样,就必须实现一个__iter__()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。
我们以斐波那契数列为例,写一个Fib类,可以作用于for循环:
class Fib(object):
    def __init__(self):
        self.a, self.b = 0, 1 # 初始化两个计数器a,b

    def __iter__(self):
        return self # 实例本身就是迭代对象,故返回自己

    def __next__(self):
        self.a, self.b = self.b, self.a + self.b # 计算下一个值
        if self.a > 100000: # 退出循环的条件
            raise StopIteration()
        return self.a # 返回下一个值
  • __getitem__()方法:Fib实例虽然能作用于for循环,但是把它当成list来使用还是不行,要表现得像list那样按照下标取出元素,需要实现__getitem__()方法
class Fib(object):
    def __getitem__(self, n):
        a, b = 1, 1
        for x in range(n):
            a, b = b, a + b
        return a

这样就可以像列表一样[下标]访问元素了

>>> f = Fib()
>>> f[0]
1

__setitem__()方法,把对象视作list或dict来对集合赋值。最后,还有一个__delitem__()方法,用于删除某个元素。

  • __getattr__():动态返回一个属性
    当调用不存在的属性时,比如score,Python解释器会试图调用__getattr__(self, ‘score’)来尝试获得属性,这样,我们就有机会返回score的值:
class Student(object):

    def __init__(self):
        self.name = 'Michael'

    def __getattr__(self, attr):
        if attr=='score':
            return 99
>>> s = Student()
>>> s.name
'Michael'
>>> s.score
99
  1. __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.

callable()函数: 判断一个对象是否是“可调用”对象。
“可调用”对象:函数,定义的带有__call__()的类实例

枚举类

Enum类: 枚举类,每个常量都是class的一个唯一实例

from enum import Enum
class XX(Enum): //继承Enum类

  1. 枚举类的成员组成:name 和 value。其中 name 属性值为该枚举值的变量名(如 red),value 代表该枚举值的序号(序号通常从 1 开始)。
  2. 枚举类不能用来实例化对象,和普通类的用法不同
  3. 访问成员:
#调用枚举成员的 3 种方式
print(Color.red)
print(Color['red'])
print(Color(1))
#调取枚举成员中的 value 和 name
print(Color.red.value)
print(Color.red.name)
#遍历枚举类中所有成员的 2 种方式
for color in Color:
    print(color)
  1. Python 枚举类中各个成员必须保证 name 互不相同,但 value 可以相同。除非加装饰器@unique
  2. 枚举类中各个成员的值,不能在类的外部做任何修改。枚举类中各个成员不能比大小,但能用is或==判断相等

元类

type()函数

type的两种用法:

  1. 查看类型
type(obj)//obj为对象或类
  1. 创建类(python底层用type()创建类)
type(name, bases, dict)//name为类名,bases为所有父类(元组类型),dict为属性和方法
metaclass(一般不会用到)
  1. MetaClass 元类,其必须符合以下条件:
  • 必须显式继承自 type 类;
  • 类中需要定义并实现 new() 方法,该方法一定要返回该类的一个实例对象,因为在使用元类创建类时,该 new() 方法会自动被执行,用来修改新建的类。
  1. 在创建类时,通过在标注父类的同时指定元类(格式为metaclass=元类名),则当 Python 解释器在创建这该类时,FirstMetaClass 元类中的 new 方法就会被调用,从而实现动态修改类属性或者类方法的目的。

错误,调试,测试

错误处理

try...except...finally...的错误处理机制

try
出错
跳过剩余语句直接执行expect
finally

调试

  1. 最简单粗暴——print()语句
  2. assert 断言:将print语句换成断言,想要关闭断言输出的信息用-O参数,这样assert语句相当于pass语句
def foo(s):
    n = int(s)
    assert n != 0, 'n is zero!'
    return 10 / n

def main():
    foo('0')

assert的意思是,表达式n != 0应该是True,否则,根据程序运行的逻辑,后面的代码肯定会出错。

如果断言失败,assert语句本身就会抛出AssertionError:

$ python err.py
Traceback (most recent call last):
···
AssertionError: n is zero!
  1. logging :将print语句换成logging,可以控制输出不同级别的信息,还可以输出到文件
import logging
logging.basicConfig(level=logging.INFO)

将日志消息输出到文件中的实现方法很简单,只需要设置 logging.basicConfig() 函数中的 filename 关键字参数即可
4. pdb:单步运行(不好用,直接用IDE的断点调试更方便)

单元测试

为了编写单元测试,我们需要引入Python自带的unittest模块

import unittest

编写单元测试时,我们需要编写一个测试类,从unittest.TestCase继承。

class TestDict(unittest.TestCase):
...

以test开头的方法就是测试方法,不以test开头的方法不被认为是测试方法,测试的时候不会被执行。

由于unittest.TestCase提供了很多内置的条件判断,我们只需要调用这些方法就可以断言输出是否是我们所期望的。最常用的断言就是assertEqual(),还有assertRaises()

运行单元测试
  1. 在最后加两行代码
if __name__ == '__main__':
    unittest.main()

然后就可以当做正常的脚本运行

$ python mydict_test.py
  1. 方法二:在命令行通过参数-m unittest直接运行单元测试:
$ python -m unittest mydict_test
.....
----------------------------------------------------------------------
Ran 5 tests in 0.000s

OK

这是推荐的做法,因为这样可以一次批量运行很多单元测试,并且,有很多工具可以自动来运行这些单元测试。

setUp与tearDown

可以在单元测试中编写两个特殊的setUp()和tearDown()方法。这两个方法会分别在每调用一个测试方法的前后分别被执行。

设想你的测试需要启动一个数据库,这时,就可以在setUp()方法中连接数据库,在tearDown()方法中关闭数据库,这样,不必在每个测试方法中重复相同的代码:

文档测试

注释+导入模块doctest

当我们编写注释时,如果写上这样的注释:

def abs(n):
    '''
    Function to get absolute value of number.
    
    Example:
    
    >>> abs(1)
    1
    >>> abs(-1)
    1
    >>> abs(0)
    0
    '''
    return n if n >= 0 else (-n)

无疑更明确地告诉函数的调用者该函数的期望输入和输出。

if __name__=='__main__':
    import doctest
    doctest.testmod()

并且,Python内置的“文档测试”(doctest)模块可以直接提取注释中的代码并执行测试。

doctest严格按照Python交互式命令行的输入和输出来判断测试结果是否正确。只有测试异常的时候,可以用…表示中间一大段烦人的输出。

IO进程

同步IO,异步IO

文件读写

  1. 打开文件:f = open(文件名,标识符)'
    读文件:
    ‘r’——只读
    ‘rb’——二进制文件,比如图片、视频等等
方法 特点 适用条件
read() 一次性全部读取 文件很小
readlines() 每次读取一行内容 配置文件
read(size) 指定大小 不能确定文件大小

写文件
‘w’
‘wb’

  1. 打开后一定要关闭文件:f.close()
    为了保证无论是否出错都能正确地关闭文件,我们可以使用try ... finally来实现:
    但是这么写实在太繁琐,所以,Python引入了with语句来自动帮我们调用close()方法:
with open('/path/to/file', 'r') as f:
    print(f.read())

这和前面的try … finally是一样的,但是代码更佳简洁,并且不必调用f.close()方法。

StringIO和BytesIO

StringIO顾名思义就是在内存中读写str。

要把str写入StringIO,我们需要先创建一个StringIO,然后,像文件一样写入即可:

>>> from io import StringIO
>>> f = StringIO()
>>> f.write('hello')
5

getvalue()方法用于获得写入后的str。

操作二进制数据,就需要使用BytesIO。

BytesIO实现了在内存中读写bytes,我们创建一个BytesIO,然后写入一些bytes:

>>> from io import BytesIO
>>> f = BytesIO()
>>> f.write('中文'.encode('utf-8'))
6
>>> print(f.getvalue())
b'\xe4\xb8\xad\xe6\x96\x87'

操作系统和目录

Python内置的os模块可以直接调用操作系统提供的接口函数。
先导入os模块:import os
name
uname()
os.environ——环境变量
os.environ.get(key)
python学习笔记(自用)_第13张图片

序列化

我们把变量从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。

序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。
反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。

导入pickle模块:import pickle
序列化:pickle.dumps()方法把任意对象序列化成一个bytes,然后,就可以把这个bytes写入文件。或者用另一个方法pickle.dump()直接把对象序列化后写入一个file-like Object
反序列化:可以先把内容读到一个bytes,然后用pickle.loads()方法反序列化出对象,也可以直接用pickle.load()方法从一个file-like Object中直接反序列化出对象。

json模块:
如果要把序列化搞得更通用、更符合Web标准,就可以使用json模块。
Python内置的json模块提供了非常完善的Python对象到JSON格式的转换。
json模块的dumps()loads()函数

进程和线程

对于操作系统来说,一个任务就是一个进程(Process),进程内的“子任务”称为线程(Thread)。

多任务的实现有3种方式:
多进程模式;
多线程模式;
多进程+多线程模式。

多进程

多线程

Threadlocal

全局变量local_school就是一个ThreadLocal对象,每个Thread对它都可以读写student属性,但互不影响。你可以把local_school看成全局变量,但每个属性如local_school.student都是线程的局部变量,可以任意读写而互不干扰,也不用管理锁的问题,ThreadLocal内部会处理。

可以理解为全局变量local_school是一个dict,不但可以用local_school.student,还可以绑定其他变量,如local_school.teacher等等。

正则表达式

用于匹配字符串
可以实现:切片(re.split()),分组

在正则表达式中,如果直接给出字符,就是精确匹配。
\d:一个数字
\w:一个字母或数字
.:任意字符

要匹配变长的字符:
*:任意个字符(包括0个)
+:至少一个字符
?:0个或1个字符
{n}:n个字符
{n,m}:n-m个字符

要做更精确地匹配,可以用[]表示范围

进阶:
要做更精确地匹配,可以用[]表示范围
A|B可以匹配A或B
^ 表示行的开头,^ \d表示必须以数字开头。
$ 表示行的结束,\d$表示必须以数字结束。

re模块,match()方法判断是否匹配,如果匹配成功,返回一个Match对象,否则返回None.

备忘录

  1. 初始化二维数组:方法一:全写出来。方法二:列表生成式
  2. 删除元素:del x

你可能感兴趣的:(python)