zoukankan      html  css  js  c++  java
  • Python基础教程【读书笔记】

      希望通过博客园持续的更新,分享和记录Python基础知识到高级应用的点点滴滴!

    第一波:第6章  抽象

    [总览] 介绍函数、参数parameter、作用于scope概念,以及递归概念。

    [6.1] 函数 - 懒惰即美德!

      将程序的具体细节抽象为函数。

    [6.2] 抽象和结构

      抽象可以节省代码工作量,关键易使程序让人读懂。程序应该是非常抽象额,就像“下载网页、计算词频、打印单词频率”描述一样易懂。

    page = download_page()

    freqs = compute_frequencies(page)

    for word,freq in freqs:

      print word,freq

    [6.3] 创建函数

      函数可调用,并返回一个值。内建callable函数可判断函数是否可调用。

      函数callable在Python3.0中需要使用表达式hasattr(func.__call__)代替。

      使用def定义函数,return用来从函数中返回值。

    def fibs(num):

      result = [0,1]

      for i in range(num-2):

        result.append(result[-2] + result[-1])

      return result

    [6.3.1] 记录函数

      给函数写文档,除加入注释(以#开头),还可直接在函数def语句内写上字符串。在函数的开头写下的字符串,它就会作为函数的一部分进行存储,称为文档字符串。

      文档字符串可以function.__doc__方式访问。__doc__使函数属性,双下划线表示它是个特殊属性。

      或者使用内建help函数,如help(function_name),可以得到关于函数,包括文档字符串的信息。

    [6.3.2] 并非真正函数的函数

      Python的有些函数并不返回任何东西,没有return语句或有return但后面没有跟任何值得函数,将不返回值。此时return语句只起到结束函数作用。

      更准确的将,所有的函数的确都返回了东西:当不需要函数返回值的时候,函数就返回None。

    [6.4] 参数魔法

    [6.4.1] 值从哪里来

      卸载def语句中函数名后面的变量通常叫形式参数,而调用函数的时候提供的值使实际参数,或者称为参数。

    [6.4.2] 我能改变参数吗

      在函数内为参数赋予新值不会改变外部任何变量的值。

    def try_to_change(n):

      n = 'Mr. New'

    name = 'Mrs. Old'

    try_to_change(name)

    name

    'Mrs. Old'

      参数n获得了新值,但是没有影响到name变量。n实际上是个完全不同的变量。当变量n改变的时候,变量name不变。即当在函数内部把参数重绑定(赋值)的时候,函数外部的变量不会受到影响。

      注意:参数存储在局部作用于local scope内。

      字符串(以及数字和元组)是不可变的,考虑一下如果将可变的数据结构如列表用作参数的情况:

    def change(n):

      n[0] = 'Mr. Change_New'

    names = ['Mrs.Entity','Mrs. Thing']

    change(names)

    names

    ['Mr. Change_New','Mrs. Thing']

      当两个变量同时引用一个列表的时候,它们的确是同时引用一个列表。如果避免出现这种情况,可以复制一个列表的副本,在序列中做切片,返回的切片总是一个副本。如果复制了整个列表的切片,即得到列表的一个副本。

    names = ['Mrs.Entity','Mrs. Thing']

    n = names[:] #现在n和name是两个不同的列表。可通过is或==理解。原列表是安全的。

      1.为什么我想要修改参数

      使用函数改变数据结构是将程序抽象画的好方法。抽象的要点就是通过函数实现隐藏繁琐的细节。

    def init(data):

      data['first'] = {}

      data['middle'] = {}

    storage

    {'first':{},'middle':{},'last':{}}

    [6.4.3] 关键字参数和默认值

       位置参数和关键字参数。慢慢习惯使用这个功能以后,就会发现程序规模越大,关键字参数的作用也越大。关键字参数主要作用在于可以明确每个参数的作用。关键词参数最厉害的地方在于可以在函数中给参数提供默认值。

      位置和关键字参数可以联合使用。把位置参数放置在前面就可以。

    [6.4.4] 收集参数

      提供任意数量的参数是很有必要且重要的。

    def print_params(*params):print params

    ('Testing',)

      结果作为元祖打印出来。参数前的星号*将所有值放置在同一个元祖中。可以说是将这些值收集起来没然后使用。还可以联合普通参数使用。*星号的意思就是“收集其余的位置参数”。注意,此处强调位置参数

    def print_params(**params):print params

    print_params(x=1,y=2,z=3)

    {'x':1,'y':2,'z':3}  # f返回的是字典而不是元组

    def print_params(x,y,z=3,*pospar,**keypar):

      print x,y,z

      print pospar

      print keypar

    print_params(1,2,3,5,6,7,foo=1,bar=2)

    1 2 3

    (5,6,7)

    {'foo':1,'bar':2}

    [6.4.5] 反转过程

    [6.4.6] 练习使用参数

      位置参数,关键字参数,*,**

    [6.5] 作用域

      到底什么是变量?你可以把他们看作是值的名字。在执行x=1赋值语句时,名称x引用到值1。这就像用字典一样,键引用值,当然变量和所对应的值用的是个“不可见”的字典。实际上这个么说已经很接近真实情况啦。内建的vars函数可以返回这个字典:

    x=1

    scope = vars()

    scope['x]

      这类“不可见字典”叫做命名空间或者作用域。到底有多少个命名空间?除了全局作用域外,每个函数调用都会创建一个新的作用域。

    def foo():x=42

    x = 1

    foo()

    x

    1

      这里的foo函数改变了变量x,但是在最后的时候,x并没有变。这是因为当调用foo的时候,新的命名空间就被创建了,它作用于foo内的代码块。赋值语句x=42只在内部作用域(局部命名空间)起作用,所以它并不影响外部(全局)作用域中的x。

      函数内的变量被称为局部变量local variable,这是与全局变量相反的概念。参数的工作原理类似于局部变量,所以用全局变量的名字作为参数名并没有问题。

      【待深入问题:局部变量与全局变量屏蔽问题,重绑定全局变量问题,嵌套作用域问题】

    [6.6] 递归

      函数可以调用自身。递归简单来说就是引用自身。

      递归函数包含以下几部分:

        当函数直接返回值时有基本实例(最小可能性问题);

        递归实例,包括一个或者多个问题最小部分的递归调用。

      这里的关键就是讲问题分解为小部分,递归不能永远继续下去,因为它总是以最小可能性问题结束,而这些问题又存在基本实例中的。每次函数被调用时没针对这个调用的新命名空间会被创建,意味着当函数调用“自身”时,实际上运行的是两个不同的函数(或者说是同一个函数具有两个不同的命名空间)。

    [6.6.1] 两个经典:阶乘和幂

      n的阶乘定义为nx(n-1)x(n-2)x...x1

        1的阶乘是1;

        大于1的数n的阶乘是n乘n-1的阶乘

    def factorial(n):

      if n == 1:

        return 1

      else:

        return n * factorial(n-1)

      计算幂,就像内建的pow函数或者**运算符一样。

        对于任意数字x来说,power(x,0)是1;

        对于任意大于0的数来说,power(x,n)是x乘以(x,n-1)的结果。

    def power(x,n):

      if n == 0:

        return 1

      else:

        return x * power(x,n-1)

    [6.6.2] 另一个经典:二元查找

      二元查找binary search。

      首先定义二元查找算法的递归:

        如果上下限相同,那么就是数字所在位置,返回;

        否则找到两者的重点(上下限的平均值),查找数字是在左侧还是在右侧,继续查找数字所在的那半部分。

    def search(sequence,number,lower,upper):

      if lower == upper:

        assert number == sequence[upper]

        return upper

      else:

        middle = (lower+upper)//2

        if number > sequence[middle]:

          return search(sequence,number,middle+1,upper)

        else:

          return search(sequence,number,lower,middle)

      提示:标准库中的bisect可以非常有效地实现二元查找。

    [6.6.3] 有用的函数

      map、filter、reduce函数

      map函数可将序列中的所有元素全部传递给一个函数:

    map(str,range(10))  # equivalent to [str(i) for i in range(10)]

      filter函数可以基于一个返回布尔值的函数对元素进行过滤:

    filter(func,seq)

      lambda表达式,可以创建短小的函数。

    filter(lambda x: x.isalnum(),seq)

      reduce函数会将序列的前两个元素与给定的函数联合使用,并且将他们的返回值和第三个元素继续联合使用,直到整个序列都处理完毕,并且得到一个最终结果。

    numbers = [77,102,33,45,23,62,89,201]

    reduce(lambda x,y:x+y,numbers)

    [6.7] 小结

      抽象:抽象是隐藏多余细节的艺术。定义处理细节的函数可以让程序更抽象。

      函数定义:函数使用def语句定义。由语句组成的块,可以从”外部“获取参数,可以返回一个或者多个结果。

      参数:即函数调用时设定的变量。python中有两类参数:位置参数和关键字参数。

      作用域:变量存储在作用(也叫命名空间)中。两类作用域:全局作用域和局部作用域,作用域可嵌套。

      递归:调用函数自身。

      函数式编程:Python有一些函数型编程的机制。包括lambda表达式以及map、filter、reduce函数。

  • 相关阅读:
    AB(ApacheBench)工具 -- 压力测试
    请求错误 --405
    第三方支付 -----支付宝支付流程
    前后端分离 ---购物车
    canvas实现碰壁反弹(单个小方块)
    h5 的canvas绘制基本图形
    for in 循环
    js创建对象的三种方式和js工厂模式创建对象
    类的继承
    jq操作class类
  • 原文地址:https://www.cnblogs.com/pythonMLer/p/5605412.html
Copyright © 2011-2022 走看看