字符串查找元素

1
2
3
astr = '1234'
astr.find('1') # 返回下标或-1
astr.rfind('1') # 反向查找

python lambda 表达式

1
2
3
4
5
6
7
8
9
10
g = lambda x:x+1 # x为输入,x+1为输出: g(1) = 2
# python 中自带的lambda表达式
# foo =[2, 18, 9, 22, 17, 24, 8, 12, 27]
# 输出:[18, 9, 24, 12, 27]
filter(lambda x:x%3 ==0,foo)
# map,将foo中每个元素都算一下
#输出:[14, 46, 28, 54, 44, 58, 26, 34, 64]
map(lambda x: x * 2 + 10, foo)
#reduce 类加
reduce(lambda x, y: x + y, foo)

获取图片大小

1
2
3
from PIL import Image
im = Image.open('whatever.png')
width, height = im.size

python 🀄️的类

1
2
3
4
5
6
class Animal(object):
def __init__(self,name):
self.name = name
self.__sex = man ## 在属性前加上两个_ 变成私有变量
def greet(self):
print('hello'+self.name)

python中前后都有双下划线的变量是特殊变量,如__ver__,可以直接访问,定义式避免这种定义方式。例外,仅有一个下划线,如_name,这种变量表示不要轻易访问,但是它是可以被直接访问的。

获取变量信息

例如dog = Animal('dog'):

  • type(dog) 来获取dog的类型。
  • isinstance(dog,Animal) 判断dog的类型
  • hasattr(obj, attr) 判断类是否有attr方法/属性
  • getattr(obj,attr[,default]):得到属性的值
  • setattr(obj, attr, value): 设置属性的值
  • dir(dog): 获取dog的所有属性和方法

类方法,静态方法

可以使用类或实例直接访问:

1
2
3
4
5
6
7
class A(object):
@classmethod
def class_info(cls):
print(cls)
@staticmethod
def static_info():
print('something')

定制类以及魔法方法

python中有一类方法,使用双下划线包裹起来:__new__等等,这类方法称为魔法方法,可以对类提供特殊的功能,方便定制类。

__new__(cls): 当创建一个类时,首先调用__new__(cls)方法,之后再调用__init__()

__str__: 当我们直接输出一个实例时,如print(dog),得到的输出为:<__main__.Animal object at 0x10c37aa50>,通过覆盖__str__ 方法可以输出我们想要的内容。

__repr__: 当我们不用print时,调用该方法

1
2
3
4
5
6
7
class A(object):
def __str__(self):
return 'Animal object (name: %s)' % self.name
def __repr__(self):
return 'lalal'
print(Animal(dog)) ## 调用__str__()
Animal(dog) ## 调用 __repr__()

__iter__(),__next__(): 定义该方法使得类允许迭代调用,首先调用__iter__() 获得一个迭代器,然后每次迭代调用next。(可以不定义iter)。

__geitem__ 用于获取值,类似地,__setitem__ 用于设置值,__delitem__ 用于删除值,让我们看下面一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Point(object):
def __init__(self):
self.coordinate = {}

def __str__(self):
return "point(%s)" % self.coordinate

def __getitem__(self, key):
return self.coordinate.get(key)

def __setitem__(self, key, value):
self.coordinate[key] = value

def __delitem__(self, key):
del self.coordinate[key]
print 'delete %s' % key

def __len__(self):
return len(self.coordinate)

__repr__ = __str__

调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> p = Point()
>>> p['x'] = 2 # 对应于 p.__setitem__('x', 2)
>>> p['y'] = 5 # 对应于 p.__setitem__('y', 5)
>>> p # 对应于 __repr__
point({'y': 5, 'x': 2})
>>> len(p) # 对应于 p.__len__
2
>>> p['x'] # 对应于 p.__getitem__('x')
2
>>> p['y'] # 对应于 p.__getitem__('y')
5
>>> del p['x'] # 对应于 p.__delitem__('x')
delete x
>>> p
point({'y': 5})
>>> len(p)
1

__getattr__() 只有在属性不存在的情况下才会被调用。

__getattr__ 一起使用的还有 __setattr__, __delattr__,类似 obj.attr = value, del obj.attr:

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
class Point(object):
def __init__(self, x=0, y=0):
self.x = x
self.y = y

def __getattr__(self, attr):
if attr == 'z':
return 0
raise AttributeError("Point object has no attribute %s" % attr)

def __setattr__(self, *args, **kwargs):
print 'call func set attr (%s, %s)' % (args, kwargs)
return object.__setattr__(self, *args, **kwargs)

def __delattr__(self, *args, **kwargs):
print 'call func del attr (%s, %s)' % (args, kwargs)
return object.__delattr__(self, *args, **kwargs)

>>> p = Point(3, 4)
call func set attr (('x', 3), {})
call func set attr (('y', 4), {})
>>> p.z
0
>>> p.z = 7
call func set attr (('z', 7), {})
>>> p.z
7
>>> p.w
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in __getattr__
AttributeError: Point object has no attribute w
>>> p.w = 8
call func set attr (('w', 8), {})
>>> p.w
8
>>> del p.w
call func del attr (('w',), {})
>>> p.__dict__
{'y': 4, 'x': 3, 'z': 7}

__call__ 方法,对实例进行调用就好像对函数调用一样。

1
2
3
4
5
class A(object):
def __call__(self):
return 1+1
a = A()
a() # 将调用__call__方法

使用 __slots__ 来告诉 Python 只给一个固定集合的属性分配空间,如下:

1
2
3
4
5
6
7
8
class Point(object):
__slots__ = ('x', 'y') # 只允许使用 x 和 y

def __init__(self, x=0, y=0):
self.x = x
self.y = y
a = Point()
a.z = 1 # 报错,只允许对x,y赋值

定义@property以及@setter 方法,第一个将方法当作属性来用,第二个将这个方法当作属性来赋值。

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
class Exam(object):
def __init__(self, score):
self._score = score

@property
def score(self):
return self._score

@score.setter
def score(self, val):
if val < 0:
self._score = 0
elif val > 100:
self._score = 100
else:
self._score = val

>>> e = Exam(60)
>>> e.score
60
>>> e.score = 90
>>> e.score
90
>>> e.score = 200
>>> e.score
100

super():当使用子类与夫类方法相同时会发生覆盖,如果希望保留父类则调用super方法。

1
2
3
4
5
6
7
8
9
10
class Animal(object):
def __init__(self, name):
self.name = name
def greet(self):
print111

class Dog(Animal):
def greet(self):
super().greet()
print 'WangWang...'

使用元类:元类主要用来拦截类的创建,修改类的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class PrefixMetaclass(type):
def __new__(cls, name, bases, attrs):
# 给所有属性和方法前面加上前缀 my_
_attrs = (('my_' + name, value) for name, value in attrs.items())

_attrs = dict((name, value) for name, value in _attrs) # 转化为字典
_attrs['echo'] = lambda self, phrase: phrase # 增加了一个 echo 方法

return type.__new__(cls, name, bases, _attrs)

class Foo(metaclass=PrefixMetaclass):
name = 'foo'
def bar(self):
print 'bar'

class Bar(Foo):
prop = 'bar'

创建迭代器:

1
2
3
4
5
6
7
8
9
10
11
12
class Fib(object):
def __init__(self):
self.a, self.b = 0, 1

# 返回迭代器对象本身
def __iter__(self):
return self

# 返回容器下一个元素
def __next__(self):
self.a, self.b = self.b, self.a + self.b
return self.a

__iter__() 创建迭代器,__next__()每次迭代均调用该方法取得迭代值。

创建生成器:

1
2
3
4
5
6
7
8
9
10
11
>>> def fib():
... a, b = 0, 1
... while True:
... a, b = b, a + b
... yield a
...
>>> f = fib()
>>> for item in f: # 每次执行到yield返回一个值并停止,第二次调用f.next()时冲yield处开始执行
... if item > 10:
... break
... print item

Python OS模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import os
for dir in os.listdir('./'): # 当前路径下的所有文件
print(dir)
os.path.abspath('.') # 得到绝对路径
os.path.dirname('file.txt') #  获取当前文件的父目录
os.path.basename('./path/to/file.txt') # 输出file.txt,得到文件名
os.path.splitext('afile.txt') # 输出(afile,txt),分离文件名和扩展名
os.path.split('/path/file.txt')# (path,file.txt),分离目录与文件
os.path.isfile/os.path.isdir() #判断是否是目录或文件

##遍历目录
for root, dirs, files in os.walk('/Users/ethan/coding'):
print root
print dirs
print files

python zip函数

1
2
3
a = [1,2,3]
b = [4,5,6]
zipped = zip(a,b)#[(1,4),(2,5),(3,6)]
1
2
3
4
5
with open('afile.txt','w') as f:
a = 'this is a string'
b = 11
print >> a,b
## 重定向将a,b输入afile.txt 中

sys.stdout 标准输出

1
2
sys.stdout.write('{}/{}\r'.format(step,len(lines)))# 控制台输出
sys.stdout.flush() # 将控制台输出的抹掉

xlsx文件读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import xlrd

XLSX_PATH = './video_id.xlsx'

workbook = xlrd.open_workbook(XLSX_PATH)
print(workbook.sheet_names()) #得到所有表的表名

id_list = []
for sheet in workbook.sheet_names():
booksheet = workbook.sheet_by_name(sheet) # 根据表名得到表
col = booksheet.col_values(0)[1:] # 得到表的第一列
id_list += col
print('sheet name: '+ sheet)
print(col)

print('total account:' +str(len(id_list)))

from_slsx_get_video(id_list)

progressbar 进度条的使用

1
2
3
4
from progress import *
progress = ProgressBar()
for i in progress(range(1000)):
pass

python enumerate使用

1
2
for i,label in enumerate(labels):
print(i,label)

python argsort()

argsort是numpy的一个函数,这个函数的作用是返回从小到大排序后的元素下标。

1
2
3
4
import numpy as np
a = np.array([1,2,4,-1])
sort_index = np.argsort(a)
a = a[b] # 进行排序

numpy cumsum()

cumsum()这个函数用来对数组依次累加。

1
2
3
import numpy as np
a = np.array([1,2,3])
b = np.cumsum(a) # b = [1,3,6]

numpy maximum()

这个函数的输入为两个数组,然后生成一个数组,每个位置上为这两个数组中较大的那个。

1
2
3
4
import numpy as np
a = np.array([1,2,3])
b = np.array([2,2,2])
c = np.maximum(a,b) # c = [2,2,3]

python 排序算法

1
2
3
a = [3,2,4]
a.sort() # 输出为空,直接改变a
sorted(a) # 输出排序后的结果,但不改变a

Python 中的序列

序列是python 中最基本的数据结构。序列对象均可以进行索引,分片,迭代,加,乘操作,可以用in判断元素是否存在序列中。其中list,tuple,str都属于序列。

list 列表

list是可修改的一个变量,可以对他进行任意的修改。可以使用list()函数,对str字符串,和tuple进行转化成list。下面对list的各种函数进行讲解:

index

1
2
3
4
# index 用于从列表中寻找第一个出现元素的下标
nums = [1,2,3,4,5,6,7]
nums.index(2)
nums.index(9) # 如果找不到则抛出异常

count

1
2
# 用于计算一个元素出现的个数
nums.count(1)

append

1
2
3
# 用于在元素末尾增加元素
nums.append(8)
nums.append([9,8]) # 将[9,8]作为一个整体加入 nums = [1,2,..,[8,9]]

extend

1
2
3
4
5
6
7
# 将list进行融合
a = [1,2,3]
b = [4,5,6]
a.extend(b) # a = [1,2,3,4,5,6]
## extend 元素不允许直接添加一个元素
a.extend(3) # 报错
a.extend([3])

insert

1
2
3
#insert(pos,val)
a = [1,2,3]
a.insert(1,4) # a = [1,4,2,3]

pop

1
2
3
4
# 用于移除list中的元素,默认是最后一个,返回值为移除的数
a = [1,2,3,4]
a.pop() # a = [1,2,3]
a.pop(1) # a = [1,3]

remove

1
2
3
4
# remove(val) 移除list中值为val的元素
a = [1,2,2,3,3,4]
a.remove(2) # 移除第一个相同的,a = [1,2,3,3,4]
a.remove(8) # 若不在list中,则抛出异常

reverse

1
2
3
# 反转数组
a = [1,2,3]
a.reverse() # a = [3,2,1]

sort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 该方法直接对list进行排序,修改list的值
a = [3,1,2]
a.sort() # 直接修改a, a = [1,2,3]
a.sort(reverse=True) # 反向排序
# 此外可以指定key,进行一些多列的排序
student_tuples = [
('john', 'A', 15),
('jane', 'B', 12),
('dave', 'B', 10),
]
sorted(student_tuples,key=lambda student:student[2])

# cmp 指定函数
def compare(x,y):
return x-y
sorted(alist,cmp = compare)

sorted

1
2
3
# 该方法不是list的方法,返回值为排序结果,不改变a
a = [3,1,2]
sorted(a) # 返回值为[1,2,3],a不变

tuple

元组是一种不可变的序列,不可对tuple进行修改,它用()来表示。

1
2
3
4
a = (1,2,3)
b = (1,) # 当仅有一个元素的时候,必须叫上一个逗号
c =() # 空元组
tuple # 可以进行索引分片,与正常的序列相同

字符串

字符串是一种序列,满足索引,分片,加法,乘法等操作,并且字符串也是不可变的变量。

find

1
2
3
4
5
# find函数用于找字符串中的子串的位置
astr = 'this is a dog'
astr.find('is') # 返回第一个子串出现的位置
astr.find('is',4) # 指定起始位置
astr.find('is',4,7) # 指定起始和结束位置

split

1
2
3
# split 指定一个分割符对字符串进行分割
a = 'a,b,c,d'
a.split(',') # 返回一个list数组

join

1
2
3
# join 函数类似于split的逆函数
','.join(['1','2','3']) # 得到一个字符串:'1,2,3'
''.join(['a','b','c']) # 得到一个字符串:‘abc’

strip

1
2
3
4
5
# 用于删除左右两边的空格
a = ' sdssd '
a.strip() # a = 'sdssd'
a = '##sadsd sasd%%%'
a.strip('#%') # 删除左右两边的#与%

replace

1
2
3
# 用于体会匹配项
a = 'this is a dog'
a.replace('is','isnt') # a = 'this isnt a dog'

lower/upper

1
2
3
# 返回字符变大或者变小的结果
a = 'ABC'
a.lower() # 放回abc,但是a仍然不变

dict 字典

dict是有key-value组成的一个类型。

创建,遍历字典

1
2
3
4
5
6
7
adict = {}
adict['a'] = 1
# 遍历
for k in adict:
print(k,adict[k])
for k in adict.keys():
print(k,adict[k])

判断元素是否在字典中

1
2
3
4
5
d = {}
d['a'] = 1
d['b'] = 2
if 'b' in d:
print('b is a key')

clear

1
d.clear() # 清空所有项

copy

1
2
3
4
5
# 浅复制
d2 = d1.copy() # 对d2的改变同样也会改变d1
# 深复制,生成许多独立的样本
from copy import deepcopy
d2 = deepcopy(d1) # d2与d1无关

get

1
2
3
#访问字典中的元素
d.get('key_val') # 返回值,如果没有的话返回None
d.get('key_val',;'default val') # 如果无,放回default val

update

1
2
3
4
#将两个字典进行相加
a = {'a':1}
b = {'b':2}
b.update(a) # b = {'a':1,'b':2}

Items,keys,values

1
2
3
4
5
6
7
8
#items将dict项以list的方式返回,keys将key以list的方式返回
d = {'a':1,'b':2,'c':3}
for k ,v in d.items():
pass
for k in d.keys():
pass
for v in d.values():
pass

pop

1
2
3
4
#删除key
d = {'a':1,'b':2}
d.pop('a') # 返回a的val 1
d.popitem() # 随机删除掉一对键值对

对字典进行排序

1
2
3
4
student = [{'name': 'john', 'score': 'B', 'age': 15},
{'name': 'jane', 'score': 'A', 'age': 12},
{'name': 'dave', 'score': 'B', 'age': 10}]
sorted(student,key = lambda stu:stu['age'])

set

set是一个元素不重合的集合。

1
2
3
4
5
6
a = set()
a.add('0') # 添加元素
#遍历集合
for e in a:
print(e)
e.remove('0') # 删除元素

交集,并集,差集

1
2
3
4
5
6
7
s1 = {1,2,3}
s2 = {3,4,5}
s3 = s1&s2 # 交集,s3 = {3}
s4 = s1|s2 # 并集,s4 = {1,2,3,4,5}
s5 = s1 - s2 # 差集,s5 = {1,2}
# 判断是否是子集
s1.issubset(s2) # s1是否是s2的子集

参数组合

1
2
3
4
5
def func(x, y, z=0, *args, **kwargs):
pass
# 其中x,y为必须传入的参数,z默认参数,
# *args 接受无限制的值参数,变为一个list
#**kwargs 接受键值参数,最后变成一个dict

map

1
2
3
4
def square(x):
return x
a = [1,2,3]
map(square,a) # 返回值为[1,4,9]

reduce

1
reduce(lambda x, y: x * y, [1, 2, 3, 4])  # 相当于 ((1 * 2) * 3) * 4

filter

1
filter(lambda x: x < 'g', 'hijack') # 返回 ac

装饰器

1
2
3
4
5
6
7
8
def makeitalic(func):
def wrapped():
return "<i>" + func() + "</i>"
return wrapped

@makeitalic
def hello():
return 'hello world'

即调用hello的时候会提前调用makeitalic,对hello进行装饰。

pdb python调试工具

pdb是调试代码的一个工具包,主要特性包括设置断点、单步调试、进入函数调试、查看当前代码、查看栈片段、动态改变变量的值等。

1
2
3
4
5
6
7
import pdb 
a = "aaa"
pdb.set_trace()
b = "bbb"
c = "ccc"
final = a + b + c
print final

代码在set_trace()处进入暂停,输入n + enter进入下一行,下一次敲回车将重复上一个操作。输入q退出程序。在控制台允许执行print等代码来获取结果。

查看当前位置前后11行的代码。

1
l

查看当前所有的代码。

1
ll

添加断点:

1
2
b line-number
tbreak line-number # 添加临时断点

清除断点:

1
2
cl # 	清除所有断点
cl line-number # 清除该行断点

打印变量:

1
p expression

逐行调试:

1
2
3
4
5
6
n 下一条
s 下一行,能进入函数题
r 跳过函数体
c 跳到下一个断点
unt line-number 一直执行到line-number
a 查看函数参数

关于python的相对导入问题

python包导入的时候不同的层级关系可以使用... 来表示上一层目录和当前目录。这种层级关系是通过module中__name__字段来定义的,如下:

1
2
3
4
5
6
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleA.py

在这个package的同级目录中调用moduleX.py文件时,该文件__name__.package.subpackage1.moduleX,因此该moduleX反过来去调用moduleA,可以写作from .. import moduleA 。但是如果在同一个文件目录下执行脚本的话,该文件夹下就会变成top-level script,name就变成了__main__,因此层级结构就会失效。

因此含有这些层级结构的脚本,不允许直接运行,而是需要由外层的文件来间接调用。

python 捕获异常

1
2
3
4
5
6
7
from traceback import print_exc
try:
if something wrong
except Exception, e:
print 'type is:', e.__class__.__name__
print_exc()
# print "exception happened!"