pull/1/head
wanglei 2020-08-09 22:46:19 +08:00
parent d58c40d3d6
commit cbc4e335f7
11 changed files with 1239 additions and 0 deletions

View File

@ -0,0 +1,14 @@
在python中想用graphviz画图的时候发现报了如下异常
```
RuntimeError: failed to execute ['dot', '-Tpdf', '-O', 'test'], make sure the Graphviz executables are on your systems' path
```
很奇怪啊。python里面明明已经安装好了graphviz。。。
经过google搜索发现是系统也需要安装graphviz。。。
```
sudo apt-get install graphviz
```
系统安装graphviz完毕以后代码就可以正常运行。

View File

@ -0,0 +1,90 @@
## 1.np.repeat VS np.tile
repeat与tile函数都是复制相关的操作。
tile操作是复制的多维数组本身
```
"""
Construct an array by repeating A the number of times given by reps.
“”“
```
repeat操作复制的则是多维数组的每个元素
```
"""
Repeat elements of an array.
"""
```
## 2.np.repeat
```
>>> np.repeat(3, 4)
array([3, 3, 3, 3])
```
上面的操作得到一个长度为4的数组
```
>>> x = np.array([[1,2],[3,4]])
>>> np.repeat(x, 2)
array([1, 1, 2, 2, 3, 3, 4, 4])
```
上面先将高维的数组flatten至一维然后进行复制。
```
>>> np.repeat(x, 3, axis=1)
array([[1, 1, 1, 2, 2, 2],
[3, 3, 3, 4, 4, 4]])
```
axis=1是按行进行操作。
```
>>> np.repeat(x, [1, 2], axis=0)
array([[1, 2],
[3, 4],
[3, 4]])
```
axis=0相当于按照行进行复制并且前面的list [1,2]指定了按照不同的行复制不同的次数。
## 3.np.tile
注意tile不需要指定axis
```
>>> a = np.array([0, 1, 2])
>>> np.tile(a, 2)
array([0, 1, 2, 0, 1, 2])
```
```
>>> np.tile(a, (2, 2))
array([[0, 1, 2, 0, 1, 2],
[0, 1, 2, 0, 1, 2]])
>>> np.tile(a, (2, 1, 2))
array([[[0, 1, 2, 0, 1, 2]],
[[0, 1, 2, 0, 1, 2]]])
```
```
>>> b = np.array([[1, 2], [3, 4]])
>>> np.tile(b, 2)
array([[1, 2, 1, 2],
[3, 4, 3, 4]])
>>> np.tile(b, (2, 1))
array([[1, 2],
[3, 4],
[1, 2],
[3, 4]])
```
```
>>> c = np.array([1,2,3,4])
>>> np.tile(c,(4,1))
array([[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4]])
```

View File

@ -0,0 +1,186 @@
## 1.java里get/set方法
大部分的同学开始写java代码的时候最初始的代码肯定是字段的get/set方法。大家对于java特别冗长的诟病很大一部分来自于无处不在的get/set方法。甚至国内有相当一部分不负责任的java书籍里面靠大段的get/set代码来拼凑篇幅。。。
来个最简单的例子,估计大家都写过类似的代码:
```
public class Person {
private int age;
public Person(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
```
## 2.python里的get/set方法
python里如果按java的那一套写法代码应该像是这样
```
class Person(object):
def __init__(self):
self._age = None
def get_age(self):
return self._age
def set_age(self,age):
if(isinstance(age,str)):
self._age = int(age)
elif(isinstance(age,int)):
self._age = age
```
显然这是java风格的代码python的哲学是简洁明了这么麻烦的代码显然不是我们想要的。如果我们想直接访问上面Person类的age属性也得使用get/set方法否则会报错
```
p = Person()
p.set_age("18")
print p.get_age() #OK,没问题
print p.age #会报错,'Person' object has no attribute 'age'
```
## 3.property方法
如果我们想在py中直接访问属性比如想在上面的例子中直接访问Person的age字段可以在Person类的最后加如下一行代码
```
age = property(get_age,set_age)
```
这样我们就直接可以访问age字段了
```
p = Person()
p.age = 18
print p.get_age() #OK没问题返回的结果是18
print p.age #OK没问题返回的结构也是18
```
上面是用函数模式的方式来使用property的。当然我们也可以用装饰器的模式使用。
```
class Person(object):
def __init__(self):
self._age = None
@property
def age(self):
return self._age
@age.setter
def age(self,age):
if isinstance(age,str):
self._age = int(age)
elif isinstance(age,int):
self._age = age
@age.deleter
def age(self):
del self._age
p = Person()
p.age = "18"
print p.age #18
del p.age
print p.age #报错,AttributeError: 'Person' object has no attribute '_age'
```
上面使用property装饰器模式的时候注意几个小点
1.三个函数的名字与字段名是一样的。
2.使用proterty可以比较简单实现字段的读写控制。例如想要字段为只读属性那么只需要提供getter方法上面的setter方法可以去掉。
## 4.用property定义需要计算的属性
同时我们还可以用property来定义需要进行计算的字段。这些字段不会保存在对象中只有当我们实际需要的时候才会完成真正计算。
```
class Person(object):
def __init__(self):
self._age = None
@property
def age(self):
return self._age
@age.setter
def age(self,age):
if isinstance(age,str):
self._age = int(age)
elif isinstance(age,int):
self._age = age
@property
def height(self):
return self.age * 10
p = Person()
p.age = ("18")
print p.height #180
```
上面的例子,就是根据年龄来推算身高。。
## 5.property的基本原理
在python中property()是一个内置的函数。他的原型如下:
```
def __init__(self, fget=None, fset=None, fdel=None, doc=None): # known special case of property.__init__
"""
property(fget=None, fset=None, fdel=None, doc=None) -> property attribute
fget is a function to be used for getting an attribute value, and likewise
fset is a function for setting, and fdel a function for del'ing, an
attribute. Typical use is to define a managed attribute x:
class C(object):
def getx(self): return self._x
def setx(self, value): self._x = value
def delx(self): del self._x
x = property(getx, setx, delx, "I'm the 'x' property.")
Decorators make defining new properties or modifying existing ones easy:
class C(object):
@property
def x(self):
"I am the 'x' property."
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
# (copied from class doc)
"""
pass
```
在python的源码中我们就很容易看出property的用法。其中fget是一个获取字段值的函数而fget是一个设置字段值的函数fdel是一个删除属性的函数doc是一个字符串类似于注释。从函数实现上看这些函数参数都是可选的默认为None调用的其实就是__get__,__set__,__del__方法!
```
age = property(get_age,set_age)
```
这句代码,其实可以被分解为
```
age = property()
age = age.getter(get_age)
age = age.setter(set_age)
```
不去定义名字get_age和set_age因为他们不是必须的并且污染类的命名空间。而通过property的实现方式都很简单。在python各种类库的源码中经常会遇到很多类似的代码结构。

View File

@ -0,0 +1,56 @@
## 1.zip函数的定义
zip是python中的一个内建函数平时用得不是太多。zip的签名如下:
```
def zip(seq1, seq2, *more_seqs): # known special case of zip
"""
zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]
Return a list of tuples, where each tuple contains the i-th element
from each of the argument sequences. The returned list is truncated
in length to the length of the shortest argument sequence.
"""
pass
```
从python源码中可以看出zip的大致用途:输入是n个序列返回的是一个由tuples组成的list每个tuple是输入序列中的第i个元素。如果输入的序列长度不一样那么返回的列表将按输入序列中最短的那个做截断。
## 2.用法示范
### 2.1 矩阵进行转置
```
>>>a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
```
上述列表可以描述一个二维矩阵
采用列表的方式,我们可以完成矩阵转置的需求
```
>>> [ [row[col] for row in a] for col in range(len(a[0]))]
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
```
还可以通过zip的方式:
```
>>> zip(*a)
[(1, 4, 7), (2, 5, 8), (3, 6, 9)]
```
上面的操作是利用*这个操作符将list做unzip操作。
因为列表里的类型是tuple将tuple转换成list即可
```
>>> map(list, zip(*a))
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
```
### 2.2 生成字典
```
>>> keys = [1, 2, 3]
>>> values = ['a', 'b', 'c']
>>> d = dict(zip(keys, values))
>>> d
{1: 'a', 2: 'b', 3: 'c'}
```

View File

@ -0,0 +1,100 @@
在python中经常会使用到type与isinstance两个内置的函数来判断变量属于什么类型。那么这两个函数有什么区别呢下面来简单分析一下。
## 1.type
type函数的源码如下:
```
def __init__(cls, what, bases=None, dict=None): # known special case of type.__init__
"""
type(object) -> the object's type
type(name, bases, dict) -> a new type
# (copied from class doc)
"""
pass
```
此部分代码位于__builtin__.py中。从这段代码可以看出type函数的用法很简单就是type(object)返回的是传入的object的类型。
## 2.isinstance
isinstance函数的源码
```
def isinstance(p_object, class_or_type_or_tuple): # real signature unknown; restored from __doc__
"""
isinstance(object, class-or-type-or-tuple) -> bool
Return whether an object is an instance of a class or of a subclass thereof.
With a type as second argument, return whether that is the object's type.
The form using a tuple, isinstance(x, (A, B, ...)), is a shortcut for
isinstance(x, A) or isinstance(x, B) or ... (etc.).
"""
return False
```
isinstance的用法为:
isinstance(object,type-or-tuple-or-class) -> bool
传入的第一个参数为对象,第二个参数为类型名(int,str,float等)或者类型名的一个列表(如(str, str, int)为一个列表),返回值为一个布尔变量。
## 3.两个函数的异同
相同点
都可以判断变量是否属于某个内建类型。
不同点
1.type只接受一个参数不仅可以判断变量是否属于某个类型还可以直接返回参数类型。而isinstance只能判断是否属于某个已知的类型不能直接得到变量所属的类型。
2.isinstance可以判断子类实例对象是属于父类的而type会判断子类实例对象和父类类型不一样。
```
class A1(object):
pass
class B1(A1):
pass
print type(A1()) is A1
print type(B1()) is A1
print isinstance(B1(), B1)
```
输出结果为:
```
True
False
True
```
从以上的分析可以看出type主要是用来获取未知变量的类型而instance可以用于继承关系的判断
## 4.旧式类type
旧式类与新式类的type()结果是不一样的。旧式类type的结果都为<type 'instance'>
```
class A1(object):
pass
class B1(A1):
pass
class C1:
pass
print type(B1())
print type(C1())
print type(C1()) is C1
```
结果如下:
```
<class '__main__.B1'>
<type 'instance'>
False
```

View File

@ -0,0 +1,168 @@
## 1.前言
虽然用python有一些年头了但是在处理中文字符串的时候还是经常会遇到UnicodeEncodeErrorUnicodeDecodeError等问题。每次都是随便调一调程序能正常run以后就不管了。不巧今天又遇到了同样的状况于是痛下决心一定要把python中的字符编码问题搞清楚。
## 2.字节与字符
计算机存储的任何数据包括各种文本、图片、音视频文件等等实际上都是一串二进制数字01字节序列组成的。相信大家都知道一个字节Byte(B)是8个比特bit(b)。
而字符自然就是符号了。比如说二十六个英文字母阿拉伯数字以及在python中最坑爹的汉字都是字符。python中遇到的字符编码问题大部分都与汉字有关系。
写过java的小伙伴都知道java中的IO模块从大的方向来说就可以分为字节流与字符流。字节流包括InputStream与OutputStream字符流包括Writer与Reader。
有的同学会有疑问,为什么要搞这么复杂?统一用字节或者字符不就行了?
字节一般用来存储与网络传输这样可以节省存储空间与网络传输带宽。而字符主要是用于显示方便大家阅读。试想你正在debug结果所有的输出是一堆01011100这种那你还不得疯了。
## 3.编码(encoding)与解码(decoding)
字符编码Character encoding、字集码是把字符集中的字符编码为指定集合中某一对象例如比特模式、自然数序列、8位组或者电脉冲以便文本在计算机中存储和通过通信网络的传递。常见的例子包括将拉丁字母表编码成摩斯电码和ASCII。其中ASCII将字母、数字和其它符号编号并用7比特的二进制来表示这个整数。通常会额外使用一个扩充的比特以便于以1个字节的方式存储。(参考文献1)
encoding是将字符转换为字节那么反过来将字节转换为字符则是decoding两者是可逆的。编码主要是为了存储传输而解码是为了方便阅读。
## 4.utf-8与unicode区别
在正式讲python字符编码问题之前还需要先扯清除unicode跟utf-8的关系。
简单来说unicode是一个字符集而utf-8是一个编码规则两者并不是同一维度的东西。
字符集:为每一个字符分配一个唯一的 ID学名为码位 / 码点 / Code Point
编码规则:将码位转换为字节序列的规则(编码/解码 可以理解为 加密/解密 的过程)
## 4.python 2.7中的字符串
python2x中的字符串实际有两种类型: str与unicode。很多时候出现的各种问题就是出现在这上面。
下面我们在python解释器中简单测试一下
```
>>> s = "你好"
>>> s
'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> type(s)
<type 'str'>
```
上面的代码可以看出s是str类型在内部的存储方式就是一堆01二进制字节序列显示出来是一串十六进制字符。
很多时候我们看到定义字符串的时候会在前面加上一个前缀u这个u其实就是表示这个字符串是unicode形式
```
>>> s = u"你好"
>>> s
u'\u4f60\u597d'
>>> type(s)
<type 'unicode'>
```
我们看看编码的过程,大家记住编码是从字符->字节
```
>>> s = u"你好"
>>> s
u'\u4f60\u597d'
>>> type(s)
<type 'unicode'>
>>> s.encode('utf-8')
'\xe4\xbd\xa0\xe5\xa5\xbd'
```
再看看解码过程,解码自然就是从字节-> 字符
```
>>> s = "你好"
>>> s
'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> type(s)
<type 'str'>
>>> s.decode("utf-8")
u'\u4f60\u597d'
```
## 5.UnicodeEncodeError
既然是UnicodeEncodeError那么应该是在字符->字节的环节出现了问题。来看下面的例子。
```
def t1():
f = open("ttt", "w")
u1 = u'你好'
f.writelines(u1 + "\n")
t1()
```
运行这段代码以后,会有如下问题:
```
TypeError: writelines() argument must be a sequence of strings
```
这个问题比较好解释writelines方法需要的是一个字符串序列而u1是个unicode。
将代码稍作修改
```
def t1():
f = open("ttt", "w")
u1 = u'你好'
f.write(u1)
t1()
```
```
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
```
调用write方法时如果传入的是字符串就直接将该str写入文件无需编码因为str本身就是一堆二进制的01字节序列。
如果是unicode那需要先用encode方法将unicode字符串转换为二进制形式的str才能保存。
重点来了刚刚我们有提到unicode -> str是encode过程。既然是encode肯定需要指定encode的方法比如最常用的utf-8。坑爹就在于python2中如果不指定encode的形式默认是用ASCII码来进行编码。
很明显ASCII只有128个拉丁字母是木有处理中文字符能力的。所以报错里面的信息就是`ordinal not in range(128)`
解决方法很简单将encode方式指定为utf-8即可。
```
def t1():
f = open("ttt", "w")
u1 = u'你好'.encode("utf-8")
f.write(u1)
t1()
```
## 6.UnicodeDecodeError
与UnicodeEncodeError对应的UnicodeDecodeError肯定就是出现在字节->字符的环节。
```
def t2():
u1 = u"啦啦啦"
print repr(u1)
byte1 = u1.encode("utf-8")
print repr(byte1)
byte1.decode("gbk")
t2()
```
```
u'\u5566\u5566\u5566'
'\xe5\x95\xa6\xe5\x95\xa6\xe5\x95\xa6'
...
UnicodeDecodeError: 'gbk' codec can't decode byte 0xa6 in position 8: incomplete multibyte sequence
```
把一个经过 UTF-8编码后生成的字节序列 '\xe5\x95\xa6\xe5\x95\xa6\xe5\x95\xa6'用GBK解码成unicode的时候因为GBK编码只有两字节而UTF-8是三字节多出来一个字节肯定无法解析。因此要防止出现UnicodeDecodeError主要就是保持编码与解码的时候所用的编码方式一致。
## 7.coding:utf-8
python代码在开头位置一般都有这么一行
```
# -*- coding: utf-8
```
作用是定义源代码的编码. 如果没有定义, 此源码中是不可以包含中文字符串的.
## 8.setdefaultencoding
在源码中经常还可以看到如下代码:
```
import sys
reload(sys)
sys.setdefaultencoding('utf8')
```
上面几行代码的作用是设置默认的string的编码格式为utf8在2.7以后已经不推荐使用这种方式了
参考文献
1.https://zh.wikipedia.org/wiki/%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81

View File

@ -0,0 +1,164 @@
## 1.Counter类
Counter类是hashtable对象的计数是dict的子类从2.7以后的版本加入。
计数器是我们常用的一个功能collections中的Counter类就提供了此功能。
```
>>> from collections import *
>>> a = Counter()
>>> b = Counter("aabbcccd")
>>> c = Counter({"a":10,"b":20})
>>> d = Counter(a=10,b=20)
>>> b["a"]
2
>>> c.most_common()
[('b', 20), ('a', 10)]
```
## 2.defaultdict类
defaultdict使用工厂函数创建字典使用的时候不用考虑缺失的key。从2.5版本后引入。
python原生的dict结构如果使用d[key]的方式访问需要先判断key是否存在。如果key在字典中不存在会抛出一个KeyError的异常。
defaultdict就是为解决这个痛点而生的。只要传入一个默认的工厂方法如果用d[key]的方式访问字典而key不存在会调用这个工厂方法使用其结果来作为这个key的默认值。
```
#!/usr/bin/env python
#coding:utf-8
from collections import *
def test_defaultdict():
members = [
['male', 'John'],
['male', 'Jack'],
['female', 'Lily'],
['male', 'Pony'],
['female', 'Lucy']
]
result_dic = defaultdict(list)
for sex,name in members:
result_dic[sex].append(name)
for k,v in result_dic.items():
print k,"\t",v
test_defaultdict()
```
最后的输出为:
```
male ['John', 'Jack', 'Pony']
female ['Lily', 'Lucy']
```
## 3.OrderedDict类
排序字典是字典的子类。从2.7版本后引入。
在python中dictset等数据结构的key是hash无序的。有时候我们需要得到排序的字典。collections中的OrderedDict类即可满足我们的上述需求。
```
#!/usr/bin/env python
#coding:utf-8
from collections import *
def test_orderdict():
raw_dic = {"watermelon":4,"grape":3,"apple":1,"mango":2}
ret_dic_by_key = OrderedDict(sorted(raw_dic.items(),key = lambda item:item[0]))
ret_dic_by_value = OrderedDict(sorted(raw_dic.items(),key = lambda item:item[1]))
ret_dic_by_keylen = OrderedDict(sorted(raw_dic.items(),key = lambda item:len(item[0])))
print "ret_dic_by_key is: "
for k,v in ret_dic_by_key.items():
print k,"\t",v
print "ret_dic_by_value is: "
for k,v in ret_dic_by_value.items():
print k,"\t",v
print "ret_dic_by_keylen is: "
for k,v in ret_dic_by_keylen.items():
print k,"\t",v
test_orderdict()
```
将代码run起来以后
```
ret_dic_by_key is:
apple 1
grape 3
mango 2
watermelon 4
ret_dic_by_value is:
apple 1
mango 2
grape 3
watermelon 4
ret_dic_by_keylen is:
grape 3
mango 2
apple 1
watermelon 4
```
## 4.namedtuple
namedtuple命名元组是一个工厂函数。从2.6版本后引入。
namedtuple主要用来产生可以使用名称来访问元素的数据对象通常用来增强代码的可读性 在访问一些tuple类型的数据时尤其好用。
```
#!/usr/bin/env python
#coding:utf-8
from collections import *
def test_namedtuple():
Point = namedtuple('Point','x y')
location = [10,20]
p = Point._make(location)
print p
print "p.x is: ",p.x
print "p.y is: ",p.y
test_namedtuple()
```
将代码run起来以后
```
Point(x=10, y=20)
p.x is: 10
p.y is: 20
```
## 5.deque
deque双端队列从2.4版本后引入。
双端队列deque是一种支持向两端高效地插入数据、支持随机访问的容器。它最大的好处就是实现了从队列 头部快速增加和取出对象: .popleft(), .appendleft() 。
从piglei同志的博客中摘取一个deque的例子
```
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
下面这个是一个有趣的例子主要使用了deque的rotate方法来实现了一个无限循环
的加载动画
"""
import sys
import time
from collections import deque
fancy_loading = deque('>--------------------')
while True:
print '\r%s' % ''.join(fancy_loading),
fancy_loading.rotate(1)
sys.stdout.flush()
time.sleep(0.08)
# Result:
# 一个无尽循环的跑马灯
------------->-------
```

View File

@ -0,0 +1,63 @@
## 1. 嵌套list
python中嵌套的list还算比较常见的一种结构。比如我们经常用嵌套两层的list来模拟矩阵:
```
>>> matrix = [[1,2,3],[4,5,6],[7,8,9]]
>>> matrix
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
```
很多时候我们想将这一个嵌套两层的list变成一个list该怎么办呢对于上面的例子我们很容易找到如下的方式就可以满足需求
```
def flatmatrix(matrix):
result = []
for i in range(len(matrix)):
result.extend(matrix[i])
print result
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flatmatrix(matrix)
```
如果嵌套的list不是两层结构而是任意的形式上面的方式就不适用了。
## 2.递归打平嵌套list
比较容易想到的是递归的方式处理任意形式的嵌套list。我们取遍历原始的list如果里面的元素是list则递归如果不是加入结果中直到原始list的所有元素遍历结束。具体代码如下:
```
def flat1(inputlist, result = None):
if result is None:
result = []
for item in inputlist:
if isinstance(item, list):
flat1(item, result)
else:
result.append(item)
return result
inputlist = ['it', 'is', ['a', ['test', 'of', ['circle', 'lists'], ','], 'please', 'like', ['it', 'and'], 'hello'], 'world']
print flat1(inputlist)
```
## 3.通过循环打平嵌套list
一般来说,递归的优势是简洁明了,容易理解。缺点则是需要递归栈,效率比较低。我们尝试用非递归的方式来实现。
```
def flat2(inputlist):
result = []
while inputlist:
head = inputlist.pop(0)
if isinstance(head, list):
inputlist = head + inputlist
else:
result.append(head)
return result
inputlist = ['it', 'is', ['a', ['test', 'of', ['circle', 'lists'], ','], 'please', 'like', ['it', 'and'], 'hello'], 'world']
print flat2(inputlist)
```
循环的过程中每次将输入list的首位元素取出来然后放到原来的位置这样就起到了解开一层嵌套的作用直到最后将所有的嵌套解开为止

View File

@ -0,0 +1,161 @@
## 1.With语句是什么?
有一些任务可能事先需要设置事后做清理工作。对于这种场景Python的with语句提供了一种非常方便的处理方式。一个很好的例子是文件处理你需要获取一个文件句柄从文件中读取数据然后关闭文件句柄。
如果不用with语句代码如下
```
file = open("/tmp/foo.txt")
data = file.read()
file.close()
```
这里有两个问题:
一是可能忘记关闭文件句柄;
二是文件读取数据发生异常,没有进行任何处理。
下面是处理异常的加强版本:
```
try:
f = open('xxx')
except:
print 'fail to open'
exit(-1)
try:
do something
except:
do something
finally:
f.close()
```
虽然这段代码运行良好,但是太冗长了。
这时候就是with一展身手的时候了。除了有更优雅的语法with还可以很好的处理上下文环境产生的异常。
下面是with版本的代码
```
with open("/tmp/foo.txt") as file:
data = file.read()
```
## 2.with如何工作?
紧跟with后面的语句被求值后返回对象的 \__enter__() 方法被调用这个方法的返回值将被赋值给as后面的变量。
当with后面的代码块全部被执行完之后将调用前面返回对象的 \__exit__()方法。
下面例子可以具体说明with如何工作
```
#!/usr/bin/env python
# with_example01.py
class Sample:
def __enter__(self):
print "In __enter__()"
return "Foo"
def __exit__(self, type, value, trace):
print "In __exit__()"
def get_sample():
return Sample()
with get_sample() as sample:
print "sample:", sample
```
运行代码,输出如下
```
bash-3.2$ ./with_example01.py
In __enter__()
sample: Foo
In __exit__()
```
正如你看到的: 1. \__enter__()方法被执行 2. \__enter__()方法返回的值 - 这个例子中是”Foo”赋值给变量sample 3. 执行代码块打印变量”sample”的值为 “Foo” 4. \__exit__()方法被调用
with真正强大之处是它可以处理异常。可能你已经注意到Sample类的 \__exit__ 方法有三个参数 val, type 和 trace。 这些参数在异常处理中相当有用。我们来改一下代码,看看具体如何工作的。
```
#!/usr/bin/env python
# with_example02.py
class Sample:
def __enter__(self):
return self
def __exit__(self, type, value, trace):
print "type:", type
print "value:", value
print "trace:", trace
def do_something(self):
bar = 1/0
return bar + 10
with Sample() as sample:
sample.do_something()
```
这个例子中with后面的get_sample()变成了Sample()。这没有任何关系只要紧跟with后面的语句所返回的对象有 \__enter__() 和 \__exit__() 方法即可。此例中Sample()的 \__enter__() 方法返回新创建的Sample对象并赋值给变量sample。
代码执行后:
```
bash-3.2$ ./with_example02.py
type: <type 'exceptions.ZeroDivisionError'>
value: integer division or modulo by zero
trace: <traceback object at 0x1004a8128>
Traceback (most recent call last):
File "./with_example02.py", line 19, in <module>
sample.do_something()
File "./with_example02.py", line 15, in do_something
bar = 1/0
ZeroDivisionError: integer division or modulo by zero
```
实际上在with后面的代码块抛出任何异常时\__exit__() 方法被执行。正如例子所示异常抛出时与之关联的typevalue和stack trace传给 \__exit__() 方法因此抛出的ZeroDivisionError异常被打印出来了。开发库时清理资源关闭文件等等操作都可以放在 \__exit__ 方法当中。
另外,\__exit__ 除了用于tear things down还可以进行异常的监控和处理注意后几个参数。要跳过一个异常只需要返回该函数True即可。
下面的样例代码跳过了所有的TypeError而让其他异常正常抛出。
```
def __exit__(self, type, value, traceback):
return isinstance(value, TypeError)
```
上文说了 \__exit__ 函数可以进行部分异常的处理如果我们不在这个函数中处理异常他会正常抛出这时候我们可以这样写python 2.7及以上版本之前的版本参考使用contextlib.nested这个库函数
```
try:
with open( "a.txt" ) as f :
do something
except xxxError:
do something about exception
```
总之with-as表达式极大的简化了每次写finally的工作这对保持代码的优雅性是有极大帮助的。
如果有多个项,我们可以这么写:
```
with open("x.txt") as f1, open('xxx.txt') as f2:
do something with f1,f2
```
因此Python的with语句是提供一个有效的机制让代码更简练同时在异常产生时清理工作更简单。
## 3.相关术语
要使用 with 语句首先要明白上下文管理器这一概念。有了上下文管理器with 语句才能工作。
下面是一组与上下文管理器和with 语句有关的概念。
上下文管理协议Context Management Protocol包含方法 \__enter__() 和 \__exit__(),支持该协议的对象要实现这两个方法。
上下文管理器Context Manager支持上下文管理协议的对象这种对象实现了\__enter__() 和 \__exit__() 方法。上下文管理器定义执行 with 语句时要建立的运行时上下文,负责执行 with 语句块上下文中的进入与退出操作。通常使用 with 语句调用上下文管理器,也可以通过直接调用其方法来使用。
运行时上下文runtime context由上下文管理器创建通过上下文管理器的 \__enter__() 和\__exit__() 方法实现,\__enter__() 方法在语句体执行之前进入运行时上下文,\__exit__() 在语句体执行完后从运行时上下文退出。with 语句支持运行时上下文这一概念。
上下文表达式Context Expressionwith 语句中跟在关键字 with 之后的表达式,该表达式要返回一个上下文管理器对象。
语句体with-bodywith 语句包裹起来的代码块,在执行语句体之前会调用上下文管理器的 \__enter__() 方法,执行完语句体之后会执行\__exit__() 方法。
## 相关链接:
1.http://blog.kissdata.com/2014/05/23/python-with.html
2.https://www.ibm.com/developerworks/cn/opensource/os-cn-pythonwith/

View File

@ -0,0 +1,11 @@
遇到一个形如$\alpha * e^{-29} = 0.1$的方程,求解$\alpha$的值。
python中的sympy模块可以很轻松地解决这个问题。具体代码如下
```
from sympy.abc import x, y, z, a, b
from sympy import exp
print sympy.solve(exp(-1 * x * 29) - 0.1, x)
```
求解可得$\alpha$的值为0.0793994859653119

View File

@ -0,0 +1,226 @@
## 1.最简单的绘制方式
绘制散点图是数据分析过程中的常见需求。python中最有名的画图工具是matplotlibmatplotlib中的scatter方法可以方便实现画散点图的需求。下面我们来绘制一个最简单的散点图。
数据格式如下:
```
0 746403
1 1263043
2 982360
3 1202602
...
```
其中第一列为X坐标第二列为Y坐标。下面我们来画图。
```
#!/usr/bin/env python
#coding:utf-8
import matplotlib.pyplot as plt
def pltpicture():
file = "xxx"
xlist = []
ylist = []
with open(file, "r") as f:
for line in f.readlines():
lines = line.strip().split()
if len(lines) != 2 or int(lines[1]) < 100000:
continue
x, y = int(lines[0]), int(lines[1])
xlist.append(x)
ylist.append(y)
plt.xlabel('X')
plt.ylabel('Y')
plt.scatter(xlist, ylist)
plt.show()
```
![这里写图片描述](https://github.com/bitcarmanlee/easy-algorithm-interview-photo/blob/master/languages/python/scatter/1.png)
## 2.更漂亮一些的画图方式
上面的图片比较粗糙,是最简单的方式,没有任何相关的配置项。下面我们再用另外一份数据集画出更漂亮一点的图。
数据集来自网络的公开数据集,数据格式如下:
```
40920 8.326976 0.953952 3
14488 7.153469 1.673904 2
26052 1.441871 0.805124 1
75136 13.147394 0.428964 1
...
```
第一列每年获得的飞行常客里程数;
第二列玩视频游戏所耗时间百分比;
第三列每周消费的冰淇淋公升数;
第四列为label:
1表示不喜欢的人
2表示魅力一般的人
3表示极具魅力的人
现在将每年获取的飞行里程数作为X坐标玩视频游戏所消耗的事件百分比作为Y坐标画出图。
```
from matplotlib import pyplot as plt
file = "/home/mi/wanglei/data/datingTestSet2.txt"
label1X, label1Y, label2X, label2Y, label3X, label3Y = [], [], [], [], [], []
with open(file, "r") as f:
for line in f:
lines = line.strip().split()
if len(lines) != 4:
continue
distance, rate, label = lines[0], lines[1], lines[3]
if label == "1":
label1X.append(distance)
label1Y.append(rate)
elif label == "2":
label2X.append(distance)
label2Y.append(rate)
elif label == "3":
label3X.append(distance)
label3Y.append(rate)
plt.figure(figsize=(8, 5), dpi=80)
axes = plt.subplot(111)
label1 = axes.scatter(label1X, label1Y, s=20, c="red")
label2 = axes.scatter(label2X, label2Y, s=40, c="green")
label3 = axes.scatter(label3X, label3Y, s=50, c="blue")
plt.xlabel("every year fly distance")
plt.ylabel("play video game rate")
axes.legend((label1, label2, label3), ("don't like", "attraction common", "attraction perfect"), loc=2)
plt.show()
```
最后效果图:
![这里写图片描述](https://github.com/bitcarmanlee/easy-algorithm-interview-photo/blob/master/languages/python/scatter/2.png)
## 3.scatter函数详解
我们来看看scatter函数的签名
```
def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None,
vmin=None, vmax=None, alpha=None, linewidths=None,
verts=None, edgecolors=None,
**kwargs):
"""
Make a scatter plot of `x` vs `y`
Marker size is scaled by `s` and marker color is mapped to `c`
Parameters
----------
x, y : array_like, shape (n, )
Input data
s : scalar or array_like, shape (n, ), optional
size in points^2. Default is `rcParams['lines.markersize'] ** 2`.
c : color, sequence, or sequence of color, optional, default: 'b'
`c` can be a single color format string, or a sequence of color
specifications of length `N`, or a sequence of `N` numbers to be
mapped to colors using the `cmap` and `norm` specified via kwargs
(see below). Note that `c` should not be a single numeric RGB or
RGBA sequence because that is indistinguishable from an array of
values to be colormapped. `c` can be a 2-D array in which the
rows are RGB or RGBA, however, including the case of a single
row to specify the same color for all points.
marker : `~matplotlib.markers.MarkerStyle`, optional, default: 'o'
See `~matplotlib.markers` for more information on the different
styles of markers scatter supports. `marker` can be either
an instance of the class or the text shorthand for a particular
marker.
cmap : `~matplotlib.colors.Colormap`, optional, default: None
A `~matplotlib.colors.Colormap` instance or registered name.
`cmap` is only used if `c` is an array of floats. If None,
defaults to rc `image.cmap`.
norm : `~matplotlib.colors.Normalize`, optional, default: None
A `~matplotlib.colors.Normalize` instance is used to scale
luminance data to 0, 1. `norm` is only used if `c` is an array of
floats. If `None`, use the default :func:`normalize`.
vmin, vmax : scalar, optional, default: None
`vmin` and `vmax` are used in conjunction with `norm` to normalize
luminance data. If either are `None`, the min and max of the
color array is used. Note if you pass a `norm` instance, your
settings for `vmin` and `vmax` will be ignored.
alpha : scalar, optional, default: None
The alpha blending value, between 0 (transparent) and 1 (opaque)
linewidths : scalar or array_like, optional, default: None
If None, defaults to (lines.linewidth,).
verts : sequence of (x, y), optional
If `marker` is None, these vertices will be used to
construct the marker. The center of the marker is located
at (0,0) in normalized units. The overall marker is rescaled
by ``s``.
edgecolors : color or sequence of color, optional, default: None
If None, defaults to 'face'
If 'face', the edge color will always be the same as
the face color.
If it is 'none', the patch boundary will not
be drawn.
For non-filled markers, the `edgecolors` kwarg
is ignored and forced to 'face' internally.
Returns
-------
paths : `~matplotlib.collections.PathCollection`
Other parameters
----------------
kwargs : `~matplotlib.collections.Collection` properties
See Also
--------
plot : to plot scatter plots when markers are identical in size and
color
Notes
-----
* The `plot` function will be faster for scatterplots where markers
don't vary in size or color.
* Any or all of `x`, `y`, `s`, and `c` may be masked arrays, in which
case all masks will be combined and only unmasked points will be
plotted.
Fundamentally, scatter works with 1-D arrays; `x`, `y`, `s`, and `c`
may be input as 2-D arrays, but within scatter they will be
flattened. The exception is `c`, which will be flattened only if its
size matches the size of `x` and `y`.
Examples
--------
.. plot:: mpl_examples/shapes_and_collections/scatter_demo.py
"""
```
其中具体的参数含义如下:
x,y是相同长度的数组。
s可以是标量或者与x,y长度相同的数组表明散点的大小。默认为20。
c即color表示点的颜色。
marker 是散点的形状。