Python常用知识点一二

写在前面

Python是一门解释型的、动态型的OOP语言,结识Python的这几年来,其语法的简洁、结构的条理性深刻的吸引了我。下面是我总结出来的一些Python常用知识点。

列表碾平式

需求: 将[[1,2],[3,4]] 转换为[1,2,3,4],具体实现有以下几种方法

test_list = [[1,2],[3,4]]

1. from itertools import chain
   list(chain.from_iterable(test_list))
   结果:[1, 2, 3, 4]

2. from itertools import chain
   list(chain(*test_list))
   结果:[1, 2, 3, 4]

3. sum(test_list, [])
   结果:[1, 2, 3, 4]

4. [x for y in test_list for x in y]
   结果:[1, 2, 3, 4]

5. 万能方法(递归)
   func = lambda x: [y for t in x for y in func(t)] if type(x) is list else [x]
   func(test_list)
   结果:[1, 2, 3, 4]复制代码

PS: 项目中,难免会有类似的需求,对于结构嵌套一致的情况,上述的1,2,3,4方法都可以很好的解决(不建议用for循环嵌套的方式,那是最low的方法,没有之一);对于结构嵌套不一致的情况,第5种方法就派上了用场,其采用了递归的思想,堪称万能的方法,屡试不爽。项目中,大家可以根据实际应用场景来挑选最适合自己的方法。肚中有粮,心中不慌;大家可以把上述方法都记下来,以做到有的放矢。

三目操作符

对于Python的三元表达式,想必大家对if else都不会感到陌生,但是对and or操作想必是另一种感觉了,不过大家对其他语言的? :应该不会陌生,没错,这次的主角and or就和? :有着异曲同工之妙。

代码参考:

1 == 1 and 2 or 3   返回2
1 == 2 and 2 or 3   返回3复制代码

PS:习惯于if else的同学偶尔用下and or是不是会给人耳目一新的感觉。

and or 分开来用

  • [x] and 用法如下:
1 and 2 and 3   返回3
1 and 2 and ''   返回''
'' and 2 and 0  返回''
PS:如果都为真则返回最后一个值,如果其中某些值为假,则返回第一个为假的值复制代码
  • [x] or 用法如下
1 or '' or 0    返回1
'' or 0 or []    返回[]
PS:如果都为假返回最后一个值,如果其中某些值为真,则返回第一个为真的值复制代码

使用场景:在项目中我们经常会有这样的需求,在将一个字典更新之后还想要返回更新后的字典,这是我们就可以这样写:dic = dic1.update(dic2) or dic1

列表推导式

需求:将[1,2,3]中的每一项都加1

good: [x+1 for x in [1,2,3]]
bad:  def add_list(goal_list):
          tmp_list = []
          for x in goal_list:
              tmp_list.append(x+1)复制代码

PS: 列表推导式底层是用C实现的,其执行速度要比for循环快好多

vars() 用法

代码参考:

```
def func(a, b, c):
    print vars()
执行func(1, 2, 3)
输出:{"a":1,"b":2,"c":3}
PS: vars()的值为字典,其键值对来源于当前作用域的所有变量。
```复制代码

使用场景:在调用他人接口或方法时,需要将传入的参数打印以记录日志,此刻vars()便派上用场了。

偏函数之partial

代码示例:

import functools
def add(a, b):
    return a + b
add(4, 2)
    6
plus3 = functools.partial(add, 3)
plus5 = functools.partial(add, 5)
plus3(4)
    7
plus3(7)
    10
plus5(10)
    15复制代码

实际使用心得:

之前做对象存储的项目中,我需要同时去调用三个一样的接口(大部分参数一样)下面是我的部分代码,供大家参考

my_thread = functools.partial(myThread, dic, zone_id, start, end, customer_id)
my_thread1 = my_thread("day", "gets", "2")
my_thread1 = my_thread("day", "original_traffic", "3")复制代码

使用场景:
当我们需要同时去调用一个函数,并且发现大部分参数一致的时候,便可以采取上述方法,一来代码简洁,二来可读性高。

Python搭建简易服务

  • Python搭建简易邮件服务器:python -m smtpd -n -c DebuggingServer localhost:1025
  • Python搭建简易web服务器:

    • Python2: python -m SimpleHTTPServer port
    • Python3: python -m http.server port
  • Python搭建简易ftp服务

      pip install pyftpdlib
      python -m pyftpdlib -p 21
      ftp://localhost:21复制代码

遍历字典

在项目中遍历字典是很常见的需求,下面介绍下常用的方法并做下比较:

dic = {'name': 'peter', 'age': 27}
1. for key, value in dic.items():
       print key, value
2. for key, value in dic.iteritems():
       print key, value复制代码

PS:
iteritemsitems的区别在于iteritems采用了生成器的原理,只有在需要的时候才会把值生成,其之间的区别类似于rangexrangereadlinexreadline

内存管理

Python的内存管理主要分为引用计数和垃圾回收机制两大部分,且看下面代码:

  • [ ] 内存分配:

      a = 1
      b = 1
      a is b      True
      ---------------------
      a = 1000
      b = 1000
      a is b      False复制代码

    PS: 在Python中,整数和短小的字符,Python都会缓存这些对象,以便重复使用。当我们创建多个等于1的引用时,实际上是让这些引用指向了同一个对象。

  • [ ] 引用计数:

    在Python中,所谓引用计数(reference count)是指所有指向该对象的引用的总数;

    我们可以使用sys包中的getrefcount(),来查看某个对象的引用计数。需要注意的是,当使用该函数查看某个对象的引用计数时,实际上是临时创建了该对象的一个新的引用,所有使用getrefcount()所得到的结果,会比期望的值多1。

      from sys import getrefcount
      aa = 'test refcount'
      print(getrefcount(a))
      bb = aa
      print(getrefcount(a))复制代码

    PS: 由于上述原因,两个getrefcount()将返回2和3,并不是期望的1和2.

  • [ ] 引用减少

    引用减少大致分为两类:

    • 指向该对象的引用指向了其他对象

         from sys import getrefcount
      
         aa = 'test refcount'
         bb = aa
         print(getrefcount(aa))      3
      
         bb = 1
         print(getrefcount(aa))      2复制代码
    • 使用del关键字显示的删除某个引用

         from sys import getrefcount
      
         aa = 'test refcount'
         bb = aa
         print(getrefcount(aa))      3
      
         del bb
         print(getrefcount(aa))      2复制代码
  • [ ] 垃圾回收

    不断的创建对象,如果不及时销毁的话,那Python的体积会越来越大,再大的内存也会有耗完的时候;不用像C语言那样,需要手动的去管理内存、Python已经帮我们做好了(Python的垃圾回收机制),你只需要去关心你的业务逻辑即可,其他的都交给Python来处理。

    从原理上讲,当Python中某个对象的引用计数降为0时,该对象就应该被回收。但是频繁的启动垃圾回收机制毕竟是个很耗时的问题;因此Python只有在特定条件下(当Python中被分配对象和取消分配对象的次数之间的差值达到某个阈值时),Python会自动启动垃圾回收机制。

    我们可以通过gc模块的get_threshold()方法,查看该阈值:

      import gc
      print(gc.get_threshold())复制代码

    该方法会返回(700, 10, 10),后面的俩10是与分代回收相关的,稍后讲解。700便是垃圾回收机制启动的阈值。可以通过gc模块中的set_threshold()方法重新设定该值。

    当然了,我们也可以手动启动垃圾回收机制,使用gc.collect()即可。

  • [ ] 分代回收

    Python同时采用了分代回收的机制,设想一下:存活越久的对象、越不可能是垃圾对象。程序在运行时,往往会产生大量的临时对象,程序结束之后,这些临时对象的生命周期也就随之告一段落。但有一些对象会被长期占用,垃圾回收机制在启动的时候会减少扫描到他们的频率。

    Python将所有对象分为0,1,2三代。所有新创建的对象都是0代,当垃圾回收机制在启动多次0代机制并扫描到他们的时候,这些对象如果依然存活在内存的话,他们就会被归入下一代对象,以此类推。

    刚才上面所提到的(700, 10, 10)三个参数后面的俩10所代表的意思是:每10次0代垃圾回收,会配合1次1代的垃圾回收;而每10次1代的垃圾回收会配合1次的2代垃圾回收。

    当然我们同样可以使用set_threshold()来调整此策略的比例,比如对1代对象进行更频繁的扫描。

      import gc
      gc.set_threshold(700, 5, 10)复制代码

新式类、经典类

  • [ ] 新式类: 显示的继承了object的类

      class A(object):
          attr = 1
    
      class B(A):
          pass
    
      class C(A):
          attr = 3
    
      class D(B, C):
          pass
    
      if __name__ == '__main__':
          d = D()
          print 'attr = ', d.attr     # attr = 3复制代码
  • [ ] 经典类:没有继承自object的类

      class A():
          attr = 1
    
      class B(A):
          pass
    
      class C(A):
          attr = 3
    
      class D(B, C):
          pass
    
      if __name__ == '__main__':
          d = D()
          print 'attr = ', d.attr     # attr = 1复制代码

    PS: 通过以上代码的输出结果可以看出,新式类会广度搜索,也就是一层层的向上搜索;经典类是深度优先,即遇到一个超类点就向上搜索。

装饰器

Python的装饰器被称为Python的语法糖,哪里需要粘哪里。

代码示例:

@makeh1
@makeeitalic
def say():
    return 'Peter'

我们希望输出结果为:<h1><i>Peter</i></h1>复制代码

去看看官方文档,答案就看下面:

def makeh1(func):
    def wrp():
        return "<h1>" + func() + "</h1>"
    return wrp

def makeeitalic(func):
    def wrp():
        return "<i>" + func() + "</i>"
    return wrp

@makeh1
@makeeitalic
def say():
    return 'Hello Peter'

print say()
输出:<h1><i>Hello Peter</i></h1>复制代码

实际应用场景:

使用过django的小伙伴想必都用过login_required装饰器,但是如果用户没登录的话login_required会重定向到登录页面;在做web开发的过程中,我们会经常用
ajax异步提交数据到后台,这时如果再继续使用原有的login_required装饰器肯定是不行了(该装饰器不会重定向到登录页面,ajax也没有任何返回结果),下面我们改变下原有代码:

from django.shortcuts import HttpResponse
import json

def is_authenticat(func):
    def wrp(req, **kwargs):
        if req.user.is_authenticated():
            return func(req, **kwargs)
        else:
            json_str = {'status': 0, 'msg': u'请登录'}
            return HttpResponse(json.dumps(json_str), content_type='application/json')
    return wrp复制代码

上述代码便很好的解决了问题,也算是对Python装饰器的一个很好的使用场景。

写在结语

Python的奥妙远不止于此

Python的深度还需要继续探索

以上就是平时工作中所总结出来的常用的知识点

希望对大家以后的工作会有所帮助

    原文作者:python入门
    原文地址: https://juejin.im/post/59bccd996fb9a00a67613280
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞