对于Python这么语言,可以当作一门兴趣或爱好来学习,但是若是想找到份好的工作还是谨慎为主,这也是为什么不建议你搞Python的原因。

如果说,有些读者的学历非常牛逼,然后学习能力也非常强,那么选择人工智能、机器学习、数据分析,我觉得前途是光明的,既能赚钱,待遇又好,还不可替代,不学 Python 绝对亏。

如果说,有些读者学历一般,做程序员仅仅是为了糊口饭吃,那么我觉得可以把 Python 作为第二语言来学,不要当做主语言。搞点范围许可内的爬虫,自动化测试,我就觉得挺好的。况且 Python 这门语言本身是非常优秀的,不然怎么搞人工智能,海量数据分析,对吧?

文章目录

    • 1、输入输出
    • 2、缩进和注释
    • 3、数据类型和变量
      • 整数
      • 浮点数
    • 4、字符串
    • 5、布尔值
    • 6、空值
    • 7、变量
    • 8、常量
    • 9、除法计算结果是浮点数
    • 10、Python中的is和==
    • 11、编码
      • \u则代表unicode编码,是一个字符
    • 12、Python3注释
    • 13、运算符
      • 逻辑运算符
      • 位运算符
      • 赋值运算符
      • 算术运算符
      • 比较运算符
      • 身份运算符
      • 成员运算符
    • 14、数字类型转换
    • 15、list-列表
  • 列表脚本操作符
  • 列表截取与拼接
  • 列表函数&方法
    • 16、元组-tuple
    • 17、if else
    • 再议 input
    • 18、循环
    • 19、break、continue和pass
    • 20、Dictionary--字典
    • 21、函数
    • python 传不可变对象实例
    • 传可变对象实例
    • 命名关键字参数
    • 关键字参数
    • 命名关键字参数
    • 默认参数
      • 可变参数
      • **`*nums`表示把`nums`这个list的所有元素作为可变参数传进去。这种写法相当有用,而且很常见。**
    • 匿名函数
    • 语法
    • 实例(Python 2.0+)
    • 返回多个值
    • 全局变量和局部变量
    • 实例(Python 2.0+)
      • 函数别名
      • Import 与 from import
      • 包的概念 packa包中
    • 22、切片
    • 23、迭代
    • 24、列表生成式
    • 25、生成器
    • 26、迭代器
    • 27、函数式编程
      • 1、高阶函数
        • 变量可以指向函数
        • 函数名也是变量
      • 2、map/reduce
      • sorted
      • 3、返回函数
      • 闭包
      • 4、lambda
      • 5、装饰器
      • 6、偏函数
    • 28、模块
      • 私有变量和函数
      • 第三方模块
    • 模块搜索路径
    • 29、类和实例
    • 30、访问限制
    • 31、继承和多态
    • 32、获取对象信息
      • 使用isinstance()
      • dir()
    • 33、__slots__限制实例绑定任何属性和方法
    • 34、@property @xxx.setter
    • 35、多继承
    • 36、定制类
    • __str__

1、输入输出

  • 输出

    • print()在括号中加上字符串,就可以向屏幕上输出指定的文字

    • print()函数也可以接受多个字符串,用逗号“,”隔开,就可以连成一串输出;

      • print('The quick brown fox', 'jumps over', 'the lazy dog')
        The quick brown fox jumps over the lazy dog
        

        print()会依次打印每个字符串,遇到逗号“,”会输出一个空格

    • print()也可以打印整数,或者计算结果

      • print('100 + 200 =', 100 + 200)
        
  • 输入

    • Python提供了一个input(),可以让用户输入字符串,并存放到一个变量里

      • name = input()
        

2、缩进和注释

  • #开头的语句是注释
  • 每一行都是一个语句,当语句以冒号:结尾时,缩进的语句视为代码块;
  • 缩进有利有弊。好处是强迫你写出格式化的代码,但没有规定缩进是几个空格还是Tab。按照约定俗成的惯例,应该始终坚持使用4个空格的缩进。缩进的另一个好处是强迫你写出缩进较少的代码,你会倾向于把一段很长的代码拆分成若干函数,从而得到缩进较少的代码。缩进的坏处就是“复制-粘贴”功能失效了,这是最坑爹的地方。当你重构代码时,粘贴过去的代码必须重新检查缩进是否正确。此外,IDE很难像格式化Java代码那样格式化Python代码。
  • Python程序是大小写敏感的,如果写错了大小写,程序会报错

3、数据类型和变量

  • 整数

    • Python可以处理任意大小的整数,当然包括负整数,在程序中的表示方法和数学上的写法一模一样

    • dec = int(input("输入数字:"))
      print("十进制数为:", dec)
      print("转换为二进制为:", bin(dec))
      print("转换为八进制为:", oct(dec))  # 0o开头
      print("转换为十六进制为", hex(dec))  # 0x开
      
  • 浮点数

    • https://www.cnblogs.com/qinchao0317/p/10699717.html

    • 保留小数点位数

      • 使用字符串格式化

        • x = 1234.56789
          print(format(x, '0.2f'))
          1234.57
          
          占位符 替换内容
          %d 整数
          %f 浮点数
          %s 字符串
          %x 十六进制整数
      • 使用round内置函数

        • dec = float(input("输入的数字"))
          print("dec*dec =",round(dec*dec,2));
          
    • 数值类型转换

      • int(x [,base ])         将x转换为一个整数
        long(x [,base ])        将x转换为一个长整数
        float(x )               将x转换到一个浮点数
        complex(real [,imag ])  创建一个复数
        str(x )                 将对象 x 转换为字符串
        repr(x )                将对象 x 转换为表达式字符串
        eval(str )              用来计算在字符串中的有效Python表达式,并返回一个对象
        tuple(s )               将序列 s 转换为一个元组
        list(s )                将序列 s 转换为一个列表
        chr(x )                 将一个整数转换为一个字符
        unichr(x )              将一个整数转换为Unicode字符
        ord(x )                 将一个字符转换为它的整数值
        hex(x )                 将一个整数转换为一个十六进制字符串
        oct(x )                 将一个整数转换为一个八进制字符串
        

4、字符串

  • 字符串是以单引号'或双引号"括起来的任意文本;如果'本身也是一个字符,那就可以用""括起来,比如"I'm OK"包含的字符是I'm,空格,OK这6个字符。如果字符串内部既包含'又包含"怎么办?可以用转义字符\来标识;

    • print("i'm okss")
      print('i\'m \" ok')
      

    转义字符\可以转义很多字符,比如\n表示换行,\t表示制表符,字符\本身也要转义,所以\\表示的字符就是\

    print('i\nam\nok')

    Python还允许用r''表示''内部的字符串默认不转义

    print(r'xxjis\nosk\t')

    如果字符串内部有很多换行,用\n写在一行里不好阅读,为了简化,Python允许用'''...'''的格式表示多行内容

    print('''zzxsx
    zxsaxa
    sasads
    s''')

5、布尔值

  • 个布尔值只有TrueFalse两种值,要么是True,要么是False

  • and、 or、 not

  • print(True and True)
    print(not 1>2)

6、空值

  • None表示空值,它是一个特殊 Python 对象, None的类型是NoneType

    • print(type(None))  #<class 'NoneType'>

7、变量

  • 变量在程序中就是用一个变量名表示了,变量名必须是大小写英文、数字和_的组合,且不能用数字开头

  • 变量本身类型不固定的语言称之为动态语言,与之对应的是静态语言。静态语言在定义变量时必须指定变量类型,如果赋值的时候类型不匹配,就会报错。例如Java是静态语言

    • int a = 123; // a是整数类型变量
      a = "ABC"; // 错误:不能把字符串赋给整型变量

8、常量

  • 所谓常量就是不能变的变量,比如常用的数学常数π就是一个常量。在Python中,通常用全部大写的变量名表示常量:

    • PI = 3.14159265359

      但事实上PI仍然是一个变量,Python根本没有任何机制保证PI不会被改变,所以,用全部大写的变量名表示常量只是一个习惯上的用法,如果你一定要改变变量PI的值,也没人能拦住你

  • 赋值

    • a,b,c=1,2,3
      a,b=b,a+b
      print(a,b)

9、除法计算结果是浮点数

  • print(10/3)
    print(10//3)

    /除法计算结果是浮点数,即使是两个整数恰好整除,结果也是浮点数

    还有一种除法是//,称为地板除,两个整数的除法仍然是整数

    %为取余计算

10、Python中的is和==

  • ==是python标准操作符中的比较操作符,用来比较判断两个对象的value(值)是否相等

  • is是比较引用地址是否相等

  • Python中,万物皆对象!

    每个对象包含3个属性,id,type,value

    id就是对象地址,可以通过内置函数id()查看对象引用的地址。

    type就是对象类型,可以通过内置函数type()查看对象的类型。

    value就是对象的值。

11、编码

  • Python 3版本中,字符串是以Unicode编码的

  • 对于单个字符的编码,Python提供了ord()函数获取字符的整数表示,chr()函数把编码转换为对应的字符:

    • print(ord('a'))
      print(chr(97))
    • \u则代表unicode编码,是一个字符

      • print('\u4e2d\u6587')  #表示中文的意思
  • Python对bytes类型的数据用带b前缀的单引号或双引号表示

    • print('ABC'.encode('ascii'))  //b'ABC'

      区分'ABC'b'ABC',前者是str,后者虽然内容显示得和前者一样,但bytes的每个字符都只占用一个字节。

  • >>> b'ABC'.decode('ascii')
    'ABC'
    >>> '中文'.encode('utf-8')
    b'\xe4\xb8\xad\xe6\x96\x87'
    >>> b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')
    '中文'

    如果我们从网络或磁盘上读取了字节流,那么读到的数据就是bytes。要把bytes变为str,就需要用decode()方法:

    >>> b'ABC'.decode('ascii')
    'ABC'
    >>> b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')
    '中文'

    如果bytes中只有一小部分无效的字节,可以传入errors='ignore'忽略错误的字节:

    >>> b'\xe4\xb8\xad\xff'.decode('utf-8', errors='ignore')
    '中'

    要计算str包含多少个字符,可以用len()函数:

    >>> len('ABC')
    3
    >>> len('中文')
    2
  • 由于Python源代码也是一个文本文件,所以,当你的源代码中包含中文的时候,在保存源代码时,就需要务必指定保存为UTF-8编码。当Python解释器读取源代码时,为了让它按UTF-8编码读取,我们通常在文件开头写上这两行:

    • #!/usr/bin/env python3
      # -*- coding: utf-8 -*-
      或者
      #!/usr/bin/env python3
      #coding=utf-8

12、Python3注释

  • # 这是一个注释
  • 多行注释用三个单引号 ‘’’ 或者三个双引号 “”" 将注释括起来

13、运算符

  • 逻辑运算符

    • 运算符 逻辑表达式 描述 实例
      and x and y 布尔"与" - 如果 x 为 False,x and y 返回 False,否则它返回 y 的计算值。 (a and b) 返回 20。
      or x or y 布尔"或" - 如果 x 是 True,它返回 x 的值,否则它返回 y 的计算值。 (a or b) 返回 10。
      not not x 布尔"非" - 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。 not(a and b) 返回 False
  • 位运算符

    • & 按位与运算符:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0 (a & b) 输出结果 12 ,二进制解释: 0000 1100
      | 按位或运算符:只要对应的二个二进位有一个为1时,结果位就为1。 (a | b) 输出结果 61 ,二进制解释: 0011 1101
      ^ 按位异或运算符:当两对应的二进位相异时,结果为1 (a ^ b) 输出结果 49 ,二进制解释: 0011 0001
      ~ 按位取反运算符:对数据的每个二进制位取反,即把1变为0,把0变为1。~x 类似于 -x-1 (~a ) 输出结果 -61 ,二进制解释: 1100 0011, 在一个有符号二进制数的补码形式。
      << 左移动运算符:运算数的各二进位全部左移若干位,由"<<"右边的数指定移动的位数,高位丢弃,低位补0。 a << 2 输出结果 240 ,二进制解释: 1111 0000
      >> 右移动运算符:把">>“左边的运算数的各二进位全部右移若干位,”>>"右边的数指定移动的位数 a >> 2 输出结果 15 ,二进制解释: 0000 1111
  • 赋值运算符

    • 运算符 描述 实例
      = 简单的赋值运算符 c = a + b 将 a + b 的运算结果赋值为 c
      += 加法赋值运算符 c += a 等效于 c = c + a
      -= 减法赋值运算符 c -= a 等效于 c = c - a
      *= 乘法赋值运算符 c *= a 等效于 c = c * a
      /= 除法赋值运算符 c /= a 等效于 c = c / a
      %= 取模赋值运算符 c %= a 等效于 c = c % a
      **= 幂赋值运算符 c **= a 等效于 c = c ** a
      //= 取整除赋值运算符 c //= a 等效于 c = c // a
      := 海象运算符,可在表达式内部为变量赋值。Python3.8 版本新增运算符 在这个示例中,赋值表达式可以避免调用 len() 两次:if (n := len(a)) > 10: print(f"List is too long ({n} elements, expected <= 10)")
  • 算术运算符

    • 运算符 描述 实例
      + 加 - 两个对象相加 a + b 输出结果 31
      - 减 - 得到负数或是一个数减去另一个数 a - b 输出结果 -11
      * 乘 - 两个数相乘或是返回一个被重复若干次的字符串 a * b 输出结果 210
      / 除 - x 除以 y b / a 输出结果 2.1
      % 取模 - 返回除法的余数 b % a 输出结果 1
      ** 幂 - 返回x的y次幂 a**b 为10的21次方
      // 取整除 - 向下取接近商的整数 >>> 9//2 4 >>> -9//2 -5
  • 比较运算符

    • 运算符 描述 实例
      == 等于 - 比较对象是否相等 (a == b) 返回 False。
      != 不等于 - 比较两个对象是否不相等 (a != b) 返回 True。
      > 大于 - 返回x是否大于y (a > b) 返回 False。
      < 小于 - 返回x是否小于y。所有比较运算符返回1表示真,返回0表示假。这分别与特殊的变量True和False等价。注意,这些变量名的大写。 (a < b) 返回 True。
      >= 大于等于 - 返回x是否大于等于y。 (a >= b) 返回 False。
      <= 小于等于 - 返回x是否小于等于y。 (a <= b) 返回 True。
  • 身份运算符

    • 运算符 描述 实例
      is is 是判断两个标识符是不是引用自一个对象 x is y, 类似 id(x) == id(y) , 如果引用的是同一个对象则返回 True,否则返回 False
      is not is not 是判断两个标识符是不是引用自不同对象 x is not y , 类似 id(a) != id(b)。如果引用的不是同一个对象则返回结果 True,否则返回 False。
  • 成员运算符

    • 运算符 描述 实例
      in 如果在指定的序列中找到值返回 True,否则返回 False。 x 在 y 序列中 , 如果 x 在 y 序列中返回 True。
      not in 如果在指定的序列中没有找到值返回 True,否则返回 False。 x 不在 y 序列中 , 如果 x 不在 y 序列中返回 True。

14、数字类型转换

  • int(x) 将x转换为一个整数。
  • float(x) 将x转换到一个浮点数。

15、list-列表

  • 序列是Python中最基本的数据结构。序列中的每个元素都分配一个数字 - 它的位置,或索引,第一个索引是0,第二个索引是1,依此类推。

    Python有6个序列的内置类型,但最常见的是列表和元组。

    序列都可以进行的操作包括索引,切片,加,乘,检查成员。

    此外,Python已经内置确定序列的长度以及确定最大和最小的元素的方法。

  • 列表的数据项不需要具有相同的类型

  • list是一种有序的集合,可以随时添加和删除其中的元素。

  • 访问列表 可正负

    • list1=['1','zz','333','444']
      print(list1[0])
      print(list1[-1])
  • list是一个可变的有序表,所以,可以往list中追加元素到末尾:

    • list1.append("zzdc")
      list1.append("zdc2")
      print(list1)

      也可以把元素插入到指定的位置,比如索引号为1的位置

    • list1.insert(1,222)
      print(list1)

      要删除list末尾的元素,用pop()或pop(i)方法 pop会把删去的元素返回

    • print(list1.pop())
      print(list1.pop(0))

      要把某个元素替换成别的元素,可以直接赋值给对应的索引位置:

    • list1[0]='mzd'
      print(list1)

      list元素也可以是另一个list

    • list1[0]=['1',2,3,4]
      print(list1)
      >>> p = ['asp', 'php']
      >>> s = ['python', 'java', p, 'scheme']
  • 列表脚本操作符

    • Python 表达式 结果 描述
      len([1, 2, 3]) 3 长度
      [1, 2, 3] + [4, 5, 6] [1, 2, 3, 4, 5, 6] 组合
      [‘Hi!’] * 4 [‘Hi!’, ‘Hi!’, ‘Hi!’, ‘Hi!’] 重复
      3 in [1, 2, 3] True 元素是否存在于列表中
      for x in [1, 2, 3]: print(x, end=" ") 1 2 3 迭代

      遍历

      • for var in list1:print(var)
  • 列表截取与拼接

    • 操作:

      Python 表达式 结果 描述
      L[2] ‘Taobao’ 读取第三个元素
      L[-2] ‘Runoob’ 从右侧开始读取倒数第二个元素: count from the right
      L[1:] [‘Runoob’, ‘Taobao’] 输出从第二个元素开始后的所有元素
    • 变量[头下标:尾下标]
      变量[头下标:尾下标:步长]
      list=['123','abc',0,True]
      x=list[1:]
      y=list[:3]
      z=list[2:3]
      print(x)
      print(y)
      printlist=['123','abc',0,True]
      x=list[-3:]
      y=list[:-2]
      z=list[-3:-1]
      print(x)
      print(y)
      print(z)list=['123','abc',0,True,"12345"]
      x=list[1:4:2]
      print(x)
  • 列表函数&方法

    Python包含以下函数:

    序号 函数
    1 len(list) 列表元素个数
    2 max(list) 返回列表元素最大值
    3 min(list) 返回列表元素最小值
    4 list(seq) 将元组转换为列表

    Python包含以下方法:

    序号 方法
    1 list.append(obj) 在列表末尾添加新的对象
    2 list.count(obj) 统计某个元素在列表中出现的次数
    3 list.extend(seq) 在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)
    4 list.index(obj) 从列表中找出某个值第一个匹配项的索引位置
    5 list.insert(index, obj) 将对象插入列表
    6 [list.pop(index=-1]) 移除列表中的一个元素(默认最后一个元素),并且返回该元素的值
    7 list.remove(obj) 移除列表中某个值的第一个匹配项
    8 list.reverse() 反向列表中元素
    9 list.sort( key=None, reverse=False) 对原列表进行排序
    10 list.clear() 清空列表
    11 list.copy() 复制列表

16、元组-tuple

  • tuple和list非常类似,但是tuple一旦初始化就不能修改

  • 不可变的tuple有什么意义?因为tuple不可变,所以代码更安全。如果可能,能用tuple代替list就尽量用tuple。

  • tuple的陷阱:当你定义一个tuple时,在定义的时候,tuple的元素就必须被确定下来

    • t = (1, 2)
      t = ()  #如果要定义一个空的tuple

      要定义一个只有1个元素的tuple,如果你这么定义

      >>> t = (1)
      >>> t
      1

      定义的不是tuple,是1这个数!这是因为括号()既可以表示tuple,又可以表示数学公式中的小括号,这就产生了歧义,因此,Python规定,这种情况下,按小括号进行计算,计算结果自然是1

      所以,只有1个元素的tuple定义时必须加一个逗号,,来消除歧义:

      >>> t = (1,)
      >>> t
      (1,)

      一个“可变的”tuple:

      >>> t = ('a', 'b', ['A', 'B'])
      >>> t[2][0] = 'X'
      >>> t[2][1] = 'Y'
      >>> t
      ('a', 'b', ['X', 'Y'])

      这个tuple定义的时候有3个元素,分别是'a''b'和一个list。不是说tuple一旦定义后就不可变了吗?怎么后来又变了?

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gT70crDv-1612773531303)(1.assets/0.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qusc6dYV-1612773531305)(1.assets/0-20200713003324698.png)]

表面上看,tuple的元素确实变了,但其实变的不是tuple的元素,而是list的元素。tuple一开始指向的list并没有改成别的list,所以,tuple所谓的“不变”是说,tuple的每个元素,指向永远不变。即指向'a',就不能改成指向'b',指向一个list,就不能改成指向其他对象,但指向的这个list本身是可变的!

要创建一个内容也不变的tuple怎么做?那就必须保证tuple的每一个元素本身也不能变

  • 以对元组进行连接组合

  • tup1 = (12, 34.56)
    tup2 = ('abc', 'xyz')# 以下修改元组元素操作是非法的。
    # tup1[0] = 100# 创建一个新的元组
    tup3 = tup1 + tup2

17、if else

  • if 判断条件:执行语句……
    else:执行语句……

    当判断条件为多个值时

    if 判断条件1:执行语句1……
    elif 判断条件2:执行语句2……
    elif 判断条件3:执行语句3……
    else:执行语句4……

    if判断条件还可以简写,比如写:

    if x:print('True')

    只要x是非零数值、非空字符串、非空list等,就判断为True,否则为False

    再议 input

    最后看一个有问题的条件判断。很多同学会用input()读取用户的输入,这样可以自己输入,程序运行得更有意思:

    birth = input('birth: ')
    if birth < 2000:print('00前')
    else:print('00后')

    输入1982,结果报错:

    Traceback (most recent call last):File "<stdin>", line 1, in <module>
    TypeError: unorderable types: str() > int()

    这是因为input()返回的数据类型是strstr不能直接和整数比较,必须先把str转换成整数。Python提供了int()函数来完成这件事情:

    s = input('birth: ')
    birth = int(s)
    if birth < 2000:print('00前')
    else:print('00后')

    再次运行,就可以得到正确地结果。但是,如果输入abc呢?又会得到一个错误信息:

    Traceback (most recent call last):File "<stdin>", line 1, in <module>
    ValueError: invalid literal for int() with base 10: 'abc'

    原来int()函数发现一个字符串并不是合法的数字时就会报错,程序就退出了。

18、循环

  • while 判断条件(condition):执行语句(statements)……

循环使用 else 语句

​ 在 python 中,while … else 在循环条件为 false 时执行 else 语句块:

  • count = 0
    while count < 5:print count, " is  less than 5"count = count + 1
    else:print count, " is not less than 5"

for 循环语句

  • for iterating_var in sequence:statements(s)

在 python 中,for … else 表示这样的意思,for 中的语句和普通的没有区别,else 中的语句会在循环正常执行完(即 for 不是通过 break 跳出而中断的)的情况下执行,while … else 也是一样。

Python 语言允许在一个循环体里面嵌入另一个循环。

for iterating_var in sequence:for iterating_var in sequence:statements(s)statements(s)while expression:while expression:statement(s)statement(s)

19、break、continue和pass

  • Python continue 语句跳出本次循环,而break跳出整个循环。

  • Python pass 是空语句,是为了保持程序结构的完整性。

    pass 不做任何事情,一般用做占位语句。

    • 在 Python3.x 的时候 pass 可以写或不写。

      python2.x:

      def function():# 空函数在Python2.x版本中pass是必须的pass

      python3.x

      def function():# 在Python3.x的时候pass可以写或不写pass

20、Dictionary–字典

  • 字典是另一种可变容器模型,且可存储任意类型对象。

    字典的每个键值 key=>value 对用冒号 : 分割,每个键值对之间用逗号 , 分割,整个字典包括在花括号 {} 中 ,格式如下所示:

    d = {key1 : value1, key2 : value2 }

    如果key不存在,dict就会报错:

    >>> d['Thomas']
    Traceback (most recent call last):File "<stdin>", line 1, in <module>
    KeyError: 'Thomas'

    要避免key不存在的错误,有两种办法,一是通过in判断key是否存在:

    >>> 'Thomas' in d
    False

    二是通过dict提供的get()方法,如果key不存在,可以返回None,或者自己指定的value:

    >>> d.get('Thomas')
    >>> d.get('Thomas', -1)
    -1

    注意:返回None的时候Python的交互环境不显示结果。

    要删除一个key,用pop(key)方法,对应的value也会从dict中删除:

    >>> d.pop('Bob')
    75
    >>> d
    {'Michael': 95, 'Tracy': 85}

    请务必注意,dict内部存放的顺序和key放入的顺序是没有关系的。

    和list比较,dict有以下几个特点:

    1. 查找和插入的速度极快,不会随着key的增加而变慢;
    2. 需要占用大量的内存,内存浪费多。

    而list相反:

    1. 查找和插入的时间随着元素的增加而增加;
    2. 占用空间小,浪费内存很少。

    所以,dict是用空间来换取时间的一种方法。

    这是因为dict根据key来计算value的存储位置,如果每次计算相同的key得出的结果不同,那dict内部就完全混乱了。这个通过key计算位置的算法称为哈希算法(Hash)。

    要保证hash的正确性,作为key的对象就不能变。在Python中,字符串、整数等都是不可变的,因此,可以放心地作为key。而list是可变的,就不能作为key:

21、函数

  • 定义函数

    • 在Python中,定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回。

    • def my_abs(x):if x >= 0:return xelse:return -x

      如果你已经把my_abs()的函数定义保存为abstest.py文件了,那么,可以在该文件的当前目录下启动Python解释器,用from abstest import my_abs来导入my_abs()函数,注意abstest是文件名(不含.py扩展名):

  • 参数的可变与不可变

    • 在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。

      • **不可变类型:**变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a。
      • **可变类型:**变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。

      python 函数的参数传递:

      • **不可变类型:**类似 c++ 的值传递,如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
      • **可变类型:**类似 c++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响

      python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。

  • python 传不可变对象实例

    • #!/usr/bin/python
      # -*- coding: UTF-8 -*-def ChangeInt( a ):a = 10b = 2
      ChangeInt(b)
      print b # 结果是 2
  • 传可变对象实例

    • !/usr/bin/python
      # -*- coding: UTF-8 -*-# 可写函数说明
      def changeme( mylist ):"修改传入的列表"mylist.append([1,2,3,4])print "函数内取值: ", mylistreturn# 调用changeme函数
      mylist = [10,20,30]
      changeme( mylist )
      print "函数外取值: ", mylist
  • 命名关键字参数

    • 关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。

      使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值

      • #!/usr/bin/python
        # -*- coding: UTF-8 -*-#可写函数说明
        def printme( str ):"打印任何传入的字符串"print strreturn#调用printme函数
        printme( str = "My string")
  • 关键字参数

    **可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。**请看示例:

    def person(name, age, **kw):print('name:', name, 'age:', age, 'other:', kw)

    函数person除了必选参数nameage外,还接受关键字参数kw。在调用该函数时,可以只传入必选参数:

    >>> person('Michael', 30)
    name: Michael age: 30 other: {}

    也可以传入任意个数的关键字参数:

    >>> person('Bob', 35, city='Beijing')
    name: Bob age: 35 other: {'city': 'Beijing'}
    >>> person('Adam', 45, gender='M', job='Engineer')
    name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}

    关键字参数有什么用?它可以扩展函数的功能。比如,在person函数里,我们保证能接收到nameage这两个参数,但是,如果调用者愿意提供更多的参数,我们也能收到。试想你正在做一个用户注册的功能,除了用户名和年龄是必填项外,其他都是可选项,利用关键字参数来定义这个函数就能满足注册的需求。

    和可变参数类似,也可以先组装出一个dict,然后,把该dict转换为关键字参数传进去:

    >>> extra = {'city': 'Beijing', 'job': 'Engineer'}
    >>> person('Jack', 24, city=extra['city'], job=extra['job'])
    name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}

    当然,上面复杂的调用可以用简化的写法:

    >>> extra = {'city': 'Beijing', 'job': 'Engineer'}
    >>> person('Jack', 24, **extra)
    name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}

    **extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数,kw将获得一个dict,注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra

  • 命名关键字参数

    对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数。至于到底传入了哪些,就需要在函数内部通过kw检查。

    仍以person()函数为例,我们希望检查是否有cityjob参数:

    def person(name, age, **kw):if 'city' in kw:# 有city参数passif 'job' in kw:# 有job参数passprint('name:', name, 'age:', age, 'other:', kw)

    但是调用者仍可以传入不受限制的关键字参数:

    >>> person('Jack', 24, city='Beijing', addr='Chaoyang', zipcode=123456)

    **如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收cityjob作为关键字参数。**这种方式定义的函数如下:

    def person(name, age, *, city, job):print(name, age, city, job)

    和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符**后面的参数被视为命名关键字参数。

    调用方式如下:

    >>> person('Jack', 24, city='Beijing', job='Engineer')
    Jack 24 Beijing Engineer

    如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:

    def person(name, age, *args, city, job):print(name, age, args, city, job)

    命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错:

    >>> person('Jack', 24, 'Beijing', 'Engineer')
    Traceback (most recent call last):File "<stdin>", line 1, in <module>
    TypeError: person() takes 2 positional arguments but 4 were given

    由于调用时缺少参数名cityjob,Python解释器把这4个参数均视为位置参数,但person()函数仅接受2个位置参数。

    命名关键字参数可以有缺省值,从而简化调用:

    def person(name, age, *, city='Beijing', job):print(name, age, city, job)

    由于命名关键字参数city具有默认值,调用时,可不传入city参数:

    >>> person('Jack', 24, job='Engineer')
    Jack 24 Beijing Engineer

    使用命名关键字参数时,要特别注意,如果没有可变参数,就必须加一个*作为特殊分隔符。如果缺少*,Python解释器将无法识别位置参数和命名关键字参数:

    def person(name, age, city, job):# 缺少 *,city和job被视为位置参数pass
  • 默认参数

    • 调用函数时,默认参数的值如果没有传入,则被认为是默认值。下例会打印默认的age,如果age没有被传入:

    • #!/usr/bin/python
      # -*- coding: UTF-8 -*-#可写函数说明
      def printinfo( name, age = 35 ):"打印任何传入的字符串"print "Name: ", nameprint "Age ", agereturn#调用printinfo函数
      printinfo( age=50, name="miki" )
      printinfo( name="miki" )

      定义默认参数要牢记一点:默认参数必须指向不变对象!

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

      很多初学者很疑惑,默认参数是[],但是函数似乎每次都“记住了”上次添加了'END'后的list。

      原因解释如下:

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

  • 可变参数

    在Python函数中,还可以定义可变参数。顾名思义,可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个。

    我们以数学题为例子,给定一组数字a,b,c……,请计算a2 + b2 + c2 + ……。

    要定义出这个函数,我们必须确定输入的参数。由于参数个数不确定,我们首先想到可以把a,b,c……作为一个list或tuple传进来,这样,函数可以定义如下:

    def calc(numbers):sum = 0for n in numbers:sum = sum + n * nreturn sum

    但是调用的时候,需要先组装出一个list或tuple:

    >>> calc([1, 2, 3])
    14
    >>> calc((1, 3, 5, 7))
    84

    如果利用可变参数,调用函数的方式可以简化成这样:

    >>> calc(1, 2, 3)
    14
    >>> calc(1, 3, 5, 7)
    84

    所以,我们把函数的参数改为可变参数:

    def calc(*numbers):sum = 0for n in numbers:sum = sum + n * nreturn sum

    定义可变参数和定义一个list或tuple参数相比,仅仅在参数前面加了一个*。在函数内部,参数numbers接收到的是一个tuple,因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数

    >>> calc(1, 2)
    5
    >>> calc()
    0

    如果已经有一个list或者tuple,要调用一个可变参数怎么办?可以这样做:

    >>> nums = [1, 2, 3]
    >>> calc(nums[0], nums[1], nums[2])
    14

    这种写法当然是可行的,问题是太繁琐,所以Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去

    >>> nums = [1, 2, 3]
    >>> calc(*nums)
    14

    *nums表示把nums这个list的所有元素作为可变参数传进去。这种写法相当有用,而且很常见。

    def change(*numbers):sum=0;for i in numbers:sum+=i;return sum;
    print(change(1,2,3))
    st=(1,2,3,4,5,6,7)
    print(change(*st))

    在Python中定义函数,可以用必选参数、默认参数、可变参数和关键字参数,这4种参数都可以一起使用,或者只用其中某些,但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数和关键字参数。

    def func(a, b, c=0, *args, **kw):print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
    >>> func(1, 2)
    a = 1 b = 2 c = 0 args = () kw = {}
    >>> func(1, 2, c=3)
    a = 1 b = 2 c = 3 args = () kw = {}
    >>> func(1, 2, 3, 'a', 'b')
    a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
    >>> func(1, 2, 3, 'a', 'b', x=99)
    a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
  • 匿名函数

    • python 使用 lambda 来创建匿名函数。

      • lambda只是一个表达式,函数体比def简单很多。
      • lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
      • lambda函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。
      • 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。

      语法

      lambda函数的语法只包含一个语句,如下:

      lambda [arg1 [,arg2,.....argn]]:expression

      如下实例:

      实例(Python 2.0+)

      #!/usr/bin/python # -- coding: UTF-8 -- # 可写函数说明 sum = lambda arg1, arg2: arg1 + arg2 # 调用sum函数 print "相加后的值为 : ", sum( 10, 20 ) print "相加后的值为 : ", sum( 20, 20 )

      以上实例输出结果:

      相加后的值为 :  30
      相加后的值为 :  40
  • 返回多个值

    • import mathdef move(x, y, step, angle=0):nx = x + step * math.cos(angle)ny = y - step * math.sin(angle)return nx, nyx, y = move(100, 100, 60, math.pi / 6)
  • 全局变量和局部变量

    定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。

    局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。如下实例:

    实例(Python 2.0+)

    #!/usr/bin/python
    # -*- coding: UTF-8 -*-total = 0 # 这是一个全局变量
    # 可写函数说明
    def sum( arg1, arg2 ):#返回2个参数的和."total = arg1 + arg2 # total在这里是局部变量.print "函数内是局部变量 : ", totalreturn total#调用sum函数
    sum( 10, 20 )
    print "函数外是全局变量 : ", total

    默认参数一定要用不可变对象,如果是可变对象,程序运行时会有逻辑错误!

    要注意定义可变参数和关键字参数的语法:

    *args是可变参数,args接收的是一个tuple;

    kw是关键字参数,kw接收的是一个dict。

    以及调用函数时如何传入可变参数和关键字参数的语法:

    可变参数既可以直接传入:func(1, 2, 3),又可以先组装list或tuple,再通过*args传入:func(*(1, 2, 3))

    关键字参数既可以直接传入:func(a=1, b=2),又可以先组装dict,再通过**kw传入:func(**{'a': 1, 'b': 2})

    **使用*args**kw是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。

    命名的关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。

    定义命名的关键字参数在没有可变参数的情况下不要忘了写分隔符*,否则定义的将是位置参数。

  • 函数别名

    • 函数名其实就是指向一个函数对象的引用,完全可以把函数名赋给一个变量,相当于给这个函数起了一个“别名

    • >>> a = abs # 变量a指向abs函数
      >>> a(-1) # 所以也可以通过a调用abs函数
      1
  • Import 与 from import

    • >>> import datetime>>> print(datetime.datetime.now()>>> from datetime import datetime>>> print(datetime.now())
  • 包的概念 packa包中

    • from packa.a import a
      from packa.b import b
      a()
      b()

22、切片

lis=[1,2,3,4,5,6,7,8]
print(lis[0:3])
print(lis[:4])
print(lis[-5:-3])
print(lis[-5:])

23、迭代

  • 在Python中,迭代是通过for ... in来完成的

    • for num in lis:print(num)
  • 默认情况下,dict迭代的是key。如果要迭代value,可以用for value in d.values(),如果要同时迭代key和value,可以用for k, v in d.items()

    • d = {'a': 1, 'b': 2, 'c': 3}
      for k in d:print(k)
      for v in d.values():print(v)
      for k,v in d.items():print('k=',k,'v=',v)
  • 字符串也是可迭代对象

    • for ch in 'ABCD':print(ch)
  • 如何判断一个对象是可迭代对象呢?方法是通过collections模块的Iterable类型判断:

    • >>> from collections import Iterable
      >>> isinstance('abc', Iterable) # str是否可迭代
      True
      >>> isinstance([1,2,3], Iterable) # list是否可迭代
      True
      >>> isinstance(123, Iterable) # 整数是否可迭代
      False
  • 如果要对list实现类似Java那样的下标循环怎么办?Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身:

    • for i,v in enumerate(lis):print(i,v)

24、列表生成式

  • 列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。

  • python range() 函数可创建一个整数列表,一般用在 for 循环中。

  • print(list(range(1,20)))l=[]
    for i in range(1,20):l.append(i*i)
    print(l)print([x * x for x in range(1,5)]) #列表生成式print([x * x for x in range(1, 10) if x%2==1])print([d for d in os.listdir('/')])  #import os

    写列表生成式时,把要生成的元素x * x放到前面,后面跟for循环,就可以把list创建出来,十分有用,多写几次,很快就可以熟悉这种语法。

    for循环后面还可以加上if判断

    还可以使用两层循环,可以生成全排列

    print([x+y for x in 'abc' for y in 'bdf'])
  • 列表生产式也可以同时使用多个变量

    • d = {'x': 'A', 'y': 'B', 'z': 'C'}
      print([k+'='+v for k,v in d.items()])
  • 列表生成式中的if…else

    • print([[x if x % 2 == 0 else -x for x in range(1, 11)]])print([x if x>2 else 100 for x in range(1,5)])

      在一个列表生成式中,for前面的if ... else是表达式,而for后面的if是过滤条件,不能带else

25、生成器

  • 通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

    所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

    要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator

    g=(x*x for x in range(10));
    print(next(g))
    print(next(g))
    print(next(g))
    for i in g:print(i)

    generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

    我们创建了一个generator后,基本上永远不会调用next(),而是通过for循环来迭代它,并且不需要关心StopIteration的错误。

  • generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现

    • def fib(max):n, a, b = 0, 0, 1while n < max:yield ba, b = b, a + bn = n + 1return 'done'

      如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator;

      函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

      def odd():print('step 1')yield 1print('step 2')yield(3)print('step 3')yield(5)

      但是用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIterationvalue中:

      >>> g = fib(6)
      >>> while True:
      ...     try:
      ...         x = next(g)
      ...         print('g:', x)
      ...     except StopIteration as e:
      ...         print('Generator return value:', e.value)
      ...         break
      ...
      g: 1
      g: 1
      g: 2
      g: 3
      g: 5
      g: 8
      Generator return value: done

26、迭代器

  • 一类是集合数据类型,如listtupledictsetstr等;

    一类是generator,包括生成器和带yield的generator function。

    这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

    可以使用isinstance()判断一个对象是否是Iterable对象

  • 而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

    可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

  • 生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator

    listdictstrIterable变成Iterator可以使用iter()函数:

    >>> isinstance(iter([]), Iterator)
    True
    >>> isinstance(iter('abc'), Iterator)
    True

    你可能会问,为什么listdictstr等数据类型不是Iterator

    这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算

    Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

  • 凡是可作用于for循环的对象都是Iterable类型;

    凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

    集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

    Python的for循环本质上就是通过不断调用next()

27、函数式编程

1、高阶函数

  • 变量可以指向函数
  • 函数名也是变量
  • 既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数

  • f=abs
    print(f)
    abs=10  #abs本来是内嵌函数
    print(abs)def absAdd(x,y,f):return f(x)+f(y)
    print(absAdd(-1,-2,f))

2、map/reduce

  • map

    • def pow(x):return x*x
      # 返回的是一个Iterator  因此通过list()函数让它把整个序列都计算出来并返回一个list。
      lis = map(pow, [1, 2, 3, 4, 5])
      print(list(lis))print(list(map(str,[1,2,3,4,5])))   #返回字符串
  • reduce

    • from functools import reduce
      def add(x,y):return x+y
      print(reduce(add,[1,2,3,4,5]))

      reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,re**duce把结果继续和序列的下一个元素做累积计算**,其效果就是:

      reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
  • filter

    • Python内建的filter()函数用于过滤序列。和map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

      • def is_odd(n):return n % 2 == 1list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
        # 结果: [1, 5, 9, 15]
  • sorted

    • >>> sorted([36, 5, -12, 9, -21])
      [-21, -12, 5, 9, 36]

      此外,sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序:

      >>> sorted([36, 5, -12, 9, -21], key=abs)
      [5, 9, -12, -21, 36]

      key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序。

3、返回函数

  • def lazy_sum(*args):def sum():ax = 0for n in args:ax = ax + nreturn axreturn sumf = lazy_sum(1, 3, 5, 7, 9)
    print(f())

    当我们调用lazy_sum()时,返回的并不是求和结果,而是求和函数:

    在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。

闭包

  • 当一个函数返回了一个函数后,其内部的局部变量还被新函数引用

  • 返回的函数并没有立刻执行,而是直到调用了f()才执行

  • def count():fs = []for i in range(1, 4):def f():return i*ifs.append(f)return fsf1, f2, f3 = count()
    在上面的例子中,每次循环,都创建了一个新的函数,然后,把创建的3个函数都返回了。你可能认为调用f1(),f2()和f3()结果应该是1,4,9,但实际结果是:>>> f1()
    9
    >>> f2()
    9
    >>> f3()
    9
    def count():fs = []for i in range(1, 4):def f():return i*ifs.append(f)return fsf1, f2, f3 = count()

    在上面的例子中,每次循环,都创建了一个新的函数,然后,把创建的3个函数都返回了。

    你可能认为调用f1()f2()f3()结果应该是149,但实际结果是:

    >>> f1()
    9
    >>> f2()
    9
    >>> f3()
    9

    全部都是9!原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9

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

4、lambda

  • f=lambda x:x*x-2;
    f1=lambda x,y:x+y
    print(f(2))
    print(f1(3,4))

5、装饰器

  • def log(f):def decrotor(*args,**kw):print('call %s():' % f.__name__)return f(*args, **kw)return decrotor
    @log
    def tes():print('tes')
    tes()

    @log放到now()函数的定义处,相当于执行了语句:

    now = log(now)

    由于log()是一个decorator,返回一个函数,所以,原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数,于是调用now()将执行新函数,即在log()函数中返回的wrapper()函数。

    wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数。

  • 如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会更复杂。比如,要自定义log的文本:

    def log(text):def decorator(func):def wrapper(*args, **kw):print('%s %s():' % (text, func.__name__))return func(*args, **kw)return wrapperreturn decorator

    这个3层嵌套的decorator用法如下:

    @log('execute')
    def now():print('2015-3-25')

    执行结果如下:

    >>> now()
    execute now():
    2015-3-25

    和两层嵌套的decorator相比,3层嵌套的效果是这样的:

    >>> now = log('execute')(now)

    我们来剖析上面的语句,首先执行log('execute'),返回的是decorator函数,再调用返回的函数,参数是now函数,返回值最终是wrapper函数。

    以上两种decorator的定义都没有问题,但还差最后一步。因为我们讲了函数也是对象,它有__name__等属性,但你去看经过decorator装饰之后的函数,它们的__name__已经从原来的'now'变成了'wrapper'

    >>> now.__name__
    'wrapper'

    因为返回的那个wrapper()函数名字就是'wrapper',所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。

    不需要编写wrapper.__name__ = func.__name__这样的代码,Python内置的functools.wraps就是干这个事的,所以,一个完整的decorator的写法如下:

    import functoolsdef log(func):@functools.wraps(func)def wrapper(*args, **kw):print('call %s():' % func.__name__)return func(*args, **kw)return wrapper

    或者针对带参数的decorator:

    import functoolsdef log(text):def decorator(func):@functools.wraps(func)def wrapper(*args, **kw):print('%s %s():' % (text, func.__name__))return func(*args, **kw)return wrapperreturn decorator

    import functools是导入functools模块。模块的概念稍候讲解。现在,只需记住在定义wrapper()的前面加上@functools.wraps(func)即可。

6、偏函数

  • Python的functools模块提供了很多有用的功能,其中一个就是偏函数(Partial function)。

  • nt()函数可以把字符串转换为整数,当仅传入字符串时,int()函数默认按十进制转换:

    >>> int('12345')
    12345

    int()函数还提供额外的base参数,默认值为10。如果传入base参数,就可以做N进制的转换:

    >>> int('12345', base=8)
    5349
    >>> int('12345', 16)
    74565

    假设要转换大量的二进制字符串,每次都传入int(x, base=2)非常麻烦,于是,我们想到,可以定义一个int2()的函数,默认把base=2传进去:

    def int2(x, base=2):return int(x, base)

    这样,我们转换二进制就非常方便了:

    >>> int2('1000000')
    64
    >>> int2('1010101')
    85

    functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2(),可以直接使用下面的代码创建一个新的函数int2

    >>> import functools
    >>> int2 = functools.partial(int, base=2)
    >>> int2('1000000')
    64
    >>> int2('1010101')
    85

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

    注意到上面的新的int2函数,仅仅是把base参数重新设定默认值为2,但也可以在函数调用时传入其他值:

    >>> int2('1000000', base=10)
    1000000

    最后,创建偏函数时,实际上可以接收函数对象、*args**kw这3个参数,当传入:

    int2 = functools.partial(int, base=2)

    实际上固定了int()函数的关键字参数base,也就是:

    int2('10010')

    相当于:

    kw = { 'base': 2 }
    int('10010', **kw)

    当传入:

    max2 = functools.partial(max, 10)

    实际上会把10作为*args的一部分自动加到左边,也就是:

    max2(5, 6, 7)

    相当于:

    args = (10, 5, 6, 7)
    max(*args)

    结果为10

28、模块

#!/usr/bin/env python3
# -*- coding: utf-8 -*-' a test module '__author__ = 'Michael Liao'import sysdef test():args = sys.argvif len(args)==1:print('Hello, world!')elif len(args)==2:print('Hello, %s!' % args[1])else:print('Too many arguments!')if __name__=='__main__':test()

第1行和第2行是标准注释,第1行注释可以让这个hello.py文件直接在Unix/Linux/Mac上运行,第2行注释表示.py文件本身使用标准UTF-8编码;

第4行是一个字符串,表示模块的文档注释,任何模块代码的第一个字符串都被视为模块的文档注释;

第6行使用__author__变量把作者写进去,这样当你公开源代码后别人就可以瞻仰你的大名;

以上就是Python模块的标准文件模板,当然也可以全部删掉不写,但是,按标准办事肯定没错。

你可能注意到了,使用sys模块的第一步,就是导入该模块:

import sys

导入sys模块后,我们就有了变量sys指向该模块,利用sys这个变量,就可以访问sys模块的所有功能。

sys模块有一个argv变量,用list存储了命令行的所有参数。argv至少有一个元素,因为第一个参数永远是该.py文件的名称,例如:

运行python3 hello.py获得的sys.argv就是['hello.py']

运行python3 hello.py Michael获得的sys.argv就是['hello.py', 'Michael']

最后,注意到这两行代码:

if __name__=='__main__':test()

**当我们在命令行运行hello模块文件时,Python解释器把一个特殊变量__name__置为__main__,**而如果在其他地方导入该hello模块时,if判断将失败,因此,这种if测试可以让一个模块通过命令行运行时执行一些额外的代码,最常见的就是运行测试。

私有变量和函数
  • 正常的函数和变量名是公开的(public),可以被直接引用,比如:abcx123PI等;

    类似__xxx__这样的变量是特殊变量,可以被直接引用,但是有特殊用途,比如上面的__author____name__就是特殊变量,hello模块定义的文档注释也可以用特殊变量__doc__访问,我们自己的变量一般不要用这种变量名;

    **类似_xxx__xxx**这样的函数或变量就是非公开的(private),不应该被直接引用,比如_abc__abc等;

  • 类似_xxx__xxx这样的函数或变量就是非公开的(private),不应该被直接引用,比如_abc__abc等;

    之所以我们说,private函数和变量“不应该”被直接引用,而不是“不能”被直接引用,是因为Python并没有一种方法可以完全限制访问private函数或变量,但是,从编程习惯上不应该引用private函数或变量。

在Python中,有以下几种方式来定义变量:

  • xx:公有变量
  • _xx:单前置下划线,私有化属性或方法,类对象和子类可以访问,from somemodule import *禁止导入
  • __xx:双前置下划线,私有化属性或方法,无法在外部直接访问(名字重整所以访问不到)
  • xx:双前后下划线,系统定义名字(不要自己发明这样的名字)
  • xx_:单后置下划线,用于避免与Python关键词的冲突

使用不同方法导入模块,模块中私有变量的使用区别

在使用不同方法导入模块后,是否能使用模块中的私有属性和方法,有以下两种情况

  • 在使用 from somemodule import * 导入模块的情况下,不能导入或使用私有属性和方法
  • 在使用 import somemodule 导入模块的情况下,能导入并使用私有属性和方法
第三方模块
  • 在Python中,安装第三方模块,是通过包管理工具pip完成的。

  • 模块搜索路径

    当我们试图加载一个模块时,Python会在指定的路径下搜索对应的.py文件,如果找不到,就会报错:

    >>> import mymodule
    Traceback (most recent call last):File "<stdin>", line 1, in <module>
    ImportError: No module named mymodule

    默认情况下,Python解释器会搜索当前目录、所有已安装的内置模块和第三方模块,搜索路径存放在sys模块的path变量中

    >>> import sys
    >>> sys.path
    ['', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python36.zip', '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6', ..., '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages']

    如果我们要添加自己的搜索目录,有两种方法:

    一是直接修改sys.path,添加要搜索的目录:

    >>> import sys
    >>> sys.path.append('/Users/michael/my_py_scripts')

    这种方法是在运行时修改,运行结束后失效。

    第二种方法是设置环境变量PYTHONPATH,该环境变量的内容会被自动添加到模块搜索路径中。设置方式与设置Path环境变量类似。注意只需要添加你自己的搜索路径,Python自己本身的搜索路径不受影响。

29、类和实例

    • class Student(object):def __init__(self, name, score):self.name = nameself.score = score

class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的,继承的概念我们后面再讲,通常,如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类。

由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的__init__方法,在创建实例的时候,就把namescore等属性绑上去

注意到**__init__方法的第一个参数永远是self,表示创建的实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。**

有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,但self不需要传,Python解释器自己会把实例变量传进去

和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,并且,调用时,不用传递该参数。除此之外,类的方法和普通函数没有什么区别,所以,你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。

可以自由地给一个实例变量绑定属性

class Student(object):def __init__(self, name, score):self.__name = nameself.__score = scoredef get_grade(self):if self.score >= 90:return 'A'elif self.score >= 60:return 'B'else:return 'C'

方法就是与实例绑定的函数,和普通函数不同,方法可以直接访问实例的数据;

stu=Student('zdc',29)
def min(a,b):if a>b:return belse:return a
print(stu)
stu.min=min
print(stu.min(1,2))
stu.zz='ssd'
print(stu.zz)

实例可以任意添加属性和方法

30、访问限制

class Student(object):def __init__(self,name,score):self.__name=nameself.__score=scorestu=Student('zdc',29)print(stu._Student__name)#可以访问
print(stu.__name)

如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问,所以,我们把Student类改一改:

class Student(object):def __init__(self, name, score):self.__name = nameself.__score = scoredef print_score(self):print('%s: %s' % (self.__name, self.__score))

改完后,对于外部代码来说,没什么变动,但是已经无法从外部访问实例变量.__name实例变量.__score了:

>>> bart = Student('Bart Simpson', 59)
>>> bart.__name
Traceback (most recent call last):File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute '__name'

这样就确保了外部代码不能随意修改对象内部的状态,这样通过访问限制的保护,代码更加健壮。

但是如果外部代码要获取name和score怎么办?可以给Student类增加get_nameget_score这样的方法:

class Student(object):...def get_name(self):return self.__namedef get_score(self):return self.__score

如果又要允许外部代码修改score怎么办?可以再给Student类增加set_score方法:

class Student(object):...def set_score(self, score):self.__score = score

你也许会问,原先那种直接通过bart.score = 99也可以修改啊,为什么要定义一个方法大费周折?因为在方法中,可以对参数做检查,避免传入无效的参数:

class Student(object):...def set_score(self, score):if 0 <= score <= 100:self.__score = scoreelse:raise ValueError('bad score')

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

有些时候,你会看到以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。

双下划线开头的实例变量是不是一定不能从外部访问呢?其实也不是。不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name,所以,仍然可以通过_Student__name来访问__name变量

31、继承和多态

  • class Animal(object):def run(self):print('Animal is running...')class Dog(Animal):passclass Cat(Animal):passdog = Dog()
    dog.run()

    继承的第二个好处需要我们对代码做一点改进。你看到了,无论是Dog还是Cat,它们run()的时候,显示的都是Animal is running...,符合逻辑的做法是分别显示Dog is running...Cat is running...,因此,对DogCat类改进如下:

    class Dog(Animal):def run(self):print('Dog is running...')class Cat(Animal):def run(self):print('Cat is running...')

    再次运行,结果如下:

    Dog is running...
    Cat is running...

    当子类和父类都存在相同的run()方法时,我们说,子类的run()覆盖了父类的run(),在代码运行的时候,总是会调用子类的run()。这样,我们就获得了继承的另一个好处:多态。

    def run_twice(animal):animal.run()

32、获取对象信息

  • 基本类型都可以用type()判断

    >>> type(123)
    <class 'int'>
    >>> type('str')
    <class 'str'>
    >>> type(None)
    <type(None) 'NoneType'>

    如果一个变量指向函数或者类,也可以用type()判断:

    >>> type(abs)
    <class 'builtin_function_or_method'>
    >>> type(a)
    <class '__main__.Animal'>

    但是type()函数返回的是什么类型呢?它返回对应的Class类型。如果我们要在if语句中判断,就需要比较两个变量的type类型是否相同:

    >>> type(123)==type(456)
    True
    >>> type(123)==int
    True
    >>> type('abc')==type('123')
    True
    >>> type('abc')==str
    True
    >>> type('abc')==type(123)
    False

    判断基本数据类型可以直接写intstr等,但如果要判断一个对象是否是函数怎么办?可以使用types模块中定义的常量:

    >>> import types
    >>> def fn():
    ...     pass
    ...
    >>> type(fn)==types.FunctionType
    True
    >>> type(abs)==types.BuiltinFunctionType
    True
    >>> type(lambda x: x)==types.LambdaType
    True
    >>> type((x for x in range(10)))==types.GeneratorType
    True
  • 使用isinstance()

    • 对于class的继承关系来说,使用type()就很不方便。我们要判断class的类型,可以使用isinstance()函数。

    • isinstance()就可以告诉我们,一个对象是否是某种类型。先创建3种类型的对象:>>> a = Animal()
      >>> d = Dog()
      >>> h = Husky()
      然后,判断:>>> isinstance(h, Husky)
      True
      >>> isinstance(h, Dog)
      True    #但由于Husky是从Dog继承下来的,所以,h也还是Dog类型
  • dir()

    • 如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list,比如,获得一个str对象的所有属性和方法:

      >>> dir('ABC')
      ['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill']

      仅仅把属性和方法列出来是不够的,配合**getattr()setattr()以及hasattr()**,我们可以直接操作一个对象的状态:

      >>> hasattr(obj, 'x') # 有属性'x'吗?
      True
      >>> obj.x
      9
      >>> hasattr(obj, 'y') # 有属性'y'吗?
      False
      >>> setattr(obj, 'y', 19) # 设置一个属性'y'
      >>> hasattr(obj, 'y') # 有属性'y'吗?
      True
      >>> getattr(obj, 'y') # 获取属性'y'
      19
      >>> obj.y # 获取属性'y'
      19

      如果试图获取不存在的属性,会抛出AttributeError的错误:

      >>> getattr(obj, 'z') # 获取属性'z'
      Traceback (most recent call last):File "<stdin>", line 1, in <module>
      AttributeError: 'MyObject' object has no attribute 'z'

      可以传入一个default参数,如果属性不存在,就返回默认值:

      >>> getattr(obj, 'z', 404) # 获取属性'z',如果不存在,返回默认值404
      404

      也可以获得对象的方法:

      >>> hasattr(obj, 'power') # 有属性'power'吗?
      True
      >>> getattr(obj, 'power') # 获取属性'power'
      <bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
      >>> fn = getattr(obj, 'power') # 获取属性'power'并赋值到变量fn
      >>> fn # fn指向obj.power
      <bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
      >>> fn() # 调用fn()与调用obj.power()是一样的
      81

33、实例属性和类属性

  • class Demo:count=100; #类变量 def __init__(self,name,age):self.__name=nameself.__age=aged=Demo('zz',22)
    d2=Demo('dd',11)
    d.count=222    # 给实例绑定count属性  类的count被隐藏了
    print(d2.count)  #100   因为实例并没有count属性,所以会继续查找class的count属性
    print(d.count)  #222
    print(Demo.count) #100
    del d.count  #删除d的实例属性  此时可以访问到类属性
    print(d.count)

    在编写程序的时候,千万不要对实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性

33、__slots__限制实例绑定任何属性和方法

  • 常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性。但是,给一个实例绑定的方法,对另一个实例是不起作用的

  • 但是,如果我们想要限制实例的属性怎么办?比如,只允许对Student实例添加nameage属性。

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

    class Student(object):__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称>>> s.score = 99 # 绑定属性'score'
    Traceback (most recent call last):File "<stdin>", line 1, in <module>
    AttributeError: 'Student' object has no attribute 'score'

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

  • len

    • __len__
      如果一个类表现得像一个list,要获取有多少个元素,就得用 len() 函数。要让 len() 函数工作正常,类必须提供一个特殊方法__len__(),它返回元素的个数。例如,我们写一个 Students 类,把名字传进去:class Students(object):def __init__(self, *args):self.names = argsdef __len__(self):return len(self.names)
      只要正确实现了__len__()方法,就可以用len()函数返回Students实例的“长度”:

34、@property @xxx.setter

  • class Person(object):@propertydef birth(self):return self._birth@birth.setterdef birth(self, value):self._birth = value@propertydef age(self):return 2015 - self._birthp = Person()
    p.birth = 100
    # p.age=11  #age为只读
    print(p.birth)
    print(p.age)

    把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值

35、多继承

  • Python允许使用多重继承

36、定制类

  • str

    我们先定义一个Student类,打印一个实例:

    >>> class Student(object):
    ...     def __init__(self, name):
    ...         self.name = name
    ...
    >>> print(Student('Michael'))
    <__main__.Student object at 0x109afb190>

    打印出一堆<__main__.Student object at 0x109afb190>,不好看。

    怎么才能打印得好看呢?只需要定义好__str__()方法,返回一个好看的字符串就可以了:

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

    这样打印出来的实例,不但好看,而且容易看出实例内部重要的数据。

怎么说呢,python 的特性太胶水了,不适合作为项目主力,所以它是生产力技能而不是业务技能。

真的不建议学Python,煞笔才学习Python,学Python难?两个小时足够搞定相关推荐

  1. 学妹问我Java枚举类与注解,我直接用这个搞定她!

    很多人问我学妹长什么样,不多说 上图吧! 学妹问我Java枚举类与注解,我直接一篇文章搞定! 一.枚举类 ① 自定义枚举类 ② enum关键字定义枚举类 ③ enum 枚举类的方法 ④ enum 枚举 ...

  2. python语言翻译成中文-Python 神工具包!翻译、文字识别、语音转文字统统搞定...

    原标题:Python 神工具包!翻译.文字识别.语音转文字统统搞定 今天给大家介绍一款 Python 制作的实用工具包,包含多种功能: 音频转文字 文字转语音 截图 OCR文字识别 复制翻译 举个例子 ...

  3. 前端学python有什么用-学习和使用python的13个理由

    如果您希望转向网站开发或软件开发,成为程序员中的一员,那么学习HTML,CSS和JavaScript的基础三重奏就不会出错.但要真正在拥挤的应用领域中脱颖而出,您还是需要学习其他编程语言. 有很的编程 ...

  4. python工程师笔试题_2019年,Python工程师必考的6个面试题,Python面试题No5

    函数 tuple(seq) 可以把所有 可迭代的(iterable)序列 转换成一个 tuple , 元素不变,排序也不变 list转为tuple: temp_list = [1,2,3,4,5] 复 ...

  5. 业余学java还是python_业余学习Java和Python哪个比较合适?

    就我个人而言,业余使用,不考虑就业需求,那肯定是Python. 首先要考虑的是Java的难度问题.Java当中涉及到很多概念,比如什么package包啊,或者是什么静态类动态类等等.如果是要写一些大型 ...

  6. 加班奖励 python_“加班做了2天的方案,同事用Python半个小时就搞定了?”

    最近, 朋友娜娜跟我说,她想辞职了. 娜娜在上海一家公司做了 3 年的市场销售, 为了更好地完成业绩,每天都赶着最后一班地铁回家. 毕业 3 年,算上加班时长, 说是工作了 5 年也不过分! 像她这样 ...

  7. 初学者自学python要看什么书-学习Python可以看书籍学习吗?老男孩Python入门课程...

    在人工智能和数据分析的带领之下,推动了互联网市场的发展,也推动了python语言的发展,让它成为了市场上炙手可热的编程语言. 而python具有入门简单.就业范围广泛.薪资水平高诸多优势,越来越多的人 ...

  8. 零基础自学python看什么书-学习Python可以看书籍学习吗?老男孩Python入门课程

    在人工智能和数据分析的带领之下,推动了互联网市场的发展,也推动了python语言的发展,让它成为了市场上炙手可热的编程语言. 而python具有入门简单.就业范围广泛.薪资水平高诸多优势,越来越多的人 ...

  9. python零基础系统学习教程之Python 变量类型

    Python 变量类型 变量存储在内存中的值.这就意味着在创建变量时会在内存中开辟一个空间. 基于变量的数据类型,解释器会分配指定内存,并决定什么数据可以被存储在内存中. 因此,变量可以指定不同的数据 ...

最新文章

  1. leetcode17. 电话号码的字母组合--每天刷一道leetcode算法系列!
  2. rust怎么不要的墙拆掉_封阳台,栏杆要不要拆掉?栏杆装在玻璃窗里面还是外面...
  3. 前端学习(1943)vue之电商管理系统电商系统之通过路由加载商品分类
  4. 删除单元格_VBA(实验1)用VBA 删除某列空单元格的3种方法:删除法,转移到其他列方法,数组方法...
  5. 小小数据统计(柱状图、折线图、扇形图)
  6. 对标Postman的ApiPost创始人:用户,是ApiPost唯一的信仰
  7. 没有任何一个行业是没有竞争的
  8. 如何使用CodeBlocks开发C/C++程序
  9. Nginx常见问题(优化)
  10. 20-30岁怎么规划自己的人生呢?
  11. 打造高速浏览器,逐鹿搜索市场,搜狗高速浏览器2.0值得期待
  12. 什么是 Python Launcher?
  13. 母函数——整数拆分(HDOJ2152)
  14. jquery上传图片本地预览插件V1.2
  15. zendstudio最新下载地址
  16. 《地理信息系统导论》chapter 7 空间数据准确度和质量
  17. 如何做好云上资源的费用管理?
  18. 【转】数据挖掘,你不应该错过的六本书
  19. 031 突破SQL注入限制的一点想法
  20. 【转帖】windows 服务大全

热门文章

  1. 制定标准的重要性和意义_标准的重要性
  2. Chrome的启动参数
  3. matlab复数开偶次方根,运用复数1的n次方根巧解一类复数方程
  4. json和jsonp区别与讲解
  5. 【Kafka】测试集群中Broker故障对客户端的影响
  6. [Pytorch]torch.nn.functional.conv2d与深度可分离卷积和标准卷积
  7. html箭头相关符号
  8. mysql字段掩码_什么叫掩码
  9. 提供Minimal SD Base Gal/Raf SD基础培养基(含半乳糖/棉子糖)
  10. VS code snippets