后端开发者互联网科技

Python基础 | 小技巧

2017-06-09  本文已影响150人  采风JS

初识Python是在16年的国庆节,趁着国庆假期,弥补了些许知识。真心为其语言的简洁和美妙感动。中间陆陆续续练习过静态爬虫、简单数据处理等,收拾心情,重新整理,便于复习。

网上以廖雪峰博客为参考资料,简单明了,方便学习。实验环境为Anaconda3,自带Python3.6。下面分享一些简单的技巧,以供参考。

一、数据类型

Python中内置的四种数据类型,list(列表)、tuple(元组)、dict(字典)和set(集合)。list是可变的序列,支持多种数据类型,其列表生成器、列表解析器和切片操作,是尤为关键的。tuple简单总结为不变的列表。字典与Java中的HashMap有异曲同工之妙,而集合就是没有值,只有键的字典

1. 元组命名

# 基于IPython环境进行交互
from collections import namedtuple
Student = namedtuple('Student',['stu_id','age','tel'])
s1 =  Student('001',22,'lzw@163.com')
# 访问学生学号有两种方式
s1[0]与s1.stu_id

2. 列表中次数统计

# 基于IPython环境进行交互
# 列表生成器生成随机序列
from random import randint
list = [randint(1,10) for x in range(1,20)] # 20次循环,产生重复数字
# 方法一
list_dict = dict.fromkeys(list,0) #以list为键,0为值
for i in list:
    list_dict[i] += 1
# 方法二
from collections import Counter
list_count = Counter(list)
list_count.most_common() #以元组形式返回每个值的次数,以次数升序排列

3. 以字典中值排序

# 基于IPython环境进行交互
# 基于字典生成器生成学生成绩,针对学生成绩进行排序
from random import randint
score = {x:randint(60,100) for x in ['baby','dengchao','chenhe','liche']}
#  方法一
sorted(list(zip(score.values(),score.keys()))) #以字典的值和键相互对应生成元组列表
#  方法二
sorted(score.items(),key=lambda x:x[1])

4. 统计多个字典中的公共键

# 基于IPython环境进行交互
# 统计欧冠每轮均有进球的队员
from random import sample,randint #sample用于产生抽样个数
player=['c罗','梅西','本泽马','苏牙','内马尔','穆勒']
#在队员中随机挑选三到五个人
s1 = {x:randint(1,4) for x in sample(player,randint(3,5))}
s2 = {x:randint(1,4) for x in sample(player,randint(3,5))}
s3 = {x:randint(1,4) for x in sample(player,randint(3,5))}
# 方法 map与reduce
from functools import reduce
reduce(lambda x,y: x&y ,list(map(dict.key,[s1,s2,s3])))

二、迭代操作

廖雪峰的博客中提到,for循环中的对象为两种类型,一种list、tuple、dict和set等可迭代对象,另一种为生成器对象。同时,还存在迭代器对象。曾经也是不能非常清晰的判别这些概念,这里姑且给出一个自己的判别准则,存在iter()方法的为可迭代对象,存在next()方法的为迭代器对象,一个对象可以同时为可迭代对象和迭代器对象。

# 基于IPython环境进行交互
# 进行对象类型判别
from collections import Iterable,Iterator
l=[x for x in range(1,10)]
g = (x for x in range(1,10))
ll = iter(l)
isinstance(l,Iterable) True
isinstance(l,Iterator) False
isinstance(g,Iterable) True
isinstance(g,Iterator) True
isinstance(ll,Iterable) True
isinstance(ll,Iterator) True

1. 基于生成器的可迭代类

# 用于产生素数的类
class PrimeNumbers:
    def __init__(self,start,end):
        self.start=start
        self.end=end     
    def isPrime(self,k):
        if k <= 2:
            return False
        for i in range(2,k):
            if k % i == 0:
                return False
        return True
# 本类的关键是在__iter__函数中实现生成器,模拟next方法
    def __iter__(self):
        for k in range(self.start,self.end+1):
            if self.isPrime(k):
                # 工作原理与next方法相同
                yield k

2. 反向迭代器

class FloatRange:
    # 生成构造函数
    def __init__(self,start,end,step):
        self.start=start
        self.end=end
        self.step=step
    # 实现正向迭代器
    def __iter__(self):
        t = self.start
        while t <= self.end:
            yield t
            t += self.step      
    # 用于实现反向迭代器,实现__reversed__函数
    def __reversed__(self):
        t = self.end
        while t >= self.start:
            yield t
            t = t - self.step

三、装饰器

Python中的函数式编程思想,在《Java8实战》中学习过,其包括高阶函数、返回函数、匿名函数、偏函数等,装饰器以函数作为参数且返回函数,在函数运行时动态增强功能,其魔法糖功能让人应接不暇。选择两个合适的例子,一看究竟。

1. Fibonacci数列优化装饰器

# Fibonacci数列优化装饰器
def memo(func):
    cache={}
    def wrap(*args):
        if args not in cache:
            cache[args]=func(*args)
        return cache[args]
    return wrap
    
@memo
def fibonacci(n):
    if n <= 1:
        return 1
    res = fibonacci(n-1)+fibonacci(n-2)
    return res
# 计算fibonacci(30)需要1.68s,加上缓存装饰器后需要813ns
# 在计算fibonacci值时,存在诸多重复的值,浪费大量的时间

2. 方法元数据保存装饰器

# 方法的元数据,包括__name__,__doc__等,被包装后自动丢失
from functools import update_wrapper
def mydecorator(func):
    def wrapper(*args,**kargs):
        '''wrapper function'''
        func(*args,**kargs)
    update_wrapper(wrapper,func,('__doc__','__name__'),('__dict__',))
    return wrapper    
    
@mydecorator
def f():
    '''f function'''
    print ('in f function')

3. 检测函数参数类型

def typeassert(*ty_args,**ty_kargs):
    def decorator(func):
        # 获取函数func的签名
        sig = signature(func)
        # 为函数的签名绑定部分参数类型
        btypes = sig.bind_partial(*ty_args,**ty_kargs).arguments
        def wrapper(*args,**kargs):
            for name,obj in sig.bind(*args,**kargs).arguments.items():
                if name in btypes:
                    # 校验函数中的参数类型是否符合规范
                    if not isinstance(obj,btypes[name]):
                        raise TypeError("类型异常")
            return func(*args,**kargs)
        return wrapper
    return decorator

@typeassert(int,str,list)
def g(a,b,c):
    print (a,b,c)

刚刚结束西安城墙13.54公里的历练,在腰酸背痛中温习了学习过的python知识,进来机器学习和深度学习席卷科研,看来得抓紧时间深入学习了,不然真的赶不上队伍了,加油吧!不知道为什么,忽然想起一句话,向死而生,尴尬了,珍惜!

上一篇 下一篇

猜你喜欢

热点阅读