一起学python(一)

一起学python


大家好,俗话说温故而知新,但是如果学习的过程和其中遇到的问题不做记录,相信大家很快就会忘记。
而我们在工作中遇到的很多问题都是细节的问题,但是这些细节问题却可能会使我们浪费很多时间,所以系统地学习,对细节加以掌握并时常翻阅复习。是我们增加内功的好办法。

我们分以下几个部分来进行整体的整理和学习:

  • python简介
  • python整体控制流程
  • python的数据结构
  • python模块
  • python的输入和输出
  • python常见错误和异常
  • python中的类
  • python标准库

最好的助手就是官方文档

由于Python2和3版本差别较大,我们所有的学习内容都以Python3为基础。参考 — [ Python3.6.1 ]


Python简单介绍

引援官网说法:如果你想要在大量的文本文件中执行查找/替换,或者以复杂的方式对大量的图片进行重命名和整理。也许你想要编写一个小型的自定义数据库、一个特殊的 GUI 应用程序或一个简单的小游戏。

如果你是一名专业的软件开发者,可能你必须使用几种 C/C++/JAVA 类库,并且发现通常编写/编译/测试/重新编译的周期是如此漫长。也许你正在为这些类库编写测试用例,但是发现这是一个让人烦躁的工作。又或者你已经完成了一个可以使用扩展语言的程序,但你并不想为此重新设计并实现一套全新的语言。

那么 Python 正是你所需要的语言。(悄悄告诉你,想了解机器学习么?那你首先得学一学Python)

至于Python其他特性,在学习中我们慢慢了解,如果你怕学不好,你不妨暂且把它看做成精简版的 C、C++ 或 Java。


Python整体控制流程

通过代码学习永远是最好的学习
我们来看看整体控制流程中有哪些东西 ↓

-if 语句
-for 语句
-range() 函数
-break 和 continue 语句,以及循环中的 else 子句
-pass 语句
-定义函数
-深入Python函数定义
-编码习惯

============================================

-if 语句:
>>> x = int(input("Please enter an integer: "))
Please enter an integer: 42
>>> if x < 0:
...      x = 0
...      print('Negative changed to zero')
... elif x == 0:
...      print('Zero')
... elif x == 1:
...      print('Single')
... else:
...      print('More')
...
More

关键字 ‘elif‘ 是 ’else if’ 的缩写,这个是为了避免过深的缩进。if … elif … elif … 序列用于替代其它语言中的 switch 或 case 语句。

============================================

-for 语句:
>>> # Measure some strings:
... words = ['cat', 'window', 'defenestrate']
>>> for w in words:
...     print(w, len(w))
...
cat 3
window 6
defenestrate 12

Python 的 for 语句依据任意序列(链表或字符串)中的子项,按它们在序列中的顺序来进行迭代,我们可以来看下下面的例子:

>>> # Measure some strings:
... words = ['cat', 'window', 'defenestrate']
>>> for d in words:
...     print(d, len(d))
...
cat 3
window 6
defenestrate 12

答案是一样的

如果你想要修改你迭代的序列(例如,复制选择项),你可以迭代它的复本。使用切割标识就可以很方便的做到这一点:

>>> # Measure some strings:
... words = ['cat', 'window', 'defenestrate']
>>> for w in words[:]:
...     if len(w) > 6:
...        words.insert(0, w)
...
>>> words
['defenestrate', 'cat', 'window', 'defenestrate']

============================================

-range() 函数:

函数 range() 是内置的,也就是说可以直接调用,它可以用来生成一个等差级数链表:

>>> for i in range(5):
...     print(i)
...
0
1
2
3
4

需要迭代链表索引的话,如下所示结合使 用 range() 和 len():

>>> a = ['Mary', 'had', 'a', 'little', 'lamb']
>>> for i in range(len(a)):
...     print(i, a[i])
...
0 Mary
1 had
2 a
3 little
4 lamb

需要说一下的是 range() 函数返回的对象并不是一个列表。当你迭代它时,它是一个能够像期望的序列返回连续项的对象;但为了节省空间,它并不真正构造列表。
我们称此类对象是 可迭代的,即适合作为那些期望从某些东西中获得连续项直到结束的函数或结构的一个目标(参数)。我们已经见过的 for 语句就是这样一个迭代器。list() 函数是另外一个( 迭代器 ),我们通过它可以从可迭代(对象)中创建列表:

>>> list(range(5))
[0, 1, 2, 3, 4]

============================================

-break 和 continue 语句, 以及循环中的 else 子句:

break 语句和 C 中的类似,用于跳出最近的一级 for 或 while 循环。

循环可以有一个 else 子句;它在循环迭代完整个列表(对于 for )或执行条件为 false (对于 while )时执行,但循环被 break 中止的情况下不会执行。以下搜索素数的示例程序演示了这个子句:

>>> for n in range(2, 10):
...     for x in range(2, n):
...         if n % x == 0:
...             print(n, '=', x, '*', n//x)
...             break
...     else:
...         # loop fell through without finding a factor
...         print(n, '是素数')
...
2 是素数
3 是素数
4 = 2 * 2
5 是素数
6 = 2 * 3
7 是素数
8 = 2 * 4
9 = 3 * 3

(有一点要注意:else 语句是属于 for 循环之中, 不是 if 语句。)
与循环一起使用时,else 子句与 try 语句的 else 子句比与 if 语句的具有更多的共同点:try 语句的 else 子句在未出现异常时运行,循环的 else 子句在未出现 break 时运行。更多关于 try 语句和异常的内容,请参见 异常处理。

continue 语句是从 C 中借鉴来的,它表示循环继续执行下一次迭代:

>>> for num in range(2, 10):
...     if num % 2 == 0:
...         print("Found an even number", num)
...         continue
...     print("Found a number", num)
Found an even number 2
Found a number 3
Found an even number 4
Found a number 5
Found an even number 6
Found a number 7
Found an even number 8
Found a number 9

我们来看一下实际运行效果

这里写图片描述

在这里可以看到 else 如果和 if 对齐发生的改变,以及类似range(2,10)的作用,让range(10)从2起步

============================================
pass语句的作用就在于啥也不做,它用于那些语法上必须要有什么语句,但程序什么也不做的场合,例如:

-pass 语句:
>>> while True:
...     pass  # Busy-wait for keyboard interrupt (Ctrl+C)
...

可以用来创建一个最小的类(空类)

>>> class MyEmptyClass:
...     pass
...

另一方面,pass 可以在创建新代码时用来做函数或控制体的占位符。可以让你在更抽象的级别上思考。pass 可以默默的被忽视:

>>> def initlog(*args):
...     pass   # Remember to implement this!
...

============================================

-定义函数:

我们以生成指定边界的斐波那契数列的函数为例:

>>> 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()
...
>>> # Now call the function we just defined:
... fib(2000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597

我们来看一下实际运行效果:
这里写图片描述

注意1:关键字 def 引入了一个函数 定义。在其后必须跟有函数名和包括形式参数的圆括号。函数体语句从下一行开始,必须是缩进的。

注意2:函数 调用 会为函数局部变量生成一个新的符号表。确切的说,所有函数中的变量赋值都是将值存储在局部符号表。变量引用首先在局部符号表中查找,然后是包含函数的局部符号表,然后是全局符号表,最后是内置名字表。因此,全局变量不能在函数中直接赋值(除非用 global 语句命名),尽管他们可以被引用。

注意3:函数引用的实际参数在函数调用时引入局部符号表,因此,实参总是 传值调用 (这里的 值 总是一个对象 引用 ,而不是该对象的值)。一个函数被另一个函数调用时,一个新的局部符号表在调用过程中被创建。

注意4:一个函数定义会在当前符号表内引入函数名。函数名指代的值(即函数体)有一个被 Python 解释器认定为 用户自定义函数 的类型。 这个值可以赋予其他的名字(即变量名),然后它也可以被当做函数使用。这可以作为通用的重命名机制:

>>> fib
<function fib at 10042ed0>
>>> f = fib
>>> f(100)
0 1 1 2 3 5 8 13 21 34 55 89

有的朋友看到这里可能会比较迷惑,使用过其他语言的朋友,可能会说fib是一个方法,而不是一个函数,因为它不返回任何值,其实面向对象的语言叫方法,面向过程的语言叫函数,没有声明严格的要求你可以当它就是一个执行块,而且事实上,没有 return 语句的函数也会返回一个值: None 。
如果None (这是一个内建名称)值是唯一被书写的值,那么在写的时候通常会被解释器忽略(即不输出任何内容)。
我们使用 print() 函数看看具体情况:

>>> fib(0)
>>> print(fib(0))
None

输出了 None。

我们换一种方式来写一下上面的函数,定义一个返回斐波那契数列数字列表:

>>> def fib2(n): 
...     """Return a list containing the Fibonacci series up to n."""
...     result = []
...     a, b = 0, 1
...     while a < n:
...         result.append(a)    # 把得到的小于n的a都加进去
...         a, b = b, a+b
...     return result
...
>>> f100 = fib2(100)    # call it
>>> f100                # write the result
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

如果直接输入fib(100)效果也是一样的。

· return 语句从函数中返回一个值,不带表达式的 return 返回 None。过程结束后也会返回 None。

语句 result.append(b) 称为链表对象 result 的一个 方法。
示例中演示的 append() 方法由链表对象定义,用于向链表中加入一个新元素。你可以把它看作 result = result + [a],不过效率更高。

============================================
在 Python 中,你可以定义包含若干参数的函数。有三种可用的形式,我们分别来看一下。

-深入 Python 函数定义:
-默认参数值

最常用的一种形式是为一个或多个参数指定默认值。这会创建一个可以使用比定义时允许的参数更少的参数调用的函数,例如:

def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
    while True:
        ok = input(prompt)
        if ok in ('y', 'ye', 'yes'):
            return True
        if ok in ('n', 'no', 'nop', 'nope'):
            return False
        retries = retries - 1
        if retries < 0:
            raise OSError('uncooperative user')
        print(complaint)

这个函数可以通过几种不同的方式调用:
1.只给出必要的参数:
ask_ok(‘Do you really want to quit?’)
2.给出一个可选的参数:
ask_ok(‘OK to overwrite the file?’, 2)
3.或者给出所有的参数:
ask_ok(‘OK to overwrite the file?’, 2, ‘Come on, only yes or no!’)

我们来看下实际运行效果:

这里写图片描述

通过运行代码我们可以发现 input 内容从第一个键入的值开始算起,如果我把 y 写成 [空格]y 是不行的,还有Python里对大小写敏感,所以我把 no 写成 No 也是不行的。

-这个例子中用到了一个关键字 in ,它可以用来测定序列中是否包含某个确定的值。-

默认值在函数 定义 作用域被解析,如下所示:

>>> i = 5
>>> def f(arg=i):
...     print(arg)
... 
>>> i = 6
>>> f()
5

输出结果为5,可以了解到 i 在代码运行到函数的时候就已经被解析了

重要警告: 默认值只被赋值一次。这使得当默认值是可变对象时会有所不同,比如列表、字典或者大多数类的实例。例如,下面的函数在后续调用过程中会累积(前面)传给它的参数:

>>> def f(a, L=[]):
...     L.append(a)
...     return L
... 
>>> print(f(1))
[1]
>>> print(f(2))
[1, 2]
>>> print(f(3))
>[1, 2, 3]

如果你不想让默认值在后续调用中累积,你可以像下面一样定义函数:

>>> def f(a, L=None):
...     if L is None:
...         L = []
...     L.append(a)
...     return L
... 
>>> print(f(1))
[1]
>>> print(f(2))
[2]

这两个例子如果有不理解的可以仔细看几遍,默认值只被赋值一次

-关键字参数

函数可以通过 关键字参数 的形式来调用,形如 keyword = value。例如,以下的函数:

def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
    print("-- This parrot wouldn't", action, end=' ')
    print("if you put", voltage, "volts through it.")
    print("-- Lovely plumage, the", type)
    print("-- It's", state, "!")

我们来看下具体代码实现效果
这里写图片描述

我们可以发现函数接受一个必选参数 (voltage) 以及三个可选参数 (state, action, 和 type)。可以用以下的任一方法调用:

parrot(1000)
parrot(voltage=1000)
parrot(voltage=1000000, action=’VOOOOOM’)
parrot(action=’VOOOOOM’, voltage=1000000)
parrot(‘a million’, ‘bereft of life’, ‘jump’)
parrot(‘a thousand’, state=’pushing up the daisies’)

下几种调用无效:

parrot()
parrot(voltage=5.0, ‘dead’)
parrot(110, voltage=220)
parrot(actor=’John Cleese’)

在函数调用中,关键字的参数必须跟随在位置参数的后面。传递的所有关键字参数必须与函数接受的某个参数相匹配 (例如 actor 不是 parrot 函数的有效参数),它们的顺序并不重要。这也包括非可选参数(例如 parrot(voltage=1000) 也是有效的)。任何参数都不可以多次赋值。下面的示例由于这种限制将失败:

>>> def function(a):
...     pass
...
>>> function(0, a=0)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: function() got multiple values for keyword argument 'a'

引入一个形如 **name 的参数时,它接收一个字典(参见 Mapping Types — dict ),该字典包含了所有未出现在形式参数列表中的关键字参数。这里可能还会组合使用一个形如 *name (下一小节详细介绍) 的形式参数,它接收一个元组(下一节中会详细介绍),包含了所有没有出现在形式参数列表中的参数值( *name 必须在 **name 之前出现)。 例如,我们这样定义一个函数:

def cheeseshop(kind, *arguments, **keywords):
    print("-- Do you have any", kind, "?")
    print("-- I'm sorry, we're all out of", kind)
    for arg in arguments:
        print(arg)
    print("-" * 40)
    keys = sorted(keywords.keys())
    for kw in keys:
        print(kw, ":", keywords[kw])

它可以像这样调用:

cheeseshop("Limburger", "It's very runny, sir.",
           "It's really very, VERY runny, sir.",
           shopkeeper="Michael Palin",
           client="John Cleese",
           sketch="Cheese Shop Sketch")

它会按如下内容打印:

-- Do you have any Limburger ?
-- I'm sorry, we're all out of Limburger
It's very runny, sir.
It's really very, VERY runny, sir.
----------------------------------------
client : John Cleese
shopkeeper : Michael Palin
sketch : Cheese Shop Sketch

我们发现下面的三句话顺序改变了,那是因为打印关键字参数之前,我们通过对关键字字典 keys() 方法的结果进行了排序,生成了关键字参数名的列表;如果不这样做,打印出来的参数的顺序是未定义的。

-可变参数列表

函数可以通过 关键字参数 的形式来调用,形如 keyword = value。例如,以下的函数:

这个不太常用,我们可以让函数调用可变个数的参数。这些参数被包装进一个元组(参见 元组和序列 )。在这些可变个数的参数之前,可以有零到多个普通的参数,例如:

def write_multiple_items(file, separator, *args):
    file.write(separator.join(args))

我们发现可变参数是参数列表中的最后一个,通常我们都把它放在最后,因为它们将把所有的剩余输入参数传递给函数。任何出现在 *args 后的参数是关键字参数,这意味着,他们只能被用作关键字,而不是位置参数:

>>> def concat(*args, sep="/"):
...    return sep.join(args)
...
>>> concat("earth", "mars", "venus")
'earth/mars/venus'
>>> concat("earth", "mars", "venus", sep=".")
'earth.mars.venus'

是不是也挺有意思?

-参数列表的分拆

有一种和上面相反的情况: 当你要传递的参数已经是一个列表,但要调用的函数却接受分开一个个的参数值。这时候你要把已有的列表拆开来。例如内建函数 range() 需要要独立的 start,stop 参数。你可以在调用函数时加一个 * 操作符来自动把参数列表拆开:

>>> list(range(3, 6))            # 正常切片
[3, 4, 5]
>>> args = [3, 6]
>>> list(range(*args))            # 把参数列表拆开
[3, 4, 5]

我们还可以用同样的方式,使用 ** 操作符分拆关键字参数为字典:

>>> def parrot(voltage, state='a stiff', action='voom'):
...     print("-- This parrot wouldn't", action, end=' ')
...     print("if you put", voltage, "volts through it.", end=' ')
...     print("E's", state, "!")
...
>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
>>> parrot(**d)
-参数列表的分拆

出于实际需要,有几种通常在函数式编程语言例如 Lisp 中出现的功能加入到了 Python。通过 lambda 关键字,可以创建短小的匿名函数。这里有一个函数返回它的两个参数的和: lambda a, b: a+b。 Lambda 形式可以用于任何需要的函数对象。出于语法限制,它们只能有一个单独的表达式。语义上讲,它们只是普通函数定义中的一个语法技巧。类似于嵌套函数定义,lambda 形式可以从外部作用域引用变量.
看下例子:

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

我们这里是返回了一个函数,对于 x 为什么是 43 不是 1 ,前面的内容里已经说过了。

我们还可以使用 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中的缩进是区分代码的重要标识,四个空格和Tab键代表的意义不同

我们来看个示例:

>>> def my_function():
...     """Do nothing, but document it.
...
...     No, really, it doesn't do anything.
...     """
...     pass
...
>>> print(my_function.__doc__)
Do nothing, but document it.

    No, really, it doesn't do anything.
-函数注解

函数注解 是关于用户自定义的函数的完全可选的、随意的元数据信息。值得说一下的是无论 Python 本身或者标准库中都没有使用函数注解;本节只是描述了语法。第三方的项目是自由地为文档,类型检查,以及其它用途选择函数注解。

注解是以字典形式存储在函数的 annotations 属性中,对函数的其它部分没有任何影响。参数注解(Parameter annotations)是定义在参数名称的冒号后面,紧随着一个用来表示注解的值得表达式。返回注释(Return annotations)是定义在一个 -> 后面,紧随着一个表达式,在冒号与 -> 之间。下面的示例包含一个位置参数,一个关键字参数,和没有意义的返回值注释:

>>> def f(ham: 42, eggs: int = 'spam') -> "Nothing to see here":
...     print("Annotations:", f.__annotations__)
...     print("Arguments:", ham, eggs)
...
>>> f('wonderful')
Annotations: {'eggs': <class 'int'>, 'return': 'Nothing to see here', 'ham': 42}
Arguments: wonderful spam

============================================

-编码习惯:

引援官网说法:
对于 Python,PEP 8 引入了大多数项目遵循的风格指导。它给出了一个高度可读,视觉友好的编码风格。每个 Python 开发者都应该读一下,大多数要点都会对你有帮助:

  • 使用 4 空格缩进,而非 TAB,在小缩进(可以嵌套更深)和大缩进(更易读)之间,4空格是一个很好的折中。TAB 引发了一些混乱,最好弃用
  • 折行以确保其不会超过 79 个字符,这有助于小显示器用户阅读,也可以让大显示器能并排显示几个代码文件
  • 使用空行分隔函数和类,以及函数中的大块代码
  • 可能的话,注释独占一行
  • 使用文档字符串
  • 把空格放到操作符两边,以及逗号后面,但是括号里侧不加空格:a = f(1, 2) + g(3, 4)
  • 统一函数和类命名
    推荐类名用 驼峰命名, 函数和方法名用 小写下划线。总是用 self 作为方法的第一个参数(关于类和方法的知识详见 初识类 )
  • 不要使用花哨的编码,如果你的代码的目的是要在国际化环境下工作。Python 的默认情况下,UTF-8,甚至普通的 ASCII 总是工作的最好
  • 同样,也不要使用非 ASCII 字符的标识符,除非是不同语种的会阅读或者维护代码。

是不是感觉很亲切,不管使用任何一门语言,良好的编码习惯和风格总能让你的代码看起来更行心悦目也让人更容易看懂。

关于Python的控制流程我们已经学习完了,怎么样,是不是对Python有了个整体的认识,接下来我们将继续学习Python里的数据结构,/嘿哈

“——-任何技艺的磨练都离不开枯燥的重复和反复的领悟 ——”

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值