adinxu
by adinxu
9 分钟 阅读用时

分类

标签

python文档学习

python文档学习

之前爬取csdn博客的时候,使用了别人写的python工具,但是一直有依赖问题报错。之前一直说要学python,开始看一看吧。
打开python官网,找到文档汇总,这个页面上有很多有用的资料,比如:
python3的文档
另外还有一个叫pypi的东西,相当于docker的docker hub一样的东西,把软件包都汇总在一起,个人感觉python强大的原因之一就是因为python包。
设计和历史常见问题,这个也挺有意思的。
下面是关于python doc学习的记录

python解释器

传入参数

这个和c语言main函数的入参很像,如果想要读取python的命令行参数,需要执行 import sys,导入这个模块,因为解释器读取命令行参数,把脚本名与其他参数转化为字符串列表存到 sys 模块的 argv 变量里。

交互模式的提示符

基础知识

python保留字

保留字即关键字,我们不能把它们用作任何标识符名称。Python 的标准库提供了一个 keyword 模块,可以输出当前版本的所有关键字:

>>> import keyword
>>> keyword.kwlist
['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

注释

可以使用#,'''"""

#!/usr/bin/python3
 
# 第一个注释
# 第二个注释
'''
第三注释
第四注释
'''
"""
第五注释
第六注释
"""
print ("Hello, Python!")

多行语句

Python 可以在同一行中使用多条语句,语句之间使用分号 ; 分割:

#!/usr/bin/python3
 
import sys; x = 'runoob'; sys.stdout.write(x + '\n')

缩进

python数据类型与运算符

变量与基本类型

Python 中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建。
在 Python 中,变量就是变量,它没有类型,我们所说的”类型”是变量所指的内存中对象的类型。
Python允许同时为多个变量赋值。例如:

a = b = c = 1
a, b, c = 1, 2, "runoob"

Python3 中有六个标准的数据类型:

其中:
不可变数据(3 个):Number(数字)、String(字符串)、Tuple(元组);
可变数据(3 个):List(列表)、Dictionary(字典)、Set(集合)。

数字类型

数字类型有 int、float、bool、complex(复数)。
Python3 中,bool 是 int 的子类,True 和 False 可以和数字相加, True1、False0 会返回 True,但可以通过 is 来判断类型。

>>> issubclass(bool, int) 
True
>>> True==1
True
>>> False==0
True
>>> True+1
2
>>> False+1
1
>>> 1 is True
False
>>> 0 is False
False

集合(set)

集合可以类比数学里的集合,他是由不重复元素组成的无序容器。
创建集合用花括号或 set() 函数。注意,创建空集合只能用 set(),不能用 {},{} 创建的是空字典.
集合基本功能是进行成员关系测试和删除重复元素。
创建集合:

>>> basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
>>> print(basket)                      # show that duplicates have been removed
{'orange', 'banana', 'pear', 'apple'}
>>> 'orange' in basket                 # fast membership testing
True
>>> 'crabgrass' in basket
False

>>> # Demonstrate set operations on unique letters from two words
...
>>> a = set('abracadabra')
>>> a                                  # unique letters in a
{'a', 'r', 'b', 'c', 'd'}

序列

字符串类型(str)

>>> a='''first line
... next line
... '''
>>> print(a) 
first line
next line


>>> word[0:2]  # characters from position 0 (included) to 2 (excluded)
'Py'
>>> word[2:5]  # characters from position 2 (included) to 5 (excluded)
'tho'
>>> word[:2]   # character from the beginning to position 2 (excluded)
'Py'
>>> word[4:]   # characters from position 4 (included) to the end
'on'
>>> word[-2:]  # characters from the second-last (included) to the end
'on'

>>> name = 'Runoob'
>>> f'Hello {name}'  # 替换变量
'Hello Runoob'
>>> f'{1+2}'         # 使用表达式
'3'

>>> w = {'name': 'Runoob', 'url': 'www.runoob.com'}
>>> f'{w["name"]}: {w["url"]}'
'Runoob: www.runoob.com'

列表(list)

列表可以比较像c语言的数组,在列表末尾添加和删除元素非常快,但在列表开头插入或移除元素却很慢。

元组(tuple)

定义

元组即为tuples,他看起来跟列表很像,但他是不可更改的,即immutable。元组中的元素类型也可以不相同.但是他可以包含可更改的变量,比如列表:

>>> # but they can contain mutable objects:
... v = ([1, 2, 3], [3, 2, 1])
>>> v
([1, 2, 3], [3, 2, 1])

元组打包
>>> t = 12345, 54321, 'hello!'

序列解包
>>> x, y, z = t

序列解包时,左侧变量与右侧序列元素的数量应相等。注意,多重赋值其实只是元组打包和序列解包的组合。

字典(dict)

字典以 关键字 为索引,关键字通常是字符串或数字,也可以是其他任意不可变类型。只包含字符串、数字、元组的元组,也可以用作关键字。但如果元组直接或间接地包含了可变对象,就不能用作关键字。列表不能当关键字,因为列表可以用索引、切片、append() 、extend() 等方法修改。
花括号 {} 用于创建空字典。另一种初始化字典的方式是,在花括号里输入逗号分隔的键值对,这也是字典的输出方式。

>>> tel = {'jack': 4098, 'sape': 4139}
>>> tel['guido'] = 4127
>>> tel
{'jack': 4098, 'sape': 4139, 'guido': 4127}

dict() 构造函数可以直接用键值对序列创建字典:

>>>
>>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
{'sape': 4139, 'guido': 4127, 'jack': 4098}

字典推导式可以用任意键值表达式创建字典:

>>>
>>> {x: x**2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}

关键字是比较简单的字符串时,直接用关键字参数指定键值对更便捷:

>>>
>>> dict(sape=4139, guido=4127, jack=4098)
{'sape': 4139, 'guido': 4127, 'jack': 4098}

Python数据类型转换

数据类型的转换,你只需要将数据类型作为函数名即可

总结

6种基本类型里,其中数字和字符串是单纯的常量。列表和元组,分别为[]与(),可修改与不可修改,都是1对1的关系。集合与字典,都是{},也是可修改与不可修改,是无序的,元素之间无关系。

运算符

控制流

选择

循环

对象方法在循环中的应用

无动作

pass语句相当于汇编里的nop,并不执行任何实际动作。

函数

函数定义

定义 函数使用关键字def,后跟函数名与括号内的形参列表。函数语句从下一行开始,并且必须缩进。
函数内的第一条语句是字符串时,该字符串就是文档字符串,也称为 docstring,详见 文档字符串。利用文档字符串可以自动生成在线文档或打印版文档,还可以让开发者在浏览代码时直接查阅文档;Python 开发者最好养成在代码中加入文档字符串的好习惯。

>>> def fib(n):    # write Fibonacci series up to n
...     """Print a Fibonacci series up to n."""
...     a, b = 0, 1
...     while a < n:
...         print(a, end=' ')
...         a, b = b, a+b
...     print()


函数定义可变参

下面列举了可变数量的参数的函数的定义,其中位置参数代表依靠位置来给形参赋值的参数,关键字参数代表显式的使用关键字来形参赋值的参数。

解包实参列表

函数调用要求独立的位置参数,但实参在列表或元组里时,要执行相反的操作。例如,内置的 range() 函数要求独立的 start 和 stop 实参。如果这些参数不是独立的,则要在调用函数时,用 * 操作符把实参从列表或元组解包出来,用**解出字典。

lambda表达式

lambda表达式是常规函数定义的语法糖,用于创建小巧的匿名函数,可用于任何需要函数对象的地方。

>>> def make_incrementor(n):
...     return lambda x: x + n
...
>>> f = make_incrementor(42)
>>> f(0)
42
>>> f(1)
43

上例用 lambda 表达式返回函数。还可以把匿名函数用作传递的实参:

>>>
>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
>>> pairs.sort(key=lambda pair: pair[1])
>>> pairs
[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]

既然是面向对象语言,就不能不提类。python的类比较特别的是,和python模块一样,类也支持 Python 动态特性:在运行时创建,创建后还可以修改。

Python 作用域和命名空间

命名空间是在不同时刻创建的,且拥有不同的生命周期。内置名称的命名空间是在 Python 解释器启动时创建的,永远不会被删除。模块的全局命名空间在读取模块定义时创建;通常,模块的命名空间也会持续到解释器退出。从脚本文件读取或交互式读取的,由解释器顶层调用执行的语句是 main 模块调用的一部分,也拥有自己的全局命名空间。内置名称实际上也在模块里,即 builtins 。
函数的本地命名空间在调用该函数时创建,并在函数返回或抛出不在函数内部处理的错误时被删除。 (实际上,用“遗忘”来描述实际发生的情况会更好一些。) 当然,每次递归调用都会有自己的本地命名空间。
作用域 是命名空间可直接访问的 Python 程序的文本区域。 “可直接访问” 的意思是,对名称的非限定引用会在命名空间中查找名称。
执行期间的任何时刻,都会有 3 或 4 个命名空间可被直接访问的嵌套作用域:

def scope_test():
    def do_local():
        spam = "local spam"

    def do_nonlocal():
        nonlocal spam
        spam = "nonlocal spam"

    def do_global():
        global spam
        spam = "global spam"

    spam = "test spam"
    do_local()
    print("After local assignment:", spam)
    do_nonlocal()
    print("After nonlocal assignment:", spam)
    do_global()
    print("After global assignment:", spam)

scope_test()
print("In global scope:", spam)

输出为:

After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam

注意,局部 赋值(这是默认状态)不会改变 scope_test 对 spam 的绑定。 nonlocal 赋值会改变 scope_test 对 spam 的绑定,而 global 赋值会改变模块层级的绑定。

定义类

与函数定义 (def 语句) 一样,类定义必须先执行才能生效。类用class关键字定义。

class MyClass:
    """A simple example class"""
    i = 12345

    def f(self):
        return 'hello world'

类的属性

类的方法对象

类变量

类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。

实例变量

在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。

继承

派生类定义的语法如下所示:

class DerivedClassName(BaseClassName):
    <statement-1>
    .
    .
    .
    <statement-N>

以下也是可行的:

class DerivedClassName(modname.BaseClassName):

派生类定义的执行过程与基类相同。 当构造类对象时,基类会被记住。 此信息将被用来解析属性引用:如果请求的属性在类中找不到,搜索将转往基类中进行查找。 如果基类本身也派生自其他某个类,则此规则将被递归地应用。

多重继承

Python 也支持一种多重继承。 带有多个基类的类定义语句如下所示:

class DerivedClassName(Base1, Base2, Base3):
    <statement-1>
    .
    .
    .
    <statement-N>

对于多数应用来说,在最简单的情况下,你可以认为搜索从父类所继承属性的操作是深度优先、从左至右的,当层次结构中存在重叠时不会在同一个类中搜索两次。 因此,如果某一属性在 DerivedClassName 中未找到,则会到 Base1 中搜索它,然后(递归地)到 Base1 的基类中搜索,如果在那里未找到,再到 Base2 中搜索,依此类推。
真实情况比这个更复杂一些;方法解析顺序会动态改变以支持对 super() 的协同调用。 这种方式在某些其他多重继承型语言中被称为后续方法调用,它比单继承型语言中的 super 调用更强大。

方法重写

super() 函数是用于调用父类(超类)的一个方法。

#!/usr/bin/python3
 
class Parent:        # 定义父类
   def myMethod(self):
      print ('调用父类方法')
 
class Child(Parent): # 定义子类
   def myMethod(self):
      print ('调用子类方法')
 
c = Child()          # 子类实例
c.myMethod()         # 子类调用重写方法
super(Child,c).myMethod() #用子类对象调用父类已被覆盖的方法

输出为:

调用子类方法
调用父类方法

运算符重载

#!/usr/bin/python3
 
class Vector:
   def __init__(self, a, b):
      self.a = a
      self.b = b
 
   def __str__(self):
      return 'Vector (%d, %d)' % (self.a, self.b)
   
   def __add__(self,other):
      return Vector(self.a + other.a, self.b + other.b)
 
v1 = Vector(2,10)
v2 = Vector(5,-2)
print (v1 + v2)

以上代码执行结果如下所示:

Vector(7,8)

私有变量

那种仅限从一个对象内部访问的“私有”实例变量在 Python 中并不存在。 但是,大多数 Python 代码都遵循这样一个约定:带有一个下划线的名称 (例如 _spam) 应该被当作是 API 的非公有部分 (无论它是函数、方法或是数据成员)。 这应当被视为一个实现细节,可能不经通知即加以改变。
由于存在对于类私有成员的有效使用场景(例如避免名称与子类所定义的名称相冲突),因此存在对此种机制的有限支持,称为 名称改写。 任何形式为 __spam 的标识符(至少带有两个前缀下划线,至多一个后缀下划线)的文本将被替换为 _classname__spam,其中 classname 为去除了前缀下划线的当前类名称。 这种改写不考虑标识符的句法位置,只要它出现在类定义内部就会进行。

定义空类

有时会需要使用类似于 Pascal 的“record”或 C 的“struct”这样的数据类型,将一些命名数据项捆绑在一起。 这种情况适合定义一个空类:

class Employee:
    pass

john = Employee()  # Create an empty employee record

# Fill the fields of the record
john.name = 'John Doe'
john.dept = 'computer lab'
john.salary = 1000

迭代器

容器对象上使用 for 语句是靠在容器对象上调用 iter()实现的。 该函数返回一个定义了 next() 方法的迭代器对象,此方法将逐一访问容器中的元素。
你可以使用 next() 内置函数来调用 next() 方法;这个例子显示了它的运作方式:

>>> s = 'abc'
>>> it = iter(s)
>>> it
<str_iterator object at 0x10c90e650>
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
    next(it)
StopIteration

给自己的类添加迭代器行为可以定义一个 iter() 方法来返回一个带有 next() 方法的对象。 如果类已定义了 next(),则 iter() 可以简单地返回 self:

class Reverse:
    """Iterator for looping over a sequence backwards."""
    def __init__(self, data):
        self.data = data
        self.index = len(data)

    def __iter__(self):
        return self

    def __next__(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]
>>>
>>> rev = Reverse('spam')
>>> iter(rev)
<__main__.Reverse object at 0x00A1DB50>
>>> for char in rev:
...     print(char)
...
m
a
p
s

生成器

生成器 是一个用于创建迭代器的简单而强大的工具。 它们的写法类似于标准的函数,但当它们要返回数据时会使用 yield 语句。 每次在生成器上调用 next() 时,它会从上次离开的位置恢复执行(它会记住上次执行语句时的所有数据值)。

def reverse(data):
    for index in range(len(data)-1, -1, -1):
        yield data[index]
>>>
>>> for char in reverse('golf'):
...     print(char)
...
f
l
o
g 

可以用生成器来完成的操作同样可以用前一节所描述的基于类的迭代器来完成。 但生成器的写法更为紧凑,因为它会自动创建 iter() 和 next() 方法。

>>> it = reverse("golf")
>>> next(it)
'f'
>>> next(it)
'l'
>>> next(it)
'o'
>>> next(it)
'g'
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

另一个关键特性在于局部变量和执行状态会在每次调用之间自动保存。 这使得该函数相比使用 self.index 和 self.data 这种实例变量的方式更易编写且更为清晰。

除了会自动创建方法和保存程序状态,当生成器终结时,它们还会自动引发 StopIteration。 这些特性结合在一起,使得创建迭代器能与编写常规函数一样容易。
这可能类似于其他语言的闭包。
可以参考Python 的关键字 yield 有哪些用法和用途?

生成器表达式

某些简单的生成器可以写成简洁的表达式代码,所用语法类似列表推导式,但外层为圆括号而非方括号。 这种表达式被设计用于生成器将立即被外层函数所使用的情况。 生成器表达式相比完整的生成器更紧凑但较不灵活,相比等效的列表推导式则更为节省内存。

>>> sum(i*i for i in range(10))                 # sum of squares
285

>>> xvec = [10, 20, 30]
>>> yvec = [7, 5, 3]
>>> sum(x*y for x,y in zip(xvec, yvec))         # dot product
260

>>> unique_words = set(word for line in page  for word in line.split())

>>> valedictorian = max((student.gpa, student.name) for student in graduates)

>>> data = 'golf'
>>> list(data[i] for i in range(len(data)-1, -1, -1))
['f', 'l', 'o', 'g']

模块

创建和导入模块

模块就是把各种定义存入一个文件,以便在脚本或解释器的交互式实例中使用 ;模块中的定义可以导入到其他模块或主模块。
模块是包含 Python 定义和语句的文件。其文件名是模块名加后缀名 .py 。在模块内部,通过全局变量 name 可以获取模块名(即字符串)。
比如创建以下python脚本fibo.py:

# Fibonacci numbers module

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while a < n:
        print(a, end=' ')
        a, b = b, a+b
    print()

进入 Python 解释器,用以下命令导入该模块:

>>> import fibo

不直接把 fibo 函数定义的名称导入到当前符号表,只导入模块名 fibo 。

>>> fibo.fib(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.__name__
'fibo'
>>> fib = fibo.fib
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

import 语句有一个变体,可以直接把模块里的名称导入到另一个模块的符号表。例如:

>>> from fibo import fib
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

以脚本方式执行模块

可以用以下方式运行 Python 模块:

python fibo.py <arguments>

这项操作将执行模块里的代码,和导入模块一样,但会把 name 赋值为 “main”。 所以可以把下列代码添加到模块末尾:

if __name__ == "__main__":
    import sys
    fib(int(sys.argv[1]))

导入模块时,不运行这些代码。这种操作常用于为模块提供便捷用户接口,或用于测试(把模块当作执行测试套件的脚本运行)。

模块搜索路径

查找位置:

  1. 内置模块<li>sys.path路径 </li> 初始化后,Python 程序可以更改 sys.path。运行脚本的目录在标准库路径之前,置于搜索路径的开头。即,加载的是该目录里的脚本,而不是标准库的同名模块。
    添加模块搜索路径:
&gt;&gt;&gt; import sys
&gt;&gt;&gt; sys.path.append('/ufs/guido/lib/python')

标准模块

查看模块定义的名称.

内置函数 dir() 用于查找模块定义的名称。返回结果是经过排序的字符串列表:

&gt;&gt;&gt; dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'sys']

没有参数时,dir() 列出当前定义的名称:

&gt;&gt;&gt; a = [1, 2, 3, 4, 5]
&gt;&gt;&gt; import fibo
&gt;&gt;&gt; fib = fibo.fib
&gt;&gt;&gt; dir()
['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys']

从包中导入

包是一种用“点式模块名”构造 Python 模块命名空间的方法。
假设要为统一处理声音文件与声音数据设计一个模块集(“包”)。声音文件的格式很多(通常以扩展名来识别,例如:.wav, .aiff, .au),因此,为了不同文件格式之间的转换,需要创建和维护一个不断增长的模块集合。为了实现对声音数据的不同处理(例如,混声、添加回声、均衡器功能、创造人工立体声效果),还要编写无穷无尽的模块流。下面这个分级文件树展示了这个包的架构:

sound/                          Top-level package
      __init__.py               Initialize the sound package
      formats/                  Subpackage for file format conversions
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  Subpackage for sound effects
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  Subpackage for filters
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...

导入包时,Python 搜索 sys.path 里的目录,查找包的子目录。
Python 只把含 init.py 文件的目录当成包。这样可以防止以 string 等通用名称命名的目录,无意中屏蔽出现在后方模块搜索路径中的有效模块。 最简情况下,init.py 只是一个空文件,但该文件也可以执行包的初始化代码,或设置 all 变量。
还可以从包中导入单个模块,例如:

import sound.effects.echo
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4) #引用时必须使用子模块的全名
from sound.effects.echo import echofilter
echofilter(input, output, delay=0.7, atten=4) #可以直接使用函数 echofilter()

注意,使用 from package import item 时,item 可以是包的子模块(或子包),也可以是包中定义的函数、类或变量等其他名称。import 语句首先测试包中是否定义了 item;如果未在包中定义,则假定 item 是模块,并尝试加载。如果找不到 item,则触发 ImportError 异常。
相反,使用 import item.subitem.subsubitem 句法时,除最后一项外,每个 item 都必须是包;最后一项可以是模块或包,但不能是上一项中定义的类、函数或变量。

子包的相对导入和绝对导入

包中含有多个子包时(与示例中的 sound 包一样),可以使用绝对导入引用兄弟包中的子模块。例如,要在模块 sound.filters.vocoder 中使用 sound.effects 包的 echo 模块时,可以用 from sound.effects import echo 导入。
还可以用 import 语句的 from module import name 形式执行相对导入。这些导入语句使用前导句点表示相对导入中的当前包和父包。例如,相对于 surround 模块,可以使用:

from . import echo
from .. import formats
from ..filters import equalizer

注意,相对导入基于当前模块名。因为主模块名是 “main” ,所以 Python 程序的主模块必须始终使用绝对导入。

输入与输出

输出格式

&gt;&gt;&gt; yes_votes = 42_572_654
&gt;&gt;&gt; no_votes = 43_132_495
&gt;&gt;&gt; percentage = yes_votes / (yes_votes + no_votes)
&gt;&gt;&gt; '{:-9} YES votes  {:2.2%}'.format(yes_votes, percentage)
' 42572654 YES votes  49.67%'

使用 json 保存结构化数据

json 标准模块采用 Python 数据层次结构,并将之转换为字符串表示形式;这个过程称为 serializing (序列化)。从字符串表示中重建数据称为 deserializing (解序化)。

&gt;&gt;&gt; import json
&gt;&gt;&gt; x = [1, 'simple', 'list']
&gt;&gt;&gt; json.dumps(x)
'[1, "simple", "list"]'

标准库

操作系统接口

文件通配符

命令行参数

错误输出重定向和程序终止

字符串模式匹配

数学

互联网访问

日期和时间

数据压缩

性能测量

质量控制

功能齐备

格式化输出

模板

使用二进制数据记录格式

多线程

日志记录

弱引用

用于操作列表的工具

十进制浮点运算

错误和异常

错误信息的最后一行说明程序遇到了什么类型的错误。

句法错误

异常

异常的处理

使用try, except捕获并处理异常。使用raise 强制触发指定的异常。如果存在 finally 子句,则 finally 子句是 try 语句结束前执行的最后一项任务。不论 try 语句是否触发异常,都会执行 finally 子句。

预定义的清理操作

某些对象定义了不需要该对象时要执行的标准清理操作。无论使用该对象的操作是否成功,都会执行清理操作。比如,下例要打开一个文件,并输出文件内容:

for line in open("myfile.txt"):
    print(line, end="")

这个代码的问题在于,执行完代码后,文件在一段不确定的时间内处于打开状态。在简单脚本中这没有问题,但对于较大的应用程序来说可能会出问题。with 语句支持以及时、正确的清理的方式使用文件对象:

with open("myfile.txt") as f:
    for line in f:
        print(line, end="")

语句执行完毕后,即使在处理行时遇到问题,都会关闭文件 f。和文件一样,支持预定义清理操作的对象会在文档中指出这一点。

调试

pdb 模块定义了一个交互式源代码调试器,用于 Python 程序。它支持在源码行间设置(有条件的)断点和单步执行,检视堆栈帧,列出源码列表,以及在任何堆栈帧的上下文中运行任意 Python 代码。它还支持事后调试,可以在程序控制下调用。
调试器是可扩展的——调试器实际被定义为 Pdb 类。该类目前没有文档,但通过阅读源码很容易理解它。扩展接口使用了 bdb 和 cmd 模块。
调试器的提示符是 (Pdb)。在调试器的控制下运行程序的典型用法是:

&gt;&gt;&gt; import pdb
&gt;&gt;&gt; import mymodule
&gt;&gt;&gt; pdb.run('mymodule.test()')
&gt; &lt;string&gt;(0)?()
(Pdb) continue
&gt; &lt;string&gt;(1)?()
(Pdb) continue
NameError: 'spam'
&gt; &lt;string&gt;(1)?()
(Pdb)

也可以将 pdb.py 作为脚本调用,来调试其他脚本。例如:

python3 -m pdb myscript.py

breakpoint函数

breakpoint(*args, **kws)

此函数会在调用时将你陷入调试器中。具体来说,它调用 sys.breakpointhook() ,直接传递 args 和 kws 。默认情况下, sys.breakpointhook() 调用 pdb.set_trace() 且没有参数。在这种情况下,它纯粹是一个便利函数,因此您不必显式导入 pdb 且键入尽可能少的代码即可进入调试器。但是, sys.breakpointhook() 可以设置为其他一些函数并被 breakpoint() 自动调用,以允许进入你想用的调试器。

其他特性

多重赋值

例如a, b = b, a+b
注意,多重赋值其实只是元组打包和序列解包的组合。

推导式

列表推导式

列表推导式的方括号内包含以下内容:一个表达式,后面为一个 for 子句,然后,是零个或多个 for 或 if 子句。结果是由表达式依据 for 和 if 子句求值计算而得出一个新列表。
格式:

[表达式 for 变量 in 列表] 
[out_exp_res for out_exp in input_list]

#或者 

[表达式 for 变量 in 列表 if 条件]
[out_exp_res for out_exp in input_list if condition]

举例来说,以下列表推导式将两个列表中不相等的元素组合起来:

&gt;&gt;&gt; [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]


嵌套的列表推导式
列表推导式中的初始表达式可以是任何表达式,甚至可以是另一个列表推导式。

&gt;&gt;&gt; matrix = [
...     [1, 2, 3, 4],
...     [5, 6, 7, 8],
...     [9, 10, 11, 12],
... ]

下面的列表推导式可以转置行列:

&gt;&gt;&gt;
&gt;&gt;&gt; [[row[i] for row in matrix] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

需要注意里面的嵌套关系

字典推导式

格式:

{ key_expr: value_expr for value in collection }

或

{ key_expr: value_expr for value in collection if condition }

集合推导式

格式:

{ expression for item in Sequence }
或
{ expression for item in Sequence if conditional }

元组推导式

元组推导式可以利用 range 区间、元组、列表、字典和集合等数据类型,快速生成一个满足指定需求的元组。
元组推导式基本格式:格式:

(expression for item in Sequence )
或
(expression for item in Sequence if conditional )

元组推导式和列表推导式的用法也完全相同,只是元组推导式是用 () 圆括号将各部分括起来,而列表推导式用的是中括号 [],另外元组推导式返回的结果是一个生成器对象。

常用函数

print() 打印,print 默认输出是换行的,如果要实现不换行需要在变量末尾加上 end=”“:
input()
list()
type()查看对象的类型.每个值都是一个对象,因此具有 类 (也称为 类型),并存储为 object.class

&gt;&gt;&gt; x.__class__
&lt;class '__main__.MyClass'&gt;

Python还有有两个内置函数可被用于继承机制:

待继续学习的特性

生成器
生成器表达式