2.Python基础

  • 2020 年 1 月 10 日
  • 笔记

一.语句和语法

一.继续 ()

  1. Python语句,一般使用换行分隔,也就是说一行一个语句, 一行过场的语句可以使用反斜杠"" 分解成几行.
  2. 两种情况列外一个语句不使用反斜杠也可以跨行. 在使用闭合操作符时,单一语句可以哭啊多行. 例如: 在含有小括号,中括号,花括号时可以多行书写 . 另外就是三引号包括下的字符串也可以跨行书写 .
  3. 如果要在使用反斜杠换行和使用括号元素换行做一个选择,推荐使用小括号. 这样可读性会更好.

二.多个语句构成代码组 (:)

  1. 缩进相同的一组语句构成一个代码块,我们称之为代码组. 像if ,while,wdef 和class这样的符合语句,首航以关键字开始,以 冒号(:)结束,该行之后的一行或者多行代码构成代码组.我们将首航及后面的代码组称为一个子句(clause) .

三 . 代码组由不同的缩进分隔

  1. 同一代码组的代码必须严格左对齐.
  2. 核心风格 : 缩进四个空格宽度,避免使用制表符.
  3. 随着缩进深度的增加,代码块的层次也在加深,没有缩进的代码块是最高层次的,被称作脚本的main 部分 .

四.同一行书写多个语句 (;)

  1. 分号(;) 允许你将多个语句卸载同一行上,语句之间用分号隔开, 而这些语句也不能再这行开始一个新的代码块.

五.模块

  1. 每一个Python脚本文件都可以当成是一个模块.模块以磁盘文件的形式存在. 当一个模块变得过大,并且驱动了太多功能的话,就应该考虑拆一些代码出来另外建一个模块.模块里的代码可以是一段直接执行的脚本,也可以是一堆类似库函数的代码,从而可以被别的模块导入(import) 调用 . 模块可以包含直接运行的代码块,类定义,函数定义或这几者的组合.

二.变量赋值

注意:赋值并不是直接将一个值赋给一个变量,尽管你可能根据其他语言编程经验认为应该如此. 在Python中,对象是通过引用传递的. 在赋值时,不管这个对象是新创建的.还是一个已经存在的,都是将该对象的引用(并不是值) 赋值给变量.

  1. 赋值运算符 : += , -=, *= , /= , %= , **= ,<<= ,>>= ,&= ,^= , /=
  2. 增量赋值 : 增量赋值相对普通赋值不仅仅是写法上的改变,最有意义的变化是第一对象仅被处理一次.可变对象会被就地修改(无修改拷贝引用) , 不可变对象则和 A = A+ B结果一样(分配一个新对象) .
  3. 多重赋值 : x = y = z = 1 . 这个例子中, 一个值为1的整数对象被创建,该对象的同一个引用被赋值给x,y和z . 也就是将一个对象赋给了多个变量. 当然, 在Python当中,将多个对象赋给多个变量也是可以的.
  4. "多元"赋值 : 另一种将多个变量同时赋值的方法我们称为多元赋值(multuple) . 这不是官方Python术语,而是我们将"mul-tuple" 连在一起自造的. 因为采用这种方式赋值时,等号两边的对象都是元组 . x, y, z = 1,2,'good' . 通常元组需要用小括号括起来,尽管他们是可选的. 我们建议总是加上小括号,以使得你的代码有更高的可读性.

三.标识符

标识符是电脑语言中允许作为名字的有效字符串集合 . 其中,有一部分是关键字,构成语言的标识符. 这样的标识符是不能坐它用的标识符的,否则会引起语法错误.

  1. 合法的Python标识符 : 第一个字符必须是字母或下划线 , 剩下的字符可以是字母和数字或下划线,大小写敏感.
  2. 关键字 : import keyword , keyword.iskeyword() 检测是否为关键字 .
  3. 内建 : 除了关键字外,Python还有可以在任何一级代码使用的"内建" 名字集合,这些名字可以由解释器设置或使用.
  4. 专用下划线标识符 : Python用下划线作为变量前缀和后缀指定特殊变量. a. _xxx , 不用from module import * 导入 b. xxx 系统定义名字 c. __xxx 类中的私有变量名
  5. 核心风格 : 避免用下划线作为变量名的开始 : 因为下划线对解释器有特殊的意义,而且是内建标识符所使用的符号,我们建议程序员避免用下划线作为变量名的开始. 一般来讲,变量名_xxx 被看做是"私有的" , 在模块或类外不可以使用 . 当变量是私有的时候,用_xxx来表示变量是很好的习惯. 因为变量名xxx对Python来说有特殊含义,对于普通的变量应当避免这种命名风格 .

四. 基本风格指南

  1. 注释 : 注释对于自己和后来人来说都是非常重要的,特别是对哪些很旧没有被动过的代码而言.记住,确保注释的准确性.
  2. 文档 : Python还提供一个机制,可以通过doc特别变量,动态获得文档字串.在模块,类声明,或函数声明中第一个没有复制的字符串可以用属性 obj.doc来进行访问, 其中obj是一个模块,类,或函数的名字,这在运行时刻也可以运行.

五.模块结构和布局

  1. 用模块来合理组织你的Python代码是简单又自然的方法.你应该建立一种统一且容易阅读的结构,并将它应用到每一个文件中去. 下面就是一种非常合理的布局:
    1. 起始行
    2. 模块文档
    3. 模块导入
    4. 变量定义
    5. 类定义
    6. 函数定义
    7. 主程序
  2. 起始行 : 有起始行就能够仅输入脚本名字来执行脚本,无序之界调用解释器.
  3. 模块文档 : 简要介绍模块的功能及重要全局变量的含义,模块外可通过module.doc访问这些内容.
  4. 变量定义 : 这里定义变量为全局变量,本模块中的所有函数都可直接使用. 从好的编程风格角度说,除非必须,否则就要尽量使用局部变量代替全局变量.
  5. 类定义语 : 所有的类都需要在这里定义.当模块被导入时,class语句被执行,类也就会被定义. 类的文档变量是class.doc.
  6. 函数定义语句 : 此处定义的函数可以通过module.function()在外部被访问到,当模块被导入时def 语句会被执行,函数也就都会定义好,函数的文档变量是function.doc
  7. 主程序 : 无论这个模块是被别的模块导入还是作为脚本直接执行,都会执行这部分代码. 通常这里不会有太多功能性代码,而是根据执行的模式调用不同的函数.
  8. 推荐代码风格 : 主程序调用man()函数 . 主程序代码通常都和你前面看到的代码相似,检查name变量的值然后再执行相应的调用 . 主程序中的代码通常包括变量赋值,类定义和函数定义,随后检查name来决定是否调用另一个函数(通常调用main())函数来完成该模块的功能. 主程序通常都是做这些事. 不管用什么名字,想强调一点那就是: 这儿是放置测试代码的好地方. 大部分Python模块都是用于导入调用的,直接运行模块应该调用该模块的回归测试代码 . 请记住, 绝大部分的模块创建的目的是为了别人调用而不是作为独立执行的脚本.
  9. 核心笔记 : name指示模块应如何被加载 : 由于主程序代码无论模块是被导入还是被直接执行都会运行, 我们必须知道模块如何决定运行方向. 一个应用程序可能需要导入另一个应用程序的一个模块,以便重用一些有用的代码(否则就只能用拷贝粘贴那种非面向对象的愚蠢手段) . 这种情况下,你只想访问哪些位于其它应用程序中的代码,而不是想运行那个应用程序. 因此一个问题出现了 . Python是否有一种方法能在运行时检测该模块是被导入还是被直接执行呢?
    1. 如果模块是被导入,name的值为模块名字 .
    2. 如果模块是被直接执行,name的值为 "main"
  10. 在主程序中书写测试代码 : 测试代码仅当该文件被直接执行时运行,也就是说不是被别的模块导入时 . 我们应该利用name变量这个有利条件. 将测试代码放在一个或者叫main() 的函数中.如果钙蜜快是被当成脚本运行,就调用这个函数 .这些测试代码应该随着测试条件及测试结果的变更及时修改,每次代码更新都应该运行这些测试代码,以确认修改没有引发新问题. 这要坚持这样做,你的代码就会足够简装,更不用提验证和测试新特性和更新了. 在主程序中防止测试代码是测试代码块的简单快捷手段. Python标准库中还提供了unittest模块,有时候它被称为pyunit,是一个测试框架.

六.内存管理

  1. 动态类型 : Python中不但变量名无需事先声明,而且也无需类型声明. Python语言中,对象的类型和内存占用都是运行时确定的.尽管代码被编译成字节码,Python仍然是一种解释型语言. 在创建–也就是赋值时,解释器会更具语法和右侧的操作数来决定新对象的类型. 在对象创建后,一个该对象的用用会被赋值给左侧的变量.
  2. 内存分配 : 作为一个负责人的程序员,我们知道在为变量分配内存时,是在借用系统资源 , 在用完之后,应该释放借用的系统资源.Python解释器承担了内存管理的复杂任务,这大大简化了应用程序的编写. 你只需要关心你要解决的问题,至于底层的事情放心交给Python解释器去做就行了 .
  3. 引用计数 : 当对象被创建时,就创建了一个引用计数,当这个对象不再需要时,也就是说,这个对象的引用计数变为0时,它被垃圾回收 .(严格来说这不是100%正确,不过现阶段你可以就这么认为) 4.增加引用计数 : 当对象被创建并(将其引用) 赋值给变量时, 该对象的引用计数就被设置为1 .当同一个对象(的引用)又被赋值给其他变量时, 或作为参数传递给函数,方法或类实例时,或者被赋值为一个窗口帝乡的成员时,该对象的一个新的因运用,或者称作别名,就被创建(则该对象的引用计数自动加1). 总之,对象的引用计数在以下情况会增加 :
    1. 对象被创建
    2. 或另外的别名被创建
    3. 或作为参数传递给函数(新的本地引用)
    4. 或称为容器对象的一个元素
  4. 减少引用计数 : 当对象的引用被销毁时 , 引用计数会减小. 最明显的例子就是引用离开其作用范围时,这种情况最经常出现在函数运行结束时,所有局部变量都被自动销毁,对象的引用计数也就随之减少. 对象的引用计数在以下情况会减少 :
    1. 一个本地引用离开了其作用范围
    2. 对象的别名被显式的销毁
    3. 对象的一个别名被赋值给其他的对象
    4. 对象被从一个窗口对象中移除
    5. 窗口对象本身被销毁
  5. del 语句 : del 语句会删除对象的一个引用 . 会产生两个结果 :
    1. 从现在的名字空间中删除 y.
    2. x 的引用计数减一 引申异步,执行del会删除该对象的最后一个引用,也就是改对象的引用计数会减为 0 , 这回导致该对象从此无法访问或无法抵达. 从此刻起,改对象就称为垃圾回收机制的回收对象. 注意任何追踪或调试程序会给对象增加一个额外的引用,这会推迟该对象被回收的时间.

7.垃圾回收 : 不再被使用的内存会被一种称为垃圾收集机制释放. 垃圾收集器是一块独立代码,它用来寻找引用计数为0 的对象. 它也负责检查哪些虽然引用计数大于0 但也应该销毁的对象. 特定情形会导致循环引用.