zoukankan      html  css  js  c++  java
  • 廖雪峰Python电子书总结

    函数

    1.注意:函数的默认参数必须指向不可变对象

    未修改前:

    def add_end(L=[]):     
         L.append('END')     
         return L
    

    存在的问题:如果连续调用多次,会出现多个 'END' 对象

    原因解释:

    Python函数在定义的时候,默认参数L就被计算出来了,即 [] ,因为默认参数L指向了可变对象[],每次调用的时候,如果改变了L的内容,下次调用的时候,L指向的内容也发生了改变,不再是函数定义时候的 [] 了。

    修改后:

    def add_end(L=None):    
         if L is None:         
             L = []   
         L.append('END')     
        return L
    

     这样无论调用多少次都不会出问题。

    2.关键字参数

      func(xx,xxx,**kw)

    def person(name,age,**kw):
        print('name:',name,'age:',age,'other:',kw)
    
    extra = {'city': 'BeiJing','job': 'Python'}
    person('XM',23,**extra)
    
    # 输出
    # name: XM age: 23 other: {'city': 'BeiJing', 'job': 'Python'}
    

       注意:**extra表示把extra这个dict的所有key-value用关键字参数传递给函数的**kw参数,kw将获得一个dict,注意获得dict是extra的一份拷贝,修改kw不会对extra有任何影响。

    高级特性模块

    1.迭代器

    可以被next()函数调用并不断返回下一个值的对象成为迭代器Iterator,可以使用isinstance()判断一个对象是否是Iterator对象

    >>> from collections import Iterator
    >>> isinstance((x * x for x in range(10)),Iterator)
    True
    >>> isinstance([],Iterator)
    False
    >>> isinstance({},Iterator)
    False
    

     生成器都是Iterator对象,但是list、dict、str、虽然是Iterable,却不是Iterator。

    把list、dict、str等Iterable变成Iterator,可以使用iter()函数

    >>> isinstance(iter([]),Iterator)
    True
    >>> isinstance(iter({}),Iterator)
    True

    函数式编程

    fitler用法

    把一个序列中的空字符串删掉

    # 1.把一个序列中的空字符串删掉
    def not_empty(s):
        return s and s.strip()
    
    li = ['A','',None,'B',' ','C']
    li = list(filter(not_empty,li))
    print(li)

    闭包

    返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量

    # 返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量
    def count():
        fs = []
        for i in range(1,4):
            def f():
                return i * i
            fs.append(f)
        return fs
    
    f1,f2,f3 = count()
    print(f1()) # 输出9
    print(f2()) # 输出9
    print(f3()) # 输出9

    # 原因就在于返回的函数引用了变量i,但它并非立刻执行,等到3个函数都返回时,他们所引用的变量i,已经变成了3
    # 因此最终结果都为9
    # 如果一定要引用循环变量怎么办?方法就是在创建一个函数,用该函数的参数绑定循环变量当前的值,无论循环变量后期如何变化 # 已绑定到函数参数的值不变 def count(): def f(j): def g(): return j * j return g fs = [] for i in range(1,4): fs.append(f(i)) return fs f1,f2,f3 = count() print(f1()) # 输出1 print(f2()) # 输出4 print(f3()) # 输出9

    装饰器

    # 定义装饰器
    def log(func):
        def wrapper(*args,**kwargs):
            print('call %s()' % func.__name__)
            func(*args,**kwargs)
        return wrapper
    
    
    @log
    def now():
        print('2018-04-25')
    
    # 调用now函数
    now()
    
    # 输出
    # call now()
    # 2018-04-25
    

    解释:把@log放到now()函数定义处,相当于执行了语句
    now = log(now)
    由于log()是一个decorator,返回一个函数,所以原来的now()函数仍然存在,只是现在同名的now()指向了新的函数,于是调用now()将执行新的函数,即在log()函数中返回的wrapper()函数

    如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数

    def log(txt):
        def decorator(func):
            def warpper(*args,**kwargs):
                print('%s  %s' % (txt,func.__name__))
                return func(*args,**kwargs)
            return warpper
        return decorator
    
    @log('execute')
    def now():
        print('2018-04-25')
    
    # 调用now()函数
    now()
    print('%s' % now.__name__)
    
    # 输出
    # execute  now
    # 2018-04-25
    # wrapper

    解释:和两层嵌套decorator相比,3层嵌套的效果是这样的:
    now = log('execute')(now)
    我们来剖析上面的语句,首先执行log('execute')返回的是decorator()函数,在调用返回的函数参数是now()函数,返回值最终是wrapper()函数

    最后一步:因为我们讲的是函数也是对象,他有__name__等属性,但是你去看经过decorator()函数装饰之后的函数,他们的__name__已经从原来的的'now'变成'wrapper'了
    所以需要将原始函数的__name__等属性复制到wrapper()函数中,否则又一些以来函数签名的代码执行要出错。
    不需要编写wrapper.
    __name__ = func.__name__这样的代码,Python中内置了functools.wraps就是干这事的,所以一个完整的decorator的写法如下:

    from functools import wraps
    
    def log(func):
        @wraps(func)
        def wrapper(*args,**kwargs):
            print('call %s' % func.__name__)
            return func(*args,**kwargs)
        return wrapper
    
    @log
    def now():
        print('2018-04-25')
    
    # 调用函数
    now()
    print(now.__name__)
    
    # 输出
    # call now
    # 2018-04-25
    # now
    
    def log(txt):
        def decorator(func):
            @wraps(func)
            def wrapper(*args,**kwargs):
                print('%s  %s' % (txt,func.__name__))
                return func(*args,**kwargs)
            return wrapper
        return decorator
    
    @log('execute')
    def now():
        print('2018-04-25')
    
    # 调用函数
    now()
    print(now.__name__)
    
    # 输出
    # execute  now
    # 2018-04-25
    # now

    偏函数  

    通过functools.partial可以帮助我们创建一个偏函数

    from functools import partial

    int2 = partial(int,base=2) ret = int2('100') print(ret) # 输出 # 2 max2 = partial(max,10) ret = max2(2,3,4) print(ret) # 输出 # 10

    简单总结functools.partial的作用,就是把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新的函数会更简单

    面向对象编程

    需要注意的是,在Python中,变量名类似__xxx__的,也就是双下划线开头,双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以不能用__name__、__score__这样的变量名

    双下划线开头的实例变量是不是就不能被外部访问了?其实不是的,不能只能访问__name是因为Python解释器对外吧__name变量改成了_Student__name,所以可以通过_Student__name来访问__name变量:

      bart._Student__name

    但是强烈不推荐这么做,因为不同版本的Python解释器可能会把__name改成不同的变量名

    如何判断一个对象是否是函数怎么办?可以使用types模块中定义的常量:

    import  types
    
    def Animals():
        pass
    a = Animals()
    print(type(Animals) == types.FunctionType)

    如何给实例绑定一个方法?

    class Student():
        pass
    
    def set_age(self,age): # 定义一个函数作为实例方法
        self.age = age
    
    s = Student()
    
    from types import MethodType
    
    s.set_age = MethodType(set_age,s) # 给实例绑定一个方法
    s.set_age(25) # 调用实例方法
    print(s.age) # 测试结果

    为了给所有实例都绑定方法,可以给class绑定方法:

    Student.set_age = MethodType(set_age,Student)
    
    s1 = Student()
    s1.set_age(12)
    print(s1.age)
    
    s2 = Student()
    s2.set_age(23)
    print(s2.age)

    __slots__的使用

    如果我们想要限制实例的属性怎么办?比如,只允许对Student实例添加name和age属性。

    为了达到目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性:

    class Student:
        __slots__ = ('name','age') # 用tuple定义绑定的属性名称
    
    s = Student()
    s.name = 'XM'
    s.age = 34
    s.score = 98 # 绑定属性score 报错
    
    # AttributeError: 'Student' object has no attribute 'score'

    除非在子类中也定义__slots__,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__

    class GraduateStudent(Student):
        __slots__ = ('score') # 除非子类也定义__slots__,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__
        pass
    
    g = GraduateStudent()
    g.score = 97
    g.name = 'DN'

    @property的使用

    class Student:
    @property
    def score(self): return self._score @score.setter def score(self,value): if not isinstance(value,int): raise ValueError('score must be int') if value < 0 or value >100: raise ValueError('score must be 0~100') self._score = value s = Student() s.score = 90 print(s.score)

    注意到这个神奇的@property,我们在对实例属性操作的时候,就知道该属性很可能不是直接暴漏的,而是通过getter和setter方法实现的。还可以设置只读属性,不定义setter方法就是只读属性

    __str__和__repr__的区别?

    在不使用print的时候,直接显示变量的调用的不是__str__(),而是__repr__(),两者的区别是__str__()返回用看到的字符串,而__repr__()返回程序开发者看到的字符串,也就是说,__repr__()是为了调试服务的。

    偷懒的写法是

    class Student:
        def __init__(self,name):
            self.name = name
    
        def __str__(self):
            print('Student object(name = %s)' % self.name)
    
        __repr__ = __str__

    __iter__

    如果一个类想被用于for...in循环,类似list或tuple那样,就是必须实现一个__iter__()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断的调用迭代对象的__next__()方法,拿到循环的下一个值,直到StopIteration错误时推出循环。

    # 以斐波那契数列为例,写一个Fib类
    class
    Fib: 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 # 计算下一个值 if self.a > 100: raise StopIteration() return self.a for n in Fib(): print(n)

    __getitem__/__setitem__/__delitem__的使用方法

    Fib实例虽然能作用于for循环,看起来和list有点像,但是,把它当成list来使用还是不行,如果要表现的和list那样按照下标取元素,需要实现__getitem__()方法

    class Fib:
        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 # 计算下一个值
            if self.a > 100:
                raise StopIteration()
            return self.a
        
        def __getitem__(self, item):
            a,b = 1,1
            for x in range(item):
                a,b = b,a+b
            return a
    
    for n in Fib():
        print(n)
    
    print(Fib()[5]) # 8
    print(Fib()[10]) # 89

    但是list有个神奇的切片方法:

    list(range(100))[5:10]

    对于Fib却报错,原因是__getitem__()传入的参数可能是一个int,也可以是一个切片对象slice,所以要做判断:

    class Fib:
        def __getitem__(self, item):
            if isinstance(item,int):
                a,b = 1,1
                for i in range(item):
                    a,b = b,a+b
                return a
            if isinstance(item,slice):
                start,stop = item.start,item.stop
                if start is None:
                    start = 0
                a,b = 1,1
                L = []
                for x in range(stop):
                    if x >= start:
                        L.append(a)
                    a,b = b,a+b
                return L
    
    print(Fib()[0,5])

    与之对应的是__setitem__()方法,把对象视作list或dict来对集合赋值,最后,还有一个__delitem__()方法,用于删除某个元素

    __getattr__/__setattr__/__delattr__

    正常情况下我们调用属性或方法不存在时会报错,比如定义Student类:

    class Student:
        def __init__(self):
             self.name = 'Michel'
    
    s = Student()
    print(s.name)
    print(s.age)
    
    # Michel
    # Traceback (most recent call last):
    #   File "/Users/qianhaichao/Desktop/Python练习/练习项目/LF-Project/Python练习/廖雪峰Python/面向对象编程.py", line 169, in <module>
    #     print(s.age)
    # AttributeError: 'Student' object has no attribute 'age'

    调用name属性,没问题,但是调用不存在的age属性,就有问题了,而且很明显的告诉我们没有找到age这个attribute

    要避免这个错误,除了可以加上一个age属性外,Python还有另一个机制,那就是写一个__getattr__()方法,动态的返回一个属性,修改如下:

    class Student:
        def __init__(self):
             self.name = 'Michel'
    
        def __getattr__(self, item):
            if item == 'age':
                return 99
    
    s = Student()
    print(s.name) # Michel
    print(s.age) # 99

    返回函数也是完全可以的

    class Student:
        def __getattr__(self, item):
            if item == 'age':
                return lambda: 25
    
    s = Student()
    print(s.age()) #只是调用方式变了

    此外,注意到任意调用如s.abc都会返回None,不会报错,这是因为我们定义了__getattr__默认返回的就是None,要让class只响应特定的几个属性,我们就按照约定,抛出AttributeError的错误:

    class Student:
        def __getattr__(self, item):
            if item == 'age':
                return lambda: 25
            raise AttributeError('Student object has no attribute %s' % item)

    这实际上可以把一个类的所有属性和方法调用全部动态化处理了,不需要做任何特殊手段。

    这种完全动态调用的特性有什么实际作用呢?作用就是,可以针对完全动态的情况作调用。

    现在很多网站都搞RESTAPI,比如新浪微博、豆瓣啥的,调用API的URL类似:

    http://api.server/user/friends

    http://api.server/user/timline/list

    如果要写SDK,给每个URL对应的API都写一个方法,那得累死,而且API一旦改动,SDK也要改动。

    利用完全动态的__getattr__,我们可以写一个链式调用:

    class Chain:
        def __init__(self,path=''):
            self.path = path
    
        def __getattr__(self, attr):
            return Chain('%s/%s' % (self.path,attr))
    
        def __str__(self):
            return self.path
    
        __repr__ = __str__
    
    url = Chain().status.user.timeline.list
    print(url) # /status/user/timeline/list

    这样,无论API怎么变,SDK都可以根据URL完全动态的调用,而且不随API的增加而改变

    __call__的使用

    任何类,只需要定义一个__call__()方法,就可以直接对实例进行调用

    class Student:
        def __init__(self,name):
            self.name = name
    
        def __call__(self, *args, **kwargs):
            print('My name is %s' % self.name)
    
    s = Student('XM')
    s() # My name is XM

    __call__()还可以定义参数,对实例进行直接调用就好比对一个函数进行调用,所以你完全可以把对象看成函数,把函数看成对象,因为这两者之间本来就没啥根本的区别。

    怎么判断一个变量是对象还是函数呢?其实更多的时候,我们需要判断一个对象是否能被调用,能被调用的对象就是一个Callable对象,比如函数和我们上面定义的带有__call__()的累实例

    class Student:
        def __init__(self,name):
            self.name = name
    
        def __call__(self, *args, **kwargs):
            print('My name is %s' % self.name)
    
    print(callable(Student('XM'))) # True
    print(callable(max)) # True
    print(callable([1,2,3])) # False
    print(callable('str')) # False

    使用枚举类

    Python提供了Enum类来实现这个功能:

    from enum import  Enum
    
    Month = Enum('Month',('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
    
    for name,member in Month.__members__.items():
        print('name:',name,'member:',member,'value:',member.value)
    
    print(Month.Jan.value)

    value属性则是自动赋给成员的int常量,默认是从1开始计数的。

    如果要使用更精确的控制枚举类型,可以从Enum派生出自定义类:

    from enum import Enum,unique

    from enum import Enum,unique
    
    class Weekday(Enum):
        Sun = 0  # Sun的value被设定为0
        Mon = 1
        Tue = 2
        Wed = 3
        Thu = 4
        Fri = 5
        Sat = 6
    # @unique可以帮助我们检查保证没有重复值
    
    day1 = Weekday.Mon
    
    print(day1 == Weekday.Mon)

    元类的使用(暂且先不研究)

    单元测试

    我们来编写一个Dict类,这个类的行为和dict一致,但是可以通过属性来访问,用起来就像下面这样:

    d = Dict(a=1,b=2)
    print(d['a']) # 1
    print(d.a) # 1

    Dict.py代码如下:

    class MyDict(dict):
    
        def __init__(self,**kw):
            super().__init__(**kw)
    
        def __getattr__(self, key):
            try:
                return self[key]
            except KeyError:
                raise AttributeError('MyDict object has no %s attribute' % key)
    
        def __setattr__(self, key, value):
            self[key] = value

    为了编写单于测试,我们需要引入Python自带的unittest模块,编写TestDict.py如下:

    from Dict import MyDict
    import unittest
    
    
    class TestDict(unittest.TestCase):
    
        def test_init(self):
            d = MyDict(a=1,b='test')
            self.assertEqual(d.a,1)
            self.assertEqual(d.b,'test')
            self.assertTrue(isinstance(d,dict))
    
        def test_key(self):
            d = MyDict()
            d['key'] = 'value'
            self.assertEqual(d['key'],'value')
    
        def test_attr(self):
            d = MyDict()
            d.key = 'value'
            self.assertTrue('key' in d)
            self.assertEqual(d['key'],'value')
    
        def test_keyerror(self):
            d = MyDict()
            with self.assertRaises(KeyError):
                value = d['empty']
    
        def test_attrerror(self):
            d = MyDict()
            with self.assertRaises(AttributeError):
                value = d.empty
    
    
    if __name__ == '__main__':
        unittest.main()

    setUp与tearDown

    可以编写单元测试中编写两个特殊的setUp()和tearDown()方法,这两个方法会分别在没调用一个测试方法的前后分别被执行。

    setUp()和tearDown()方法有什么用呢?设想你的测试需要启动一个数据库,这时,就可以在setup()方法中连接数据库,在tearDown()方法中关闭数据库,这样不必在每个测试方法中重复相同的代码:

    IO编程

    multiprocess模块提供一个一个Process类来代表进程对象,下面的例子演示启动一个子进程并等待其结束:

    Process

    from multiprocessing import Process
    import os
    
    
    def run_proc(name):
        print('Run child process %s (%s)' % (name,os.getpid()))
    
    
    if __name__ == '__main__':
        print('Parent process %s' % os.getpid())
        p = Process(target=run_proc,args=('test',))
        print('Child prcess will start')
        # 启动子线程
        p.start()
        # 等待子线程结束后在继续
        p.join()
        print('Process End')

    执行结果如下:

    Parent process 27352
    Child prcess will start
    Run child process test (27353)
    Process End

    创建子进程时,只需要传入一个执行函数和函数参数,创建一个Process实例,用start()方法启动,这样创建进程比fork()还要简单,join()方法可以等待子线程结束后在继续往下运行,通常用于进程间的同步。

    Pool

    from multiprocessing import Pool
    import os,time,random
    
    def long_time_task(name):
        print('Run task %s(%s)' % (name,os.getpid()))
        start = time.time()
        time.sleep(random.random() * 3)
        end = time.time()
        print('Task %s run %.02f seconds' % (name,(end-start)))
    
    if __name__ == '__main__':
        print('Parent process %s' % os.getpid())
        p = Pool(4)
        for i in range(5):
            p.apply_async(long_time_task,args=(i,))
        print('waitting all subprocesses done')
        p.close()
        p.join()
        print('All subprocesses done.')
        
        
    # 输出结果
    # Parent process 27468
    # waitting all subprocesses done
    # Run task 0(27469)
    # Run task 1(27470)
    # Run task 2(27471)
    # Run task 3(27472)
    # Task 3 run 1.03 seconds
    # Run task 4(27472)
    # Task 2 run 1.27 seconds
    # Task 4 run 0.56 seconds
    # Task 0 run 2.53 seconds
    # Task 1 run 2.96 seconds
    # All subprocesses done.

    代码解读:

    对Pool对象调用join()方法会等待所有子进程执行完毕,调用join()之前必须调用close(),调用close()之后就不能继续添加新的Process了。

    多线程

    Python的标准库提供了两个模块:_thread和threading,_thread是低级模块,threading是高级模块,对_thread进行了封装,绝大多数情况下,我们只需要使用threading这个高级模块、

    import  threading
    import time
    
    def loop():
        print('Thread %s is running...' % threading.current_thread().name)
        n = 0
        while n < 5:
            n = n + 1
            print('Thread %s >>> %s' % (threading.current_thread().name,n))
            time.sleep(1)
        print('Thread %s end' % threading.current_thread().name)
    
    
    print('Thread %s is running' % threading.current_thread().name)
    t = threading.Thread(target=loop,name='LoopThread')
    t.start()
    t.join()
    print('Thread %s end' % threading.current_thread().name)
    
    # 输出结果
    # Thread MainThread is running
    # Thread LoopThread is running...
    # Thread LoopThread >>> 1
    # Thread LoopThread >>> 2
    # Thread LoopThread >>> 3
    # Thread LoopThread >>> 4
    # Thread LoopThread >>> 5
    # Thread LoopThread end
    # Thread MainThread end

    由于任何进程都有一个默认的线程,我们把这个线程称为主线程,主线程又可以启动新的线程,Python的threading模块有一个current_thread()函数,他永远返回当前线程的实例,主线程实例的名字叫MainThread,子线程的名字在创建是指定,我们用LoopThread命名子线程,名字仅仅在打印时用来显示。、

    正则表达式

    *表示任意一个字符(包括0个),+表示至少一个字符,?表示0个或者1个字符,用{n}表示n个字符

    常用内建模块

    datetime

    1.获取系统当前时间

    from datetime import datetime

    now = datetime.now() print(now) print(type(now))

    2.获取指定日期和时间

    dt = datetime(2018,5,3,17,9)
    print(dt)

    3.datetime转换为timestamp

    ts = dt.timestamp()
    print(ts)
    
    ts = now.timestamp()
    print(ts)

    4.timestamp转换为datetime

    ts = 1525338540
    dt = datetime.fromtimestamp(ts)
    print(dt)

    注意到timestamp是一个浮点数,他没有时区的概念,而datetime是有时区的,上述转换是在tiemstamp和本地时间做转换的。

    5.timestamp也可以直接被转换为UTC标准时区的时间

    dt = datetime.utcfromtimestamp(ts)
    print(dt)

    6.str转换为datetime

    dt = datetime.strptime('2018-05-03 17:30','%Y-%m-%d %H:%M')
    print(dt)

    7.datetime转换为str

    st = datetime.strftime(datetime.now(),'%Y-%m-%d %H:%M')
    print(st)

    8.datetime的加减

    from datetime import datetime,timedelta
    
    now = datetime.now()
    dt = now + timedelta(hours=10)
    print(dt)
    
    dt = now + timedelta(days=2,hours=3)
    print(dt)

    9.时区转换

    拿到UTC时间,并强制设置时区为UTC+0:00

    utc_dt = datetime.utcnow().replace(tzinfo=timezone.utc)
    print(utc_dt)

    astimezone()将时区转换为北京时区

    bj_dt = utc_dt.astimezone(timezone(timedelta(hours=8)))
    print(bj_dt)

    小结:

      datetime表示的时间需要时区信息才能确定一个特定的时间,否则只能视为本地时间

      如果要存储datetime,最佳方法是将其转换为timestamp在存储,因为timestamp的值与时区完全无关

    collections

    1.namedtuple   namedtuple('名称',[属性list])

    from collections import namedtuple

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

    可以根据属性名来访问tuple,使用起来十分方便

    2.deque

    使用list存储数据的时候,按索引访问元素是很快的,但是插入和删除元素就很慢了,因为list是线性储存,数据量大的时候,插入和删除效率很低。

    deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈。

    from collections import deque
    
    q = deque(['a','b','c','d'])
    q.append('x')
    q.appendleft('1')
    print(q)

    deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样可以非常高效的往头部添加和删除元素。

    3.OrderedDict

    使用dict时,key是无序的,在对dict做迭代时,我们无法确定key的顺序,如果要保证key的顺序,可以使用OrderDict:

    from collections import OrderedDict
    
    d = dict([('a',1),('b',2),('c',3)])
    print(d)
    d = OrderedDict([('a',1),('b',2),('c',3)])
    print(d)

    注意:OrderedDict的key会按照插入的顺序排列,不是可以本身排序

    OrderedDict可以实现一个FIFO(先进先出)的dict,当容量超出限制时,会删除最早添加的key

    4.Counter

    统计字符出现的个数:

    from collections import Counter
    
    c = Counter()
    for ch in 'programming':
        c[ch] = c[ch] + 1
    print(c)

    5.Struct

    pass

     

    6.hashlib

    import hashlib
    
    md5 = hashlib.md5()
    md5.update('how to use md5 in python hashlib'.encode('utf-8'))
    ret = md5.hexdigest()
    print(ret)

    如果数据量很大,可以分块多次调用update(),最后计算的结果是一样的。

     7.itertools

    首先看看itertools提供的几个无限迭代器

    cycle()传入一个队列,无限循环下去

     cs = itertools.cycle('ABC')
     for c in cs:
         print(c)

    repeat()负责把一个元素无限循环下去

     ns = itertools.repeat('A',3)
     for n in ns:
         print(n)

    takewhile()根据条件取出有限序列

     ns = itertools.count(1)
     tw = itertools.takewhile(lambda x: x < 10,ns)
     for t in tw:
         print(t)

    chain()把一组有序队列串联起来,拼成一个更大的队列

     ch = itertools.chain('ABC','XYZ')
     for c in ch:
         print(c)
     print(ch)
     print(type(ch))

    groupby()把序列中相邻且重复的序列跳出来放在一起

    gb = itertools.groupby('AABBBCCCADDDBBEEEFF')
    for key,group in gb:
        print(key,list(group))

    HTMLParser

    抓取html的商品名称

    from html.parser import HTMLParser
    
    html_str = '''
    <h3 class="tb-main-title" data-title="【金冠现货/全色/顶配版】Xiaomi/小米 小米note移动联通4G手机">
         【金冠现货/全色/顶配版】Xiaomi/小米 小米note移动联通4G手机
       </h3>
       <p class="tb-subtitle">
     【购机即送布丁套+高清贴膜+线控耳机+剪卡器+电影支架等等,套餐更多豪礼更优惠】    【购机即送布丁套+高清贴膜+线控耳机+剪卡器+电影支架等等,套餐更多豪礼更优惠】    【金冠信誉+顺丰包邮+全国联保---多重保障】
     </p>
       <div id="J_TEditItem" class="tb-editor-menu"></div>
     </div>
    <h3 class="tb-main-title" data-title="【现货增强/标准】MIUI/小米 红米手机2红米2移动联通电信4G双卡">
         【现货增强/标准】MIUI/小米 红米手机2红米2移动联通电信4G双卡
       </h3>
       <p class="tb-subtitle">
     [红米手机2代颜色版本较多,请亲们阅读购买说明按需选购---感谢光临] 【金皇冠信誉小米手机集市销量第一】【购买套餐送高清钢化膜+线控通话耳机+ 剪卡器(含还原卡托)+ 防辐射贴+专用高清贴膜+ 擦机布+ 耳机绕线器+手机电影支架+ 一年延保服务+ 默认享受顺丰包邮 !
     </p>
       <div id="J_TEditItem" class="tb-editor-menu"></div>
     </div>
    '''
    
    # 定义一个MyHTMLParser继承自HTMLParser
    class MyHTMLParser(HTMLParser):
        re = [] # 放置结果
        flag = 0 # 标志是否是我们想要的标签
    
        def handle_starttag(self, tag, attrs):
            if tag == 'h3':
                for attr in attrs:
                    if attr[0] == 'class' and attr[1] == 'tb-main-title':
                        self.flag = 1
                        break
            else:
                pass
    
        def handle_data(self, data):
            if self.flag:
                self.re.append(data.strip())
                self.flag = 0 # 重置标记位
            else:
                pass
    
    myparser = MyHTMLParser()
    myparser.feed(html_str)
    
    print(myparser.re)
  • 相关阅读:
    input输入密码变黑点密文
    清除浮动的几种方法
    const let,console.log('a',a)跟console.log('a'+a)的区别
    Egret Wiing3快捷键
    时间转换成2016/12/29 14:23:09格式
    http status code
    构造函数模式
    Log4net
    Autofac
    WebApi返回Json格式字符串
  • 原文地址:https://www.cnblogs.com/it-q/p/8885721.html
Copyright © 2011-2022 走看看