Python编程导论(第二版)-学习笔记

本文深入探讨Python编程中的关键概念,包括语法与语义的区别、特殊函数如lambda的使用、变量作用域的细节、递归算法的应用及数据结构的高效利用等。此外,还介绍了Python在机器学习领域的初步应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

语法和语义的差别

例子“

foo = 10 / 'abc'

用字面常量除以字符串,==完全符合语法!==;但是不符合语义,因为使用数字除以字符串是没有任何意义的。

Python会进行静态语义检查,但是并不会报告全部语义错误;它们当中有些情况下会造成程序执行意料之外

小知识点

  1. Py2中print是解释器的命令而Py3中print是一个函数
  2. type()
  3. ==除法使用//而不是’/’==
  4. **次方运算
  5. ==bool操作==:and or not
  6. Python自带的IDE叫做IDLE,它只是一个人名也是一个喜剧团体名,并不是英文缩写
  7. 常用的IDE:Anaconda Canopy
  8. 使用elif而不是else if
  9. 10 * ‘foo’ 重复10次,这时*称为重复符,不是乘号
  10. print()的多个参数用逗号分隔时,每个参数输出的时候回自动追加空格
  11. input(‘提示信息…’)会将用户的输入解释为str对象,至于程序希望得到用户的输入是数字,那么得主动将其转换为number或使用int()包裹input()函数
  12. 使用epsilon来给表示近似范围的变量命名;如abs(a - b) < epsilon,则认为a、b近似
  13. 求平方根的边界条件应该是answer ** 2 < number 而不是answer < number;其中answer是平方根而number是被求平方根的数
  14. ==别忘了可以使用in来检查一个对象是否在另一个对象内出现或包含==
  15. 判断是否是小写字母:if c in ‘abcdefghijklmnopqrstuvwxyz’
  16. ==可以在函数内部定义函数,这一内部函数可以在函数中调用,称为辅助函数==;例:def funcA(): def funcB():… funcB() # 在funcA内部定义函数funcB,然后funcA调用funcB
  17. 字符串或容器集合处理的时候,注意用好切片功能
  18. 单元素元组必须带括号
  19. 加号作用于元组的时候是连接而不是相加
  20. x,y,z=’abc’是序列化多重赋值,并不是仅仅对z赋值,xyz分别是abc
  21. 元组和字符串都是不可变的,都能用索引来引用其元素但是都不能通过索引来修改它
  22. Python中元素其实就是一个名称,它表示了这个名称对应的绑定的变量,如,s=’aaa’表示s绑定到了对象sss
  23. ==对对象赋值,实际上就是创建了一个新的对象,然后将变量名称绑定到了这个新的对象,旧的对象不再被引用,实际上并没有修改旧对象。==修改一个变量后实际上是绑定到了新对象,因此id()函数返回值不同
  24. id()可以得到对象的唯一标识符,可以判断是不是同一个对象。
  25. 可以使用list(foo)等类似的函数拷贝容器
  26. ==执行深度拷贝,用标准库copy的copy.deepcopy==
  27. [x ** 2 for x in range(10) if x > 100]
  28. 函数也是对象
  29. 高阶函数:有至少一个参数是函数
  30. 内置了一个高阶函数:map()可以使用
  31. 除了list,str tuple range都是不可变的
  32. 如果省略split的参数,那么实际上用包括换行回车分页制表空格在内的所有空白字符作为split字符
  33. dict是无序的,可以直接对dict[newKey]赋值得到新的键值对
  34. ==字典使用del来删除元素而其他类型使用remove方法来进行删除
  35. 允许重载操作符,通过重载特殊方法来实现
  36. 继承:class Foo(Bar)
  37. ==务必主动显式地调用基类的构造函数==,基类的_ init _不是自动调用的
  38. ==注意:return 一个容器并不是返回其副本而是返回其引用!!!,要想返回其副本必须使用全切片:return foo[:]==
  39. 在Py中使用类似MATLAB的功能,可以使用标准库PyLab
  40. UNIX中的rc文件:RuntimeConfig
  41. numpy除了多维数组,还拥有大量线性代数的工具
  42. 最优化问题:比如一些需要求最大值最小值的问题
  43. 编写的函数如果会调用到外部的其它函数,最好考虑一下要不要做成高阶函数,即将函数对象作为参数传递进来。
  44. 背包的最优解问题:可以使用暴力解贪婪算法去解决
  45. 用贪婪法不一定能找到背包问题的最优解,但是背包中的物品是可以分解的即连续/分数背包问题的时候,贪婪算法一定可以找到最优解
  46. 数据可视化图表:plot chart ,数据结构中的图:graph
  47. 动态规划:当问题可以被分解为重复的子问题或存在子问题被处理多次的时候适用
  48. 斐波那契数列可以使用动态规划备忘录法,P156
  49. 概率分布
  50. 正态分布即高斯分布,在均值处概率取最大值
  51. 条件概率:当某个事件B为真时,事件A的发生概率P(A|B)
  52. 贝叶斯定理:与条件概率密切相关
  53. 贝叶斯定理比常规条件概率更高级的地方:它考虑了B事件的置信度,即B事件为真的时候其准确为真的概率

lambda函数

lambda args:
函数体

‘//’执行整数除法,只返回结果的商而丢弃余数;’/’执行浮点数除法

赋值特性

多重赋值

foo,bar = 10, 20

先对等号右侧进行求值

SWAP赋值

foo,bar = bar, foo

生成序列

Py2中的range()在生成序列的时候会一次性将序列中的所有成员都生成并放入内存,这导致较大的资源占用。Py3中的range()没有这个问题,不会一次性生成所有成员。另外,Py2可以使用xran
ge()替代range(),xrange()与Py3的range()相同。

如果在range()求值之后,在for - in 代码块内修改range()的范围,此时对range()的范围毫无影响,因为range()已经求值完成了,此时再做修改是没有效果的。

穷举法的限制和缺点

  • 复杂度高,需要穷举才能得到结果
  • 本质是一种查找技术,当正确答案包含在被查找的集合(可以被穷举出来的内容)中时才能得到结果

当穷举集合中不包含正确结果时,无法得到正确结果;例:求25的平方根,使用穷举法从1开始尝试,每次递增0.3,即按照1.0,1.3,1.6,…这样的序列去尝试,由于不可能得到数字5,因此这种穷举法并不能得到正确结果5。

二进数对浮点类型的存储问题

由于==二进制数不能完美地存储浮点数字,因此存在浮点数加减时的误差==

foo = 0.0
for i in range(10):
    i += 0.1
print(foo)

结果是0.99999999而不是1.0。

计算机存储二进制数的原理

存储数字的原理是:有效数字+指数:如1.949的有效数字可以是1949,指数为-3(实际存储的时候要将这些数字转换为二进制值来存储);即==存储一个数就是以二进制形式存储其有效数字以及指数==。
总之,表示0.1是很困难的,只能无限接近。
==因此,10个0.1相加并不等于0.1乘上10==。与C相同,==浮点数之间比较不能直接用’==’而应该用abs(a - b) <= 0.001==。

使用round()可以指定浮点数保留小数点后多少位有效数字

比二分法更好的开方法:牛顿法

如果一个数guess是多项式P的一个根的近似值,那么guess - P(guess)/P’(guess)就是一个更好的近似值。

不同于其他语言的让人懵逼的一种变量作用域情况

如下例:

def func1():
    print(something)
something = 10
func1()
# 执行到此处输出10

def func2():
    print(suprise)
    suprise = 10
suprise = 100
func2()
# 令人震惊的是,这里不能打印出100也当然不可能打印出10;
# 反而会打印出一个错误命令
# UnboundLocalError: local variable 'suprise' referenced before assignment
# 本地变量未绑定错误: 本地变量 '惊讶' 在赋值之前被引用了
  • 这表明:第二个函数未能引用到全局的变量
  • 第二个函数认为suprise未定义

原因分析:
- [x] 只要一个变量出现在了函数体内部,那么在函数执行前,解释器就已经确认了有这个变量的存在,此时,覆盖外部、全局所有/任何同名变量。(==函数在执行之前,其内部定义的所有变量已经在执行函数的第一行代码之前就被加载了==)
- [x] 虽然解释器在函数执行前确认了叫这个名称的变量的存在,但是只要函数没有执行到这个变量的赋值语句,那么这个变量就是没有赋值的。(==函数的第一行代码执行之前,其内部所有定义的变量都是一个没有赋值的变量并且屏蔽外部其他重名变量==)
- [x] 因此,函数内存在的变量会屏蔽外部变量让你无法引用到,这个全局/外部变量被屏蔽了,被降维成函数内部的局部变量,但是却在执行到赋值语句的时候才对它赋值,在此之前对该变量的引用是对未定义的值进行引用。

一般来说,鲁邦的Python代码,是应该努力避免变量名称冲突的。命名技巧的应用:==把你的函数内部定义的变量的名称修改一下:
- 增加下划线
- 增加前后缀
- 大小写变化
- …

如果不了解Python在函数执行前首先加载函数内部所有定义的变量这一特性,就会在命名重名的时候出现这种奇怪的错误。

递归完成回文判断

def isPal(s):
    if len(s) <= 1 :    # 递归结束条件:len <= 1,不可能是回文
        return True
    else:
        return s[0] == s[-1] and isPal(s[1:-1])

不建议使用from foo import *

因为这样虽然可以不使用模块名即可引用模块内的名称,如foo.bar可以直接用bar来使用,但是这样会导致可读性降低,因为看到bar并不能完全断定bar是属于foo模块内的。另外,使用了这种import方式之后,通过模块名称来引用成员的时候会报错,提示模块名称未定义。

模块被import之后,即使该模块的的代码被修改,也不会影响,仍然执行的是旧代码

修改模块代码后想使之生效,可以重启Python解释器

字典使用元组作为键的原因

字典的键必须满足可散列,py中内置的不可变类型都是可散列的而可变类型都是不可散列的,因此可散列的元组是符合条件的

生成器

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

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

以下都是生成器:
- foo = [ x ** 2 for x in range(10)]
- yield

yield的作用

调用的函数内有yield时,在yield处返回,返回值是yield的表达式的值;下一次执行该函数时,从上一次yield返回的位置继续执行。

>>> def odd():
...     print 'step 1'
...     yield 1
...     print 'step 2'
...     yield 3
...     print 'step 3'
...     yield 5
...
>>> o = odd()
>>> o.next()
step 1
1
>>> o.next()
step 2
3
>>> o.next()
step 3
5

yield应用例子

foo = [ x for x in range(1000000)]

def funcYield(foo):
    for item in foo:
        yield item

if 100 in funcYield(foo):
    print(True)

检测某个值是否存在于某个集合。
==使用yileld的优点是:每次遍历集合中的一个值就返回,如果此时符号条件,那么接下来集合的其他内容就不用再遍历了,不仅节省了计算时间还节省了内存空间,因为不再需要一次性生成完整的集合、生成集合中所有元素的副本了==。

图的单遍历问题

遍历图里面的所有节点,要求每个节点只能被进出一次。
欧拉证明了:除了起点和终点以外,行走过程的每个点都必须被偶数条边连接。
因此,如果所有节点都不是偶数条边的话,那么这个图是不可能实现单遍历的。

图的表示

  • 代码表示

节点用一个类表示,边用一个类,其中保存了这条边连接的起点和终点。
- 数学表示

可以使用邻接矩阵或邻接表来表示。

机器学习简介

机器学习步骤
- 观测训练数据集
- 分析训练数据集并进行扩展和建模
- 利用这个模型进行预测

监督式学习:从已有特征向量去预测未知的特征向量的对应值并进行标签分类。其数据都是已经标记的数据。

非监督式学习:特征集合/训练数据没有标记,目的是发现训练数据集合中的隐含模式。
非监督式学习又分为隐变量方法和聚类方法。

  • 聚类方法:对集合中的各个数据进行划分,将相似度高的划分为一个子集。
  • 隐变量方法:隐变量不能被观察到,它一般是通过可观察到的变量推导出来的,如从成绩和测试推断出学生的水平,水平就是训练数据的隐变量。

聚类就是对一组对象找到当中相似的类,相当于对它们进行分类。

常见的监督式学习应用:建立分类模型;==分类模型又称为分类器==,用于对样本进行标注,即对样本进行分类。

K最近邻分类器,又称为KNN分类器。

Programming Python, 2nd Edition 目录如下,需要下载的朋友不要错过哦~ Programming Python, 2nd Edition By Mark Lutz Publisher : O'Reilly Pub Date : March 2001 ISBN : 0-596-00085-5 Pages : 1256 Copyright Foreword Preface "And Now for Something Completely Different . . . Again" Signs of the Python Times Why This Edition? Major Changes in This Edition Using the Examples and Demos Conventions Used in This Book Where to Look for Updates Contacting O'Reilly Acknowledgments Chapter 1. Introducing Python Section 1.1. "And Now for Something Completely Different" Section 1.2. The Life of Python Section 1.3. The Compulsory Features List Section 1.4. What's Python Good For? Section 1.5. What's Python Not Good For? Part I: System Interfaces Chapter 2. System Tools Section 2.1. "The os.path to Knowledge" Section 2.2. Why Python Here? Section 2.3. System Scripting Overview Section 2.4. The sys Module Section 2.5. The os Module Section 2.6. Script Execution Context Section 2.7. Current Working Directory Section 2.8. Command-Line Arguments Section 2.9. Shell Environment Variables Section 2.10. Standard Streams Section 2.11. File Tools Section 2.12. Directory Tools Chapter 3. Parallel System Tools Section 3.1. "Telling the Monkeys What to Do" Section 3.2. Forking Processes Section 3.3. Threads Section 3.4. Program Exits Section 3.5. Interprocess Communication Section 3.6. Pipes Section 3.7. Signals Section 3.8. Launching Programs on Windows Section 3.9. Other System Tools Chapter 4. Larger System Examples I Section 4.1. "Splits and Joins and Alien Invasions"
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值