0%

python

python的学习过程:

  • 第一个是看着廖雪峰的网站,里面的内容基础,是关于数据结构等的十分基本的内容,适合小白入门
  • 第二个是流畅的python
    • 这本书比python-codebook还深入,更适合当你实现了一个功能之后,还是想知道其具体怎么实现的时候查询。
    • 第三个是python-codebook.
    • 它的组织形式是任务式、问题式的,而且问题也相对而言比较高级,不是算法导论那种以解决某个实际问题,而是在编程上我想实现什么更好的功能那种问题,通过每一个问题,或者说通过每一个你想怎么更优的实现一个方法的思路,来引导如何更好地写代码,实现高级功能。这本书的前提是你已经入门,并且写了一段时间的python代码,在实际写的过程中已经遇到了类似的问题,也勉强实现了,只是苦于没有更好更顺心的方法实现。我现在是个小白,看这本书用了将近两周吧,主要看了第一二三四七八章,里面的代码翔实。其他的也是略微看了看,因为没有实际操作背景,有的时候不懂为什么那样做会更好,可以在以后的编程过程中,遇到这样的情况:这个我能勉强实现,但是感觉不太好,我想实现的更优美。那就应该来看看这本书,说不定这本书的实现能给自己一些思路。不适合为了读而读,因为不是入门。
    • 接下来可以考虑看看那种直接算法任务型的。刚刚看了看python算法教程,估计要跳着看了,因为里面的关于算法的内容已经熟悉了,可以扫描着看

python的点

二重列表生成式

1
2
3
4
5
6
7
8
9
10
# 第一种
[[i+j for i in range(3)] for j in range(2)]
[[0, 1, 2], [1, 2, 3]]
# 第二种
[i+j for i in range(3) for j in range(2)]
[0, 1, 1, 2, 2, 3]

# 按列访问类似列表的结构
[a[i][j] for j in range(len(a[0]) for i in range(len(a.size))]

所以对于二重列表生成式,一般可以认为是对于同层的列表,是从前到后,对于不同层的列表,是从外到内

li_ = list(str_)和str_ = ‘’.join(li_)互为相反

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
# 一重列表
In [1]: str = '我你'

In [2]: li = ['我','你']

In [3]: list(str)
Out[3]: ['我', '你']

In [4]: ''.join(li)
Out[4]: '我你'

# 二重列表
In [5]: lli_=[['我','你'],['北','京']]

In [6]: str_ = [''.join(li) for li in lli_]

In [7]: str_
Out[7]: ['我你', '北京']

In [8]: st_ ='/n'.join([''.join(li) for li in lli_])

In [9]: st_
Out[9]: '我你/n北京'

#同理,可以推广到多重列表

list删除元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 利用pop,根据位置删除
# 存在返回值,与append相对应
li_.pop()
a = li_.pop(i)

# 利用remove,根据值删除
# 删除第一个匹配的值
aList = [123, 'xyz', 'zara', 'abc', 'xyz'];
aList.remove('xyz');
aList.remove(aList[1])

# 利用del,根据位置删除,没有返回值
del(n[4])
del n[4]

# str.replace()
```python
u'afafafa'.replace('a',u'eee').replace('f',u'rr')
'eeerreeerreeerreee'

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
2
3
4
5
ipdb> y = 10
ipdb> [[ 1 for w in range(2)] for j in range(y)]
[[1, 1], [1, 1], [1, 1], [1, 1], [1, 1], [1, 1], [1, 1], [1, 1], [1, 1], [1, 1]]
ipdb> [[ 1 for w in range(y)] for j in range(2)]
*** NameError: name 'y' is not defined

assert

1
2
3
4
5
6
7
8
9
10
11
12
# 第一种
assert 3 >=5,'2不等于1'

----> 1 assert 3 >=5

AssertionError:

# 第二种
assert 3 >=5,'3不小于等于5'
----> 1 assert 3 >=5,'3不小于等于5'

AssertionError: 3不小于等于5

sort和sorted

sort是对list的操作
sorted是对所有可迭代的序列的操作


requirements.txt

1
2
3
4
5
pip freeze > requirements.txt # 生成requirements.txt
pip install -r requirements.txt # 从requirements.txt安装依赖

pip install pipreqs
pipreqs /home/project/location

装饰器

第一步:
函数也是一个对象,也可以赋值给变量,也可以通过变量来调用函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
In [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

第二步:
简单的装饰器,在函数调用前后,进行一些没有参数的操作,在代码运行期间增加功能
两层的装饰器,@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
In [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
42
In [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
21
import functools

def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
# 或者
import functools

def log(text):
def decorator(func):
@functools.wraps(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或者tuple

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
In [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
33
In [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
21
In [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
14
In [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
2
3
4
5
6
7
8
9
10
11
12
# 第一种,直接*
In [26]: def person(name, * ,city, job):
...: print(name, city, job)
...:
# 其调用时必须显示输入参数名,city和job,当然,命名关键字参数也可以设置默认值
In [27]: person('11',city='beijing', job='enginner')
11 beijing enginner

# 第二种 有可变参数的存在
def person(name, age, *args, city, job):
print(name, age, args, city, job)

参数组合

参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def 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
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
In [29]: def lazy_sum(*args):
...: def sum():
...: ax = 0
...: for i in args:
...: ax = ax+i
...: return ax
...: return sum
...:
...:

In [30]: f = lazy_sum(1,2,3,4)

In [31]: f.__name__
Out[31]: 'sum'

In [32]: f.__file__
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-32-9c8edc3d9e41> in <module>()
----> 1 f.__file__

AttributeError: 'function' object has no attribute '__file__'

In [33]: f
Out[33]: <function __main__.lazy_sum.<locals>.sum()>

In [34]: f()
Out[34]: 10

In [35]: f1 = lazy_sum()

In [36]: f2 = lazy_sum()

In [37]: f1==f2
Out[37]: False

闭包存在的问题

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
23
def 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
14
In [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
2
counterA = createCounter()
print(counterA(), counterA(), counterA(), counterA(), counterA()) # 1 2 3 4 5
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
一、在内部函数内修改外部函数局部变量的两种方法
1法:把外部变量变成容器或者说可变变量

def createCounter():
a = [0]
def counter():
a[0] += 1
return a[0]
return counter

2法:在内部函数里给予外部函数局部变量nonlocal声明,让内部函数去其他领域获取这个变量

def createCounter():
a = 0
def counter():
nonlocal a
a += 1
return a
return counter
二、在内部函数内修改全局变量

def createCounter():
global a
a = 0
def counter():
global a
a += 1
return a
return counter

快速解压或者list+tuple转置

1
2
3
4
5
6
7
8
9
10
11
12
li_ = [(1,2,3),(4,5,6)]
ll = list(zip(*li_))
[(1, 4), (2, 5), (3, 6)]

# 甚至可以达到按列取值的效果
l1, l2, l3 = list(zip(*li_))
l1
(1, 4)
l2
(2, 5)
l3
(3, 6)

求一个序列中,与固定值之间的最大值,这个最大值不能超过序列的最大值和固定值

或者说求两个序列的最小最大值
或者说在这个序列中,如果没有比固定值大的数,则取这个序列的最大值作为最大值,如果有,则取固定值作为最大值
或者说对这个序列进行截断

1
2
3
4
5
ll = [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
2
3
4
5
6
7
a = 1
b = 2
d = dict(aa = a, bb = b)
{'aa': 1, 'bb': 2}
dd = {'aa':a, 'bb':2}
dd
{'aa': 1, 'bb': 2}

注释文档

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
64
65
66
67
68
69
70
71
72
73
'''
文档快速生成注释的方法介绍,首先我们要用到__all__属性
在Py中使用为导出__all__中的所有类、函数、变量成员等
在模块使用__all__属性可避免相互引用时命名冲突
'''
__all__ = ['Login', 'check', 'Shop', 'upDateIt', 'findIt', 'deleteIt']

class Login:
'''
测试注释一可以写上此类的作用说明等
例如此方法用来写登录
'''

def __init__(self):
'''
初始化你要的参数说明
那么登录可能要用到
用户名username
密码password
'''
pass

def check(self):
'''
协商你要实现的功能说明
功能也有很多例如验证
判断语句,验证码之类的
'''
pass


class Shop:
'''
商品类所包含的属性及方法
update改/更新
find查找
delete删除
create添加
'''

def __init__(self):
'''
初始化商品的价格、日期、分类等
'''
pass

def upDateIt(self):
'''
用来更新商品信息
'''
pass

def findIt(self):
'''
查找商品信息
'''
pass

def deleteIt(self):
'''
删除过期下架商品信息
'''
pass

def createIt(self):
'''
创建新商品及上架信息
'''
pass

if __name__=="__main__":
import test
print(help(test))
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
$ python test.py
Help on module test:

NAME
test

DESCRIPTION
文档快速生成注释的方法介绍,首先我们要用到__all__属性
在Py中使用为导出__all__中的所有类、函数、变量成员等
在模块使用__all__属性可避免相互引用时命名冲突

CLASSES
builtins.object
Login
Shop

class Login(builtins.object)
| 测试注释一可以写上此类的作用说明等
| 例如此方法用来写登录
|
| Methods defined here:
|
| __init__(self)
| 初始化你要的参数说明
| 那么登录可能要用到
| 用户名username
| 密码password
|
| check(self)
| 协商你要实现的功能说明
| 功能也有很多例如验证
| 判断语句,验证码之类的
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)

class Shop(builtins.object)
| 商品类所包含的属性及方法
| update改/更新
| find查找
| delete删除
| create添加
|
| Methods defined here:
|
| __init__(self)
| 初始化商品的价格、日期、分类等
|
| createIt(self)
| 创建新商品及上架信息
|
| deleteIt(self)
| 删除过期下架商品信息
|
| findIt(self)
| 查找商品信息
|
| upDateIt(self)
| 用来更新商品信息
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)

DATA
__all__ = ['Login', 'check', 'Shop', 'upDateIt', 'findIt', 'deleteIt']

FILE
h:\桌面\test.py


None

用help或者.doc

1
print(math.sin.__doc__)


all

只对from xx import *有作用
参考链接https://stackoverflow.com/questions/44834/can-someone-explain-all-in-python

1
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
4
from __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
2
3
4
5
6
7
tt = t.Tensor([[1,2,3],[3,4,5]])
ttt = tt.narrow(0,0,1)
ttt
tensor([[ 1., 2., 3.]])

tt[0:1]
tensor([[ 1., 2., 3.]])

https://www.bbsmax.com/A/gAJGaGeZdZ/


生成器函数 迭代器 迭代对象

对于生成器函数,可以理解成列表,yield的值就是列表中的元素,用next()或者for in来调用
迭代器 Iterator: 可以用于next的,惰性计算
迭代对象 Iteratable: 可以用于for的 list, tuple, 生成器
迭代对象可以使用iter变成迭代器
迭代对象范围更广


对于0

1
2
3
4
5
6
7
8
9
10
a = 0
if a ==0:
True
等价于
if not a:
并且

if a!=0
等价于
if a

2018-10-05
关于Python爬虫涉及到的编码问题
计算机内存中,使用Unicode编码
硬盘或者传输时,使用UTF-8编码

bytes和str

Python3默认的字符串类型是str,在内存中以Unicode表示,如果要想保存到硬盘上或者在网络上传输,就需要把str转换成以字节为单位的bytes。
str—encode—>bytes—decode—>str
看了一些博客,感觉还是没有讲清楚,不是很清楚。

re

参考链接