《Python高级编程技巧》学习笔记

2-1列表、字典、集合筛选数据

  • filter
from random import randint
data = [randint(-10,10) for _ in xrange(10)]
filter(lambda x : x>=0,data)  
  • 推导式

在 Ipython 中使用 timeit可以进行计时
timeit filter(lambda x : x =='a',data)

2-2命名元祖

from collections import namedtuple 
p = namedtuple('Point',['x','y'])
p.x,p.y=1,2
print p.x+p.y

2-3 统计元素出现频率

from collections import Counter
from random import randint

data = [randint(0,20) for _ in xrange(20)]
c = Counter(data)
print c.most_common(1)

2-4根据字典的值排序

  • 使用 zip
  • 使用 sort
from random import randint                                                               
d = {x:randint(0,100) for x in 'xyzabc'}  
print sorted(zip(d.values(),d.keys()))
print sorted(d.items(),key=lambda x:x[1])

2-5获取字典公共键

1.使用 viewkeys 方法获得集合再取交集
2.使用 map函数获取所有字典的 key 的集合
3.使用 reduce函数依次取交集

from random import randint,sample
s1={x:randint(1,4) for x in sample('abcdefg',randint(3,6))} 
s2={x:randint(1,4) for x in sample('abcdefg',randint(3,6))} 
s3={x:randint(1,4) for x in sample('abcdefg',randint(3,6))} 
reduce(lambda a,b:a&b,map(dict.viewkeys,[s1,s2,s3])) 

2-6有序字典

from time import time
from random import randint
from collections import OrderedDict
d = OrderedDict()
players = list('ABCDEFGH')
start = time()

for i in xrange(8):
    raw_input()
    p = players.pop(randint(0,7-i))
    end = time()
    print i+1,p,end -start,
    d[p]=(i+1,end-start)
    
print

for k in d:
    print k,d[k]                            

2-7利用队列实现历史记录

from collections import deque 
q = deque([],5) 

3-1可迭代对象和迭代器对象

  • 可迭代对象能够通过iter()函数得到一个迭代器对象
  • 实现了__iter____getitem__方法的对象是可迭代对象

3-2实现可迭代对象和迭代器

  • 可迭代对象,要实现__iter__方法,该方法要返回一个迭代器。
  • 迭代器要实现一个next()函数,该函数返回一个结果,同时需要在结束时抛出StopIteraion异常
  • 可以直接把__iter__实现为一个生成器

3-4实现反向迭代

  • 实现__reversed__函数
class FloatRange:
    def __init__(self, start, end, step=0.1):
        self.start = start
        self.end = end
        self.step = step

    def __iter__(self):
        t = self.start
        while t <= self.end:
            yield t
            t += self.step

    def __reversed__(self):
        t = self.end
        while t >= self.start:
            yield t
            t -= self.step
for x in reversed(FloatRange(1.0, 4.0, 0.5)):
    print x

3-5对可迭代对象使用切片

from itertools import islice 

Docstring:
islice(iterable, [start,] stop [, step]) –> islice object

Return an iterator whose next() method returns selected values from an
iterable. If start is specified, will skip all preceding elements;
otherwise, start defaults to zero. Step defaults to one. If
specified as another value, step determines how many values are
skipped between successive calls. Works like a slice() on a list
but returns an iterator.
Type: type

这个函数使用后,会消耗掉已经生成的元素

3-6同时迭代多个可迭代对象

  • 并行:zip()
  • 串行:from itertools import chain

4-1拆分多种分隔符的字符串

  • 反复使用split函数
def mysplit(s,ds):                                                               
      res = [s]                                                                    
      for d in ds:                                                                 
          t = []                                                                   
          map(lambda x : t.extend(x.split(d)),res)                                 
          res = t                                                                  
      return res 
  • 使用re.split()函数

4-3 如何调整字符串中文本的格式

re.sub('(\d{4})-(\d{2})-(\d{2})',r'\2/\3/\1',log)  

4-4拼接多个短字符串

  • 累加
  • join()函数,接受一个可迭代的字符串对象

4-5 如何对字符串进行左, 右, 居中对齐

  • str.ljust(),str.rjust(),str.center()
s.ljust(20,'*')                                                                 
Out[13]: 'abc*****************'
  • format()配置参数>20 <20 ^20
format(s,'<20')                                                                 
Out[19]: 'abc                 ' 

4-6 如何去掉字符串中不需要的字符

  • strip(),lstrip(),rstrip()去除两端字符
  • re.sub或者replace
  • translate

S.translate(table [,deletechars]) -> string

Return a copy of the string S, where all characters occurring
in the optional argument deletechars are removed, and the
remaining characters have been mapped through the given
translation table, which must be a string of length 256 or None.
If the table argument is None, no translation is applied and
the operation simply removes the characters in deletechars.
Type: builtin_function_or_method

5 文件操作

6 解析 cvs,xml,excel,json

6.1解析 cvs

import cvs
rf = open('file.cvs','rb')
reader = cvs.reader(rf)#生成器
reader.next()

wf = open('file.cvs','r')
writer = cvs.writer(wf)#生成器
writer.next()


6.2解析 xml

7 类与对象

7-1 如何派生内置不可变类型并修改实例化行为

派生一个元组类型,只保留整型

class IntTuple(tuple):
    def __new__(cls,iterable):
        g = (x for x in iterable if isinstance(x,int))
        return super(IntTuple,cls).__new__(cls,g)
        
    def __init__(self,iterable):
        super(IntTuple,self).__init__(iterable)
        
t = IntTuple([1,-1,'abc',['x','y'],3])
print t

7-2 利用__slot__来节省对象的内存开销

当我们不使用__slot__时,类对象使用一个 dict 来对对象的属性进行动态绑定。对象的属性就是该字典中的一个元素,可以动态添加或解除。

p = Player()
p.__dict__['x']=1
>> p.x = 1

该机制需要维护一个字典,占据大量空间。

使用预定义的 __slot__ = ['x','y'],可以预定义对象的属性,不允许动态添加。

7-3 如何让对象支持上下文管理

让对象支持 with 语句,需要定义 __enter____exit__函数

def __enter__(self):
    self.tn = Telnet()
    return self
def __exit__(self):
    self.tn.close()

当发生异常时,能正确调用__exit__,如果该函数返回一个 True,则可以压制 with 语句中的异常。

7-4 如何创建可管理的对象属性

利用 getter 和 setter 来管理对象属性,但是这样做调用起来比较麻烦。可以使用@property装饰器来简化

class Student(object):

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

    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value

当然也可以利用property() 函数

R = property(getter,setter)
C.R = 1 #调用 getter
print C.R #调用 setter

7-5 如何让类支持比较操作

  • 实现 __lt__,__ie__,__gt__,__ge__,__eq__,__ne__
  • 装饰器 @total_ordering可以通过逻辑运算自动进行推测,我们可以只定义小于和等于两种比较运算符
  • 对于两个不同的类的对象,如果其中一个类实现了比较,那么当这个类作为比较运算符的左值时才可以正确执行,否则不等式两边的类都要实现全部相关比较操作符
  • 为了应对上述问题,我们可以定义一个抽象的公共基类
from abc import abstractmethod
class shape(object):
    @abstractmethod
    def area(self):
        pass
    def __lt__(self,obj):
        return self.area()<obj.area()

class rect(shape):
    def area(self):
        return self.x * self.y
class tri(shape):
    def area(self):
        return 0.5*self.x * self.h

7-6 如何使用描述符对实例属性做类型检查

8 多线程

8-1 如何使用多线程


from threading import Thread

class myThread(Thread):
    def __init__(self,sid):
        Thread.__init__(self)
        self.sid = sid
    def run(self):
        handle(self.sid)
 
threads = []       
for i in range(1,11):
    t = myThread(i)
    threads.append(t)
    t.start()
for t in threads:
    t.join() #必须在不同的循环中调用 join 否则会依次阻塞变成线性执行

python 中的线程只适合处理 IO 密集型操作而不是 CPU 密集型操作

8-2 如何线程间通信

定义两个线程,DownloaderCoverter前者是生产者,后者是消费者
可以通过一个全局变量来进行数据通信,但是再操作数据前要调用 lock 函数加锁。或者可以使用线程安全的数据结构,例如from Queue import Queue
通常情况下,使用全局变量是不优雅的,可以通过构造器将队列传入,并使用 self.queue来维护。

8-3 如何在线程间进行事件通知

每下载100个 xml 文件,通知压缩线程来压缩,压缩线程执行完毕后,再通知下载函数继续下载

ipython 中输入!开头的命令,可以执行 shell 命令

from threading import Event,Thread    
class CovertThread(Thread):
    def __init__(self,cEvent,tEvent):
        Thread.__init__(self)
        self.cEvent = cEvent
        self.tEvent = cEvent
        self.count = 0
    def csv2xml(self,data,wf):
        pass
    def run():
        count = 1
        while True:
            self.csv2xml(data,wf):
                count +=1
            id count == 100:
                self.cEvent.set()
                self.tEvent.wait()
                self.cEvent.clear()
                count = 0
class TarThread(Thread):
    def __init__(self,cEvent,tEvent):
        Thread.__init__(self)
        self.cEvent = cEvent
        self.tEvent = cEvent
        self.count = 0
        self.setDaemon(True) #设置为守护进程
    def tarXml(self):
        self.count += 1
        tfname = '%d.tar'%self.count
        tf = tarfile.open(tfname,'w:gz')
        for fname in os.listdir('.'):
            if fname.endwith('xml'):
                tf.add(frame)
                os,remove(fname)
        tf.close()
        
        if not tf.members:
            os.remove(tfname)
    def run(self):
        while True:
            self.cEvent.wait() #等待事件
            self.tarXml() #打包
            self.cEvent.clear() #清空当前状态
            self.tEvent.set() #发送消息

共同维护两个 Event,并通过 set 和 wait 来发送消息,通过clear 清除当前状态。

8-4 如何使用线程本地数据

    原文作者:软体动物Ai
    原文地址: https://www.jianshu.com/p/f112c7c511dc
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞