python的学习过程:
- 第一个是看着廖雪峰的网站,里面的内容基础,是关于数据结构等的十分基本的内容,适合小白入门
- 第二个是流畅的python
- 这本书比python-codebook还深入,更适合当你实现了一个功能之后,还是想知道其具体怎么实现的时候查询。
- 第三个是python-codebook.
- 它的组织形式是任务式、问题式的,而且问题也相对而言比较高级,不是算法导论那种以解决某个实际问题,而是在编程上我想实现什么更好的功能那种问题,通过每一个问题,或者说通过每一个你想怎么更优的实现一个方法的思路,来引导如何更好地写代码,实现高级功能。这本书的前提是你已经入门,并且写了一段时间的python代码,在实际写的过程中已经遇到了类似的问题,也勉强实现了,只是苦于没有更好更顺心的方法实现。我现在是个小白,看这本书用了将近两周吧,主要看了第一二三四七八章,里面的代码翔实。其他的也是略微看了看,因为没有实际操作背景,有的时候不懂为什么那样做会更好,可以在以后的编程过程中,遇到这样的情况:这个我能勉强实现,但是感觉不太好,我想实现的更优美。那就应该来看看这本书,说不定这本书的实现能给自己一些思路。不适合为了读而读,因为不是入门。
- 接下来可以考虑看看那种直接算法任务型的。刚刚看了看python算法教程,估计要跳着看了,因为里面的关于算法的内容已经熟悉了,可以扫描着看
python的点
二重列表生成式
1 | # 第一种 |
所以对于二重列表生成式,一般可以认为是对于同层的列表,是从前到后,对于不同层的列表,是从外到内
li_ = list(str_)和str_ = ‘’.join(li_)互为相反
1 | # 一重列表 |
list删除元素
1 | # 利用pop,根据位置删除 |
python函数的互换
对于类似的函数,并且有相同输入和输出,只是对于实现的功能有一些不一样
暂时无法评价这两种写法的优劣1
2
3
4
5
6
7
8
9# 第一种写法
if opt.acrostic:
result = gen_acrostic(model, start_words, ix2word, word2ix, prefix_words)
else:
result = generate(model, start_words, ix2word, word2ix, prefix_words)
# 第二种写法
gen_poetry = gen_acrostic if opt.acrostic else generate
result = gen_poetry(model, start_words, ix2word, word2ix, prefix_words)
奇怪
1 | ipdb> y = 10 |
assert
1 | # 第一种 |
sort和sorted
sort是对list的操作
sorted是对所有可迭代的序列的操作
requirements.txt
1 | pip freeze > requirements.txt # 生成requirements.txt |
装饰器
第一步:
函数也是一个对象,也可以赋值给变量,也可以通过变量来调用函数。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19In [1]: def now():
...: print('now 2020202')
In [2]: f = now
In [3]: f()
now 2020202
In [4]: now.__name__
Out[4]: 'now'
In [5]: f.__name__
Out[5]: 'now'
In [6]: type(f)
Out[6]: function
In [7]: type(now)
Out[7]: function
第二步:
简单的装饰器,在函数调用前后,进行一些没有参数的操作,在代码运行期间增加功能
两层的装饰器,@log1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27In [15]: def log(func):
...: print('wrapper early')
...: print(func.__name__)
...: def wrapper(*args, **kwargs):
...: print('fun early{0}'.format(func.__name__))
...: func(*args,**kwargs)
...: print('fun later')
...: print('wrapper later')
...: return wrapper
...:
...:
In [16]: @log
...: def now():
...: print('now test3')
...:
wrapper early
now
wrapper later
In [17]: now()
fun earlynow
now test3
fun later
In [18]: now.__name__
Out[18]: 'wrapper'
第三步:
复杂的装饰器,在函数调用前后,进行有参数的操作,
三层的装饰器,@log()1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42In [19]: def log(text):
...: print('log----decorator')
...: def decorator(func):
...: print('decorator----wrapper')
...: def wrapper(*args,**kwargs):
...: print('wrapper 1')
...: print(text,func.__name__)
...: print(' wrapper 2')
...: return func(*args, **kwargs)
...: print('wrapper----decorator')
...: return wrapper
...: print('decorator----log')
...: return decorator
...:
...:
...:
In [20]: @log('hello')
...: def now():
...: print('1000')
...: return 1
...:
...:
log----decorator
decorator----log
decorator----wrapper
wrapper----decorator
In [21]: now()
wrapper 1
hello now
wrapper 2
1000
Out[21]: 1
In [22]: f = now
In [23]: f.__name__
Out[23]: 'wrapper'
In [24]: now.__name__
Out[24]: 'wrapper'
第四步:
完整的装饰器1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21import functools
def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
# 或者
import functools
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
等价于wrapper.__name__ = func.__name__
参数
分为位置参数(可以设置为默认参数),可变参数,关键字参数
位置参数很简单,跳过
可变参数或者关键字参数可以没有值赋予
可变参数
第一步:对于不确定个数的参数,使用list或者tuple作为参数传入
缺点:在调用的时候必须先组装成list或者tuple1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21In [7]: def calc(number):
...: sum = 0
...: print(type(number))
...: for i in number:
...: sum+=i
...: return sum
...:
...:
In [8]: calc([1,2,3])
<class 'list'>
Out[8]: 6
In [9]: calc((1,2,3)
...: )
<class 'tuple'>
Out[9]: 6
In [10]: calc((1,2,3))
<class 'tuple'>
Out[10]: 6
第二步:利用可变参数*number,在第一步的基础上修正缺点,使其调用不再需要先组装
缺点:输入参数是list和tuple时就会很麻烦,需要先拆解1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33In [11]: def calc(*number):
...: sum = 0
...: print(type(number))
...: for i in number:
...: sum+=i
...: return sum
...:
...:
In [12]: calc(1,2,3)
<class 'tuple'>
Out[12]: 6
In [13]: calc()
<class 'tuple'>
Out[13]: 0
In [14]: num = [1,2,3]
In [15]: calc(num)
<class 'tuple'>
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-15-bb5c0a89404a> in <module>()
----> 1 calc(num)
<ipython-input-11-34cdd7bd7eaa> in calc(*number)
3 print(type(number))
4 for i in number:
----> 5 sum+=i
6 return sum
TypeError: unsupported operand type(s) for +=: 'int' and 'list'
注意,可变参数在函数内部是作为一个tuple存在的,如果对于tuple进行修改,先变成list
第三步:对第一步的优点和第二步的优点进行整合,使调用时既能直接接收list或者tuple作为输入参数,也能不需要组装成list或者tuple进行输入。
也就是在函数定义时注明number,输入直接输入或者list.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21In [11]: def calc(*number):
...: sum = 0
...: print(type(number))
...: for i in number:
...: sum+=i
...: return sum
...:
...:
# 合理调用的几种方式
In [14]: num = [1,2,3]
In [16]: calc(*num)
<class 'tuple'>
Out[16]: 6
In [20]: calc(1,2,3)
<class 'tuple'>
Out[20]: 6
In [22]: calc(*(1,2,3))
<class 'tuple'>
Out[22]: 6
关键字参数
类比可变参数,就很容易地理解dict型参数的输入1
2
3
4
5
6
7
8
9
10
11
12
13
14In [18]: def person(name, **kwargs):
...: print(type(kwargs))
...: print(kwargs)
In [23]: person('fa',city='beijing',age='44')
<class 'dict'>
{'city': 'beijing', 'age': '44'}
In [24]: extra = {'city': 'Beijing', 'job': 'Engineer'}
In [25]: person('hh',**extra)
<class 'dict'>
{'city': 'Beijing', 'job': 'Engineer'}
对于可变参数或者关键字参树,或者按照正常地类似位置参数或者默认参数的形式传入,或者按照list或者*dict进行传入。
命名关键字参数
1 | # 第一种,直接* |
参数组合
参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24def f1(a, b, c=0, *args, **kw):
print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
def f2(a, b, c=0, *, d, **kw):
print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
In [28]: def f(a,b,c=0,*args,d,**kw):
...: print('a',a,'b',b,'c',c,'args',args,'d',d,'kw',kw)
...:
In [29]: f(1,2,3,4,d=5,e=6)
a 1 b 2 c 3 args (4,) d 5 kw {'e': 6}
# 看一个神奇的东西,输入参数用tuple和dict直接代替
In [30]: args = (1,2,3,4)
In [31]: dic = {'d':5, 'e':6}
In [33]: f(*args,**dic)
a 1 b 2 c 3 args (4,) d 5 kw {'e': 6}
# 由此引出一个重要结论
# 所以,对于任意函数,都可以通过类似func(*args, **kw)的形式调用它,无论它的参数是如何定义的。
# 这个结论解释了后期定义装饰器的时候,参数的定义直接是(*args, **kw)的形式,而不用去管函数本身的参数的定义是什么样的,而在调用的时候,按照原函数的参数定义调用即可。
闭包
1 | In [29]: def lazy_sum(*args): |
闭包存在的问题1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63# 返回多个函数
In [38]: def count():
...: fs=[]
...: for i in range(4):
...: def f():
...: return i*i
...: fs.append(f)
...: return fs
...:
...:
In [39]: f1,f2,f3,f4 = count()
In [40]: f1()
Out[40]: 9
In [42]: f2()
Out[42]: 9
In [43]: f3()
Out[43]: 9
In [44]: f4()
Out[44]: 9
In [63]: def count():
...: def f():
...: return i*i
...: fs=[]
...: for i in range(4):
...: fs.append(f)
...: print(i)
...: return fs
In [64]: f1, f2, f3, f4 = count()
0
1
2
3
In [65]: f1()
Out[65]: 9
In [66]: f2()
Out[66]: 9
# 返回单个函数
In [48]: def lazy_sum(*args):
...: j=0
...: def sum():
...: ax = 0
...: for i in args:
...: ax = ax+i+j
...: return ax
...: j=100
...: return sum
...:
...:
In [49]: f1 = lazy_sum(1,2,3)
In [50]: f1()
Out[50]: 306
返回函数不要引用任何循环变量,或者后续会发生变化的变量。应该满足内层函数定义后其所引用的外部变量不发生变化。
针对外部变量发生变化的解决方案
就是再用一个函数,令变化的外部变量从隐式参数变成显式参数
或者说,对于变化的外部变量,令其执行,不再以变量的形式存在,而是以其值的形式存在。
第一种方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23def count():
def f(j):
def g():
return j*j
return g
fs = []
for i in range(1, 4):
fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
return fs
In [52]: f1, f2, f3 = count()
In [53]: f1()
Out[53]: 1
In [60]: f1
Out[60]: <function __main__.count.<locals>.f.<locals>.g()>
In [61]: f2
Out[61]: <function __main__.count.<locals>.f.<locals>.g()>
In [62]: f1.__name__
Out[62]: 'g'
第二种方法1
2
3
4
5
6
7
8
9
10
11
12
13
14In [113]: def count():
...: fs=[]
...: for i in range(2):
...: def f(m=i):
...: return m*m
...: fs.append(f)
...: return fs
...:
...:
In [114]: count()
Out[114]:
[<function __main__.count.<locals>.f(m=0)>,
<function __main__.count.<locals>.f(m=1)>]
廖雪峰说可以用lambda函数进行代码缩写,但是没有想通怎么用。
内部函数内修改外部函数局部变量
1 | counterA = createCounter() |
1 | 一、在内部函数内修改外部函数局部变量的两种方法 |
快速解压或者list+tuple转置
1 | li_ = [(1,2,3),(4,5,6)] |
求一个序列中,与固定值之间的最大值,这个最大值不能超过序列的最大值和固定值
或者说求两个序列的最小最大值
或者说在这个序列中,如果没有比固定值大的数,则取这个序列的最大值作为最大值,如果有,则取固定值作为最大值
或者说对这个序列进行截断1
2
3
4
5ll = [min(c, max_len) for c in l]
max_query = max(ll)
# 或者
max_l = max(l)
max_query = min(max_l, max_len)
dict
1 | a = 1 |
注释文档
1 | ''' |
1 | $ python test.py |
用help或者.doc1
print(math.sin.__doc__)
all
只对from xx import *有作用
参考链接https://stackoverflow.com/questions/44834/can-someone-explain-all-in-python1
2
3
4
5
6
7
8
9
10
11
12
13# foo.py
__all__ = ['bar', 'baz']
waz = 5
bar = 10
def baz(): return 'baz'
# run-foo.py
from foo import *
print(bar) # 正常
print(baz) # 正常
print(waz) # 显示错误
from future import absolute_import
从python2.1开始以后, 当一个新的语言特性首次出现在发行版中时候, 如果该新特性与以前旧版本python不兼容, 则该特性将会被默认禁用. 如果想启用这个新特性, 则必须使用 “from futureimport *” 语句进行导入.1
2
3
4from __future__ import absolute_import
# https://blog.csdn.net/caiqiiqi/article/details/51050800
from __future__ import division
# https://blog.csdn.net/feixingfei/article/details/7081446
保持原有维度的取元素 narrow 或者切片
1 | tt = t.Tensor([[1,2,3],[3,4,5]]) |
堆
https://www.bbsmax.com/A/gAJGaGeZdZ/
生成器函数 迭代器 迭代对象
对于生成器函数,可以理解成列表,yield的值就是列表中的元素,用next()或者for in来调用
迭代器 Iterator: 可以用于next的,惰性计算
迭代对象 Iteratable: 可以用于for的 list, tuple, 生成器
迭代对象可以使用iter变成迭代器
迭代对象范围更广
对于0
1 | a = 0 |
2018-10-05
关于Python爬虫涉及到的编码问题
计算机内存中,使用Unicode编码
硬盘或者传输时,使用UTF-8编码
bytes和str
Python3默认的字符串类型是str,在内存中以Unicode表示,如果要想保存到硬盘上或者在网络上传输,就需要把str转换成以字节为单位的bytes。
str—encode—>bytes—decode—>str
看了一些博客,感觉还是没有讲清楚,不是很清楚。