澳门新萄京官方网站-www.8455.com-澳门新萄京赌场网址

澳门新萄京官方网站:python的根底三,一等目的

2019-07-28 作者:www.8455.com   |   浏览(186)

本文主要内容

一等对象

普通函数 & 高阶函数

可调用对象 & 自定义可调用类型

  函数内省

  函数注释

 

python高级——目录

文中代码均放在github上:https://github.com/ampeeg/cnblogs/tree/master/python高级

 

前言:python3.x部分学习笔记,有意交流学习者可加wechat:YWNlODAyMzU5MTEzMTQ=。如果笔记内容有错,请指出来。

python 基础,python

【python之旅】python的基础三,python之旅基础

目录:

  1、装饰器

  2、迭代器&生成器

  3、Json & pickle 数据序列化

  4、软件目录结构规范

  一、装饰器

   定义:本质是函数,(装饰其他函数)就是为其他函数添加附加功能

   原则:

    1、不能修改被装饰的函数的源代码

    2、不能修改被装饰的函数的调用方式

 一个简单的装饰器:

 1 #!/usr/bin/env python
 2 # -*- coding: utf-8 -*-
 3 # Author :GU
 4 import time
 5 def timmer(func):   ##后加的一个记录运行时间的装饰器
 6     def warpper(*args,**kwargs):
 7         start_time= time.time()
 8         func()
 9         stop_time=time.time()
10         print("The func run timr is %s"%(stop_time-start_time))
11     return warpper
12 @timmer   ##把装饰器调用到函数test1函数里面去
13 def test1():
14     time.sleep(3)
15     print("In the test1")
16 test1()
17 执行结果:
18 In the test1
19 The func run timr is 3.000171661376953

实现装饰器知识储备:

  1、函数即变量

  2、高阶函数

  3、嵌套函数

  高阶函数 嵌套函数=装饰器

  知识点一:函数即变量==》函数的调用顺序

  其他高级语言类似,Python 不允许在函数未声明之前,对其进行引用或者调用

  ①、错误的示范:

 2 def foo():
 3     print ('in the foo')
 4     bar()
 5 foo()
 6 报错:
 7 in the foo
 8 Traceback (most recent call last):
 9   File "<pyshell#13>", line 1, in <module>
10     foo()
11   File "<pyshell#12>", line 3, in foo
12     bar()
13 NameError: global name 'bar' is not defined
14 =====================================
15 def foo():
16     print ('foo')
17     bar()
18 foo()
19 def bar():
20     print ('bar')
21 报错:NameError: global name 'bar' is not define

   ②、正确的示范

 1 def bar():
 2     print ('in the bar')
 3 def foo():
 4     print ('in the foo')
 5     bar()
 6      
 7 foo()
 8  ===================================
 9 def foo():
10     print ('in the foo')
11     bar()
12 def bar():
13     print ('in the bar')
14 foo()
15 执行结果:
16 in the foo
17 in the bar
18 =======================
19 in the foo
20 in 

   知识点二

  高阶函数:a、把一个函数名当作实参传给另外一个函数 b、返回值中包含函数名

  按a原则定义一个函数:

 1 #不修改被装饰函数源代码的情况下为其添加功能
 2 import time
 3 def bar():
 4     time.sleep(3)
 5     print('in the bar')
 6 
 7 def test1(func):
 8     start_time=time.time()
 9     func()    #run bar
10     stop_time=time.time()
11     print("the func run time is %s" %(stop_time-start_time))
12 
13 test1(bar)
14 执行结果:
15 in the bar
16 the func run time is 3.000171661376953

  按b原则定义一个函数:

 1 #不修改函数的调用方式
 2 import time
 3 def bar():
 4     time.sleep(3)
 5     print('in the bar')
 6 def test2(func):
 7     print(func)
 8     return func
 9 
10 # print(test2(bar))
11 bar=test2(bar)
12 bar()  #run bar
13 执行结果:
14 <function bar at 0x00000000007DE048>
15 in the bar

  知识点三

  嵌套函数:定义:在一个函数体内创建另外一个函数,这种函数就叫内嵌函数(基于python支持静态嵌套域)

1 def foo():
2     print('in the foo')
3     def bar():
4         print('in the bar')
5     bar()
6 foo()
7 执行结果:
8 in the foo
9 in the bar

  局部作用域和全局作用域的访问顺序

 1 x=0
 2 def grandpa():
 3     x=1
 4     def dad():
 5         x=2
 6         def son():
 7             x=3
 8             print(x)
 9         son()
10     dad()
11 grandpa()
12 执行结果:
13 3

  一个完整的装饰器:

  不带参数的:

 1 import time
 2 def timer(func): #timer(test1)  func=test1
 3     def deco():
 4         start_time=time.time()
 5         func()   #run test1()
 6         stop_time = time.time()
 7         print("the func run time  is %s" %(stop_time-start_time))
 8     return deco
 9 @timer  #test1=timer(test1)
10 def test1():
11     time.sleep(1)
12     print('in the test1')
13 #执行结果:
14 in the test1
15 the func run time  is 1.0000572204589844

   带参数的:

 1 import time
 2 def timer(func): #timer(test1)  func=test1
 3     def deco(*args,**kwargs):
 4         start_time=time.time()
 5         func(*args,**kwargs)   #run test1()
 6         stop_time = time.time()
 7         print("the func run time  is %s" %(stop_time-start_time))
 8     return deco
 9 @timer  #test1=timer(test1)
10 def test1():
11     time.sleep(1)
12     print('in the test1')
13 @timer # test2 = timer(test2)  = deco  test2(name) =deco(name)
14 def test2(name,age):
15     time.sleep(1)
16     print("test2:",name,age)
17 test1()
18 test2("alex",22)
19 执行结果:
20 in the test1
21 the func run time  is 1.0000572204589844
22 test2: alex 22
23 the func run time  is 1.000057220458984

  终极版装饰器:

user,passwd = 'alex','abc123'
def auth(auth_type):
    print("auth func:",auth_type)
    def outer_wrapper(func):
        def wrapper(*args, **kwargs):
            print("wrapper func args:", *args, **kwargs)
            if auth_type == "local":
                username = input("Username:").strip()
                password = input("Password:").strip()
                if user == username and passwd == password:
                    print("33[32;1mUser has passed authentication33[0m")
                    res = func(*args, **kwargs)  # from home
                    print("---after authenticaion ")
                    return res
                else:
                    exit("33[31;1mInvalid username or password33[0m")
            elif auth_type == "ldap":
                print("搞毛线ldap,不会。。。。")
        return wrapper
    return outer_wrapper
def index():
    print("welcome to index page")
@auth(auth_type="local") # home = wrapper()
def home():
    print("welcome to home  page")
    return "from home"

@auth(auth_type="ldap")
def bbs():
    print("welcome to bbs  page")

index()
print(home()) #wrapper()
bbs()
###执行结果:
auth func: local
auth func: ldap
welcome to index page
wrapper func args:
Username:alex
Password:abc123
User has passed authentication
welcome to home  page
---after authenticaion 
from home
wrapper func args:
搞毛线ldap,不会。。。。

二、迭代器&生成器

  生成器:

  通过列表生成式,可直接创建一个列表,但是受到内存限制,列表内容是有限的,创建一个100w元素的列表,不仅占用很大的内存,如果我们仅仅需要访问前面几个元素,那么后面大多数元素占用的空间是浪费的,所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环列表的过程中不断推算出后续的函数,这样就没有必要创建完整的list,从而节省了大量的空间=====》》generator

  创建一个简单的generator,只要把一个列表生成式的[]改成(),就创建了一个generator:

1 >>> l = [x * x for x in range(10)]
2 >>> l
3 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
4 >>> g = (x * x for x in range(10))
5 >>> g
6 <generator object <genexpr> at 0x00000000006F3048>

  创建Lg的区别仅在于最外层的[]()L是一个list,而g是一个generator。

  我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?

  如果要一个一个打印出来,通过next()函数获得generator的下一个返回值:

 1 >>> next(g)
 2 0
 3 >>> next(g)
 4 1
 5 >>> next(g)
 6 4
 7 >>> next(g)
 8 9
 9 >>> next(g)
10 16
11 >>> next(g)
12 25
13 >>> next(g)
14 36
15 >>> next(g)
16 49

  生成器之后在调用时才会生成相应的数据,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

  不断调用next(g)的方式不是很好,正确的方法是使用for循环,因为generator也是可迭代对象,如果只有一个就可以用next()方法

 1 >>> for n in g:
 2 ...     print(n)
 3 ...
 4 0
 5 1
 6 4
 7 9
 8 16
 9 25
10 36
11 49
12 64
13 81

   generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

  1, 1, 2, 3, 5, 8, 13, 21, 34, ...

  斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

 1 def fib(max):
 2     n, a, b = 0, 0, 1
 3     while n < max:
 4         print(b)
 5         a, b = b, a   b   ##相当于
 6         n = n   1
 7     return 'done'
 8 fib(5)  ##打印前五个数列
 9 #####执行结果
10 1
11 1
12 2
13 3
14 5
15 ===============
16 a, b = b, a   b   ##相当于
17 t = (b, a   b) # t是一个tuple
18 a = t[0]
19 b = t[1]

  由此可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意元素,这种逻辑其实非常类似generator,要把fib函数变成generator,只需要把print(b)改成yield b就可以了:

 1 def fib(max):
 2     n, a, b = 0, 0, 1
 3     while n < max:
 4         #print(b)
 5         yield b    ###返回当前状态的值
 6         a, b = b, a   b
 7         n = n   1
 8     return 'done'
 9 gen = fib(5)
10 print(gen.__next__())
11 print(gen.__next__())
12 print(gen.__next__())
13 print(gen.__next__())
14 执行结果:
15 1
16 1
17 2
18 3

  上面fib的例子,在循环过程中不断调用yield,只要我们不中断程序就会一直执行,当然循环是需要设置一个条件来退出循环,不然就会产生一个无限数列出来,同样的generator后,我们基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代:

 1 def fib(max):
 2     n, a, b = 0, 0, 1
 3     while n < max:
 4         #print(b)
 5         yield b
 6         a, b = b, a   b
 7         n = n   1
 8     return 'done'
 9 for i in fib(5):
10     print(i)
11 #执行结果:
12 1
13 1
14 2
15 3
16 5

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

 1 def fib(max):
 2     n, a, b = 0, 0, 1
 3     while n < max:
 4         #print(b)
 5         yield b
 6         a, b = b, a   b
 7         n = n   1
 8     return 'done'
 9 g = fib(6)
10 while True:
11     try:
12         x = next(g)
13         print('g:', x)
14     except StopIteration as e:
15         print('Generator return value:', e.value)
16         break
17 ###执行结果;
18 g: 1
19 g: 1
20 g: 2
21 g: 3
22 g: 5
23 g: 8
24 Generator return value: done

  通过yield实现在单线程的情况下实现并发运算

澳门新萄京官方网站 1 1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 # Author :GU 4 import time 5 def consuner(name): 6 print("%s 准备吃包子了"%name) 7 while True: 8 baozi = yield 9 print("包子[%s]来了,被[%s]吃了"%(baozi,name)) 10 # c = consuner("haha") 11 # c.__next__() 12 13 def producer(name): 14 c = consuner("a") 15 c2 = consuner("b") 16 c.__next__() 17 c2.__next__() 18 print("老子开始准备做包子了") 19 for i in range(10): 20 time.sleep(1) 21 print("做了一个包子") 22 c.send(i) 23 c2.send(i) 24 producer("guyun") 25 #执行结果: 26 a 准备吃包子了 27 b 准备吃包子了 28 老子开始准备做包子了 29 做了一个包子 30 包子[0]来了,被[a]吃了 31 包子[0]来了,被[b]吃了 32 做了一个包子 33 包子[1]来了,被[a]吃了 34 包子[1]来了,被[b]吃了 35 做了一个包子 36 包子[2]来了,被[a]吃了 37 包子[2]来了,被[b]吃了 38 做了一个包子 39 包子[3]来了,被[a]吃了 40 包子[3]来了,被[b]吃了 41 。。。。。。。。。。。。。 View Code

  迭代器:

  可以直接作用于for循环的数据类型有以下几种:

  一类是集合数据类型,如list(列表)tuple(元组)dict(字典)set(集合)str(字符串)等;

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

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

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

 1 >>> from collections import Iterable
 2 >>> isinstance([],Iterable)
 3 True
 4 >>> isinstance({},Iterable)
 5 True
 6 >>> isinstance("abc",Iterable)
 7 True
 8 >>> isinstance((x for x in range(10)), Iterable)
 9 True
10 >>> isinstance(100, Iterable)
11 False

 

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

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

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

1 >>> from collections import Iterator
2 >>> isinstance((x for x in range(10)), Iterator)
3 True
4 >>> isinstance([], Iterator)
5 False
6 >>> isinstance({}, Iterator)
7 False
8 >>> isinstance('abc', Iterator)
9 False

  生成器都是迭代器对象,但listdictstr虽然是可迭代的,却不是迭代器

  把listdictstr可迭代对象变成迭代器可以使用iter()函数:

1 >>> isinstance(iter([]), Iterator)
2 True
3 >>> isinstance(iter('abc'), Iterator)
4 True

  你可能会问,为什么listdictstr等数据类型不是Iterator(迭代器)

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

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

小结

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

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

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

  Python的for循环本质上就是通过不断调用next()函数实现的,例如:

1 for x in [1, 2, 3, 4, 5]:
2     pass

  实际完全等价于

 1 # 首先获得Iterator对象:
 2 it = iter([1, 2, 3, 4, 5])
 3 # 循环:
 4 while True:
 5     try:
 6         # 获得下一个值:
 7         x = next(it)
 8     except StopIteration:
 9         # 遇到StopIteration就退出循环
10         break

  三、Json & pickle 数据序列化

  用于序列化的两个模块

  • json,用于字符串 和 python数据类型间进行转换
  • pickle,用于python特有的类型 和 python的数据类型间进行转换

  Json模块提供了四个功能:dumps、dump、loads、load

  pickle模块提供了四个功能:dumps、dump、loads、load

  1、json序列化(dumps)

 1 #!/usr/bin/env python
 2 # -*- coding: utf-8 -*-
 3 # Author :GU
 4 import json
 5 info = {
 6     'name':'alex',
 7     'age':22,
 8 }
 9 f = open("test.text","w")
10 f.write( json.dumps( info) )   ###用dunmps序列化
11 f.close()
12 ##执行结果:
13 {"name": "alex", "age": 22}

  2、在用json反序列化(loads)

1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # Author :GU
4 import json
5 f = open("test.text","r")
6 data = json.loads(f.read())   ###loads反序列化
7 print(data["age"])
8 ###执行结果:
9 22

  这样就实现了把内存存在硬盘上,再读出来

  3、、pickle序列化(dumps)**

 1 #!/usr/bin/env python
 2 # -*- coding: utf-8 -*-
 3 # Author :GU
 4 import pickle
 5 def sayhi(name):
 6     print("hello,",name)
 7 info = {
 8     'name':'alex',
 9     'age':22,
10     "func":sayhi,
11 }
12 f = open("test.text","wb")
13 f.write( pickle.dumps( info) )
14 f.close()
15 执行结果:
16 � }q (X    funcq c__main__
17 sayhi
18 q X    nameq X    alexq X    ageq K u.

  4、pickle反序列化(loads)

 1 #!/usr/bin/env python
 2 # -*- coding: utf-8 -*-
 3 # Author :GU
 4 import pickle
 5 def sayhi(name):
 6     print("hello,",name)
 7 f = open("test.text","rb")
 8 data = pickle.loads(f.read())
 9 print(data["func"]("alex"))
10 执行结果:
11 hello, alex
12 None

  5、dump,load序列化,反序列化

澳门新萄京官方网站 2 1 序列化 2 #!/usr/bin/env python 3 # -*- coding: utf-8 -*- 4 # Author :GU 5 import pickle 6 def sayhi(name): 7 print("hello,",name) 8 info = { 9 'name':'alex', 10 'age':22, 11 'func':sayhi 12 } 13 f = open("test.text","wb") 14 pickle.dump(info,f) #f.write( pickle.dumps( info) ) 15 f.close() 16 ############################### 17 反序列化 18 #!/usr/bin/env python 19 # -*- coding: utf-8 -*- 20 # Author :GU 21 import pickle 22 def sayhi(name): 23 print("hello2,",name) 24 f = open("test.text","rb") 25 data = pickle.load(f) #data = pickle.loads(f.read()) 26 print(data["func"]("Alex")) 27 ##执行结果跟上面完全一样 View Code

python基础

#是注释。通过空格进行缩进,当一行语句以:结尾时,缩进的语句视为一段代码块。按约定俗成的规范,使用4个空格进行缩进。最后代码就类似这样:

# output namea = 100if a > 10:    print("a>10")else:    print("a<=10")

一等对象

'''
    在python中,"一等对象"指的是满足下述条件的程序实体:
    (1)在运行时创建
    (2)能赋值给变量或数据结构中的元素
    (3)能作为参数传给函数
    (4)能作为函数的返回结果

    整数、字符串和字典都是一等对象。在面向对象编程中,函数也是对象,并满足以上条件,所以函数也是一等对象,称为"一等函数"
'''


if __name__ == "__main__":
    # 函数的一等性质
    def foo(n):
        '''returns  n!'''
        return 1 if n < 2 else n * foo(n-1)

    print(foo(5))    # 120

    my_foo = foo
    print(my_foo)    # <function foo at 0x1010e3f28> 能赋值给变量
    print(list(map(my_foo, range(6))))   # [1, 1, 2, 6, 24, 120]   能赋值给函数

    def foo2():
        return foo

    my_foo2 = foo2()
    print(my_foo2(5))     # 120 可作为函数的返回结果

 


 python基础

# 是注释。通过空格进行缩进,当一行语句以 : 结尾时,缩进的语句视为一段代码块。按约定俗成的规范,使用4个空格进行缩进。最后代码就类似这样:

# output name
a = 100
if a > 10:
    print("a>10")
else:
    print("a<=10")

四.软件目录结构规范

1. 数据类型和变量

普通函数 & 高阶函数

'''
    我们一般将函数分为"普通函数"和"高阶函数",接受函数为参数的函数为高阶函数,其余为普通函数

    普通函数大家再熟悉不过,本文不讲,主要讲一下map、filter、reduce三个高阶函数
'''


if __name__ == "__main__":
    # map第一个参数接受一个函数,并将这个函数作用于后面可迭代对象的每一个元素中
    l = map(lambda x : x ** 2, range(11))   # 返回的是生成器类型
    print(list(l))     # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

    w = map(str.upper, 'asfafasfasfaf')
    print(list(w))     # ['A', 'S', 'F', 'A', 'F', 'A', 'S', 'F', 'A', 'S', 'F', 'A', 'F']

    # filter第一个参数也接受函数,并返回所有满足该函数的元素
    l = filter(lambda n: n % 2, range(10))   # 返回n % 2为真的数,就是奇数
    l2 = filter(lambda n: n % 2 ==0, range(10))  # 返回偶数
    print(list(l))                           # [1, 3, 5, 7, 9]
    print(list(l2))                          # [0, 2, 4, 6, 8]

    # reduce 从python3开始,reduce放在functools中
    # reduce将某个操作连续应用到序列元素上,即其会将前一步的结果继续应用到下一个元素上
    from functools import reduce
    s = reduce(lambda x,y: x   y, range(101))
    print(s)       # 5050 对1到100求和

 

澳门新萄京官方网站 3

1. 数据类型和变量

1、为什么要设计好目录结构?

  "设计项目目录结构",就和"代码编码风格"一样,属于个人风格问题。对于这种风格上的规范,规范化能更好的控制程序结构,让程序具有更高的可读性。

  设计一个层次清晰的目录结构,就是为了达到以下两点:

1.1. 数据类型

整数:例如:1, -10, 0等。十六进制表示整数方式为:以0x为前缀,后面为0-9, a-f,例如:0x11af

浮点数:例如:0.12, -0.1。对于很大的浮点数就用科学计数法表示,把10用e表示,例如:1.23 *澳门新萄京官方网站:python的根底三,一等目的。 10的9次方表示为1.23e912.3e8

整数和浮点数在计算器存储方式不同,整数运算永远是精确的,但是浮点数可能会出现四舍五入的误差。

 可调用对象 & 自定义可调用类型

'''
    我们在使用函数或者实例化对象的时候会用到括号(即()),这个括号实际上是调用运算符,python里面有7中可调用对象:

    1、用户定义的函数
        def和lambda创建
    2、内置函数
        使用C语言实现的函数,如len或time.strftime
    3、内置方法
        使用C语言实现的方法,如dict.get
    4、方法
        在类的定义体中定义的函数
    5、类
        调用类时其实首先运行的是__new__方法,然后运行__init__方法。这里很有意思,自定义类中其实没有重写__new__方法,
        而是调用的超类的__new__方法,如果查看源代码的实现逻辑,相信你会有新的发现,这里不做讨论。
    6、类的实例
        如果类定义了__call__方法,那么它的实例可以作为函数调用
    7、生长器函数
        使用yield关键字的函数或方法。
'''


if __name__ == "__main__":
    # 创建一个自定义可调用类
    class Foo():
        def __init__(self):
            self.name = "Foo"
        def __call__(self, *args, **kwargs):
            print("调用__call__")

    Foo()()     # 输出:调用__call__

    # 以上使用 Foo()() 这种写法看上去很有意思。首先,Foo()会创建一个Foo实例,调用__init__构造方法,; 然后使用实例(),此时
    # 调用__call__方法

 

python笔记目录导图

1.1. 数据类型

整数:例如:1, -10, 0等。十六进制表示整数方式为:以 0x 为前缀,后面为0-9, a-f,例如:0x11af

浮点数:例如:0.12, -0.1。对于很大的浮点数就用科学计数法表示,把10用e表示,例如:1.23 * 10的9次方表示为1.23e9 或 12.3e8

整数和浮点数在计算器存储方式不同,整数运算永远是精确的,但是浮点数可能会出现四舍五入的误差。

2、目录组织方式

  关于如何组织一个较好的Python工程目录结构,已经有一些得到了共识的目录结构。在Stackoverflow的这个问题上,能看到大家对Python目录结构的讨论。

  假设项目名为foo,最方便快捷目录结构:

Foo/
|-- bin/ ##可执行文件目录
|   |-- foo
|—conf  配置文件
|-- foo/  ##主程序目录,主要的程序逻辑
|   |-- tests/  ##测试用例
|   |   |-- __init__.py
|   |   |-- test_main.py
|   |
|   |-- __init__.py  ##空文件
|   |-- main.py  ##程序主入口
|
|-- docs/  ##文档
|   |-- conf.py
|   |-- abc.rst
|
|-- setup.py##安装部署脚本
|-- requirements.txt##依赖关系
|-- README##

简要解释一下:

  除此之外,有一些方案给出了更加多的内容。比如LICENSE.txt,ChangeLog.txt文件等,我没有列在这里,因为这些东西主要是项目开源的时候需要用到。如果你想写一个开源软件,目录该如何组织,可以参考这篇文章。

1.2. 字符串

字符串:以 单引号''或 双引号""括起来的文本,例如:'abc',"abc"

是转义符,例如:'I'm ok'转义字符串内部中的',输出结果为I'm ok。此外n表示换行符,t表示制表符。

为了简化,还可以通过r''表示''内部的字符串不转义。通过'''...'''来表示很多行,示例:

澳门新萄京官方网站 4

>>> print('转义: ', '\t\')转义:      >>> print('不转义:', r'\t\')不转义: \t\>>> print('多行: ', '''line1... line2... line3''')多行:  line1line2line3

澳门新萄京官方网站 5

函数内省

'''
    函数内省我们通过例子来看
'''


if __name__ == "__main__":
    # 先创建一个函数
    def foo(n):
        ''':returns n!'''
        return 1 if n<2 else n*foo(n-1)

    print(foo.__doc__)   # :returns n!   __doc__里面存储了注释内容

    # 看看这个函数中有多少属性
    print(dir(foo))
    '''
        ['__annotations__', '__call__', '__class__', '__closure__', '__code__', 
        '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', 
        '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', 
        '__hash__', '__init__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', 
        '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', 
        '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
    '''

    # 下表对一些属性做了说明
名称 类型 说明
__annotations__ dict 参数和返回值的注解
__call__ method-wrapper 实现()运算符
__closure__ tuple 函数闭包
__code__ code 编译成字节码的函数元数据和函数定义体
__defaults__ tuple 形式参数的默认值
__get__ method-wrapper 实现只读描述符协议
__globals__ dict 函数所在模块中的全局变量
__kwdefaults__ dict 仅限关键字形式参数的默认值
__name__ str 函数名称
__qualname__ str 函数的限定名称

 

对数据类型的操作

  1. 可变数据类型:列表,集合,字典
    列表:
li=['a','b']
增:
li.insert(2,'c')  #在序号2位置上插入'c'
li.append('d')  #在列表末尾添加'd'
li.extend(li2)  #在列表li后面添加li2

删:
li.remove('c')
del li[2]
li.pop(3)

改:
li[2]='c'
li[1:-1:1]='ha'

查:
li.index('c') 

排序:
sort(key=lambda x:x[2],reverse=True)

集合:

#去重
#关系测试
s1={1,2,3,4,5},s2=set([4,5,6,7,8])
s3=s1&s2  #求交集
s4=s1|s2  #求并集

字典:

a_dict={'name':'alex','age':12,'sex':'male'}
a_dict.get('name','wrong')  #找键名对应的值,找不到就返回第二参数
a_dict.setdefault('name','lema')  #查找该键,找不到则插入该键值对
a_dict.update(dict2)  #将dict2添加到a_dict中
  1. 不可变数据类型:元组,字符串
    元组:tuple1=(1,2,3,4,5)
    字符串:
str1='abcdef',str2="a|b|c|d"
print(str1.capitalize(),str1.upper(),str1.lower())  #首字母大写,全部大写,全部小写
print(str1.find(str2,2,5))  #在str1中从序号2位置开始找str2,直到序号5的位置
print(str1.center(20,'*'))  #在字符串两边各添加20个'*'
print(str1.startswith('ab') ',' str1.endswith('ef'))  #返回True或False
print('-'.join(['2018','1','1']))
print(str2.split("|",3))  #返回一个列表
print(str1.replace('a','A',1))  #把str1中的第1个a替换成A
print(str1.strip())  #把str1两边的空白字符去掉

1.2. 字符串

字符串:以 单引号'' 或 双引号"" 括起来的文本,例如:'abc'"abc"

是转义符,例如:'I'm ok' 中转义字符串内部中的',输出结果为 I'm ok。此外 n表示换行符,t表示制表符。

为了简化,还可以通过 r''表示''内部的字符串不转义。通过'''...'''来表示很多行,示例:

澳门新萄京官方网站 6

>>> print('转义: ', '\t\')
转义:      
>>> print('不转义:', r'\t\')
不转义: \t\
>>> print('多行: ', '''line1
... line2
... line3''')
多行:  line1
line2
line3 

澳门新萄京官方网站 7

3、关于README的内容

  这个我觉得是每个项目都应该有的一个文件,目的是能简要描述该项目的信息,让读者快速了解这个项目。

 它需要说明以下几个事项:

  在软件开发初期,由于开发过程中以上内容可能不明确或者发生变化,并不是一定要在一开始就将所有信息都补全。但是在项目完结的时候,是需要撰写这样的一个文档的。可以参考Redis源码中Readme的写法,这里面简洁但是清晰的描述了Redis功能和源码结构。

1.3. 布尔值

布尔值只有TrueFalse两种,可以通过and,or,not分别进行与、或、非运算。例如:

>>> True and TrueTrue>>> True or FlaseTrue>>> not 5 > 1False

函数注释

'''
    函数注解很简单,用下面例子简单讲解即可明了
'''


if __name__ == "__main__":
    def foo(num: int, step: 'int 间隔(大于0小于num)'=1) -> int:
        ''':returns 求num的阶乘,可以设置步长'''     # 这里的注释存储在__doc__中
        return num if num <= step else num * foo(num-step,step)

    print(foo(5))  # 120   (5*4*3*2*1)
    print(foo(5, 2))  # 15 (5*3)

    # 函数声明中的各个参数可以在冒号(:)之后增加注释,该注释可以直接写参数类型,也可以写字符串
    # -> 符号后面是对函数返回值进行注解

    # 这些注释内容存储在属性 __annotations__中
    print(foo.__annotations__)  # {'step': 'int 间隔(大于0小于num)', 'num': <class 'int'>, 'return': <class 'int'>}

    # 这样注释后,在使用pycharm时会出现自动提示

 

 

 

函数

  1. 高阶函数
def func(x,y,f):
    print(f)
    print(type(f))
    return f(x) f(y)
result=func(-3,-2,abs)
print(result)
  1. 装饰器
    不修改被装饰函数的源代码
    不修改被装饰函数的调用方式
def auth(func):
    def wrapper(*args,**kwargs):
                username=input("username:").strip()
                password=input("password:").strip()
                if "lema"==username and "qwert123"==password :
                    res=func(*args,**kwargs)
                else :
                    print("wrong")
                return res
    return wrapper

@auth
def index(x,y,f):
    print(f(x) f(y))
    print("welcome to myblog")
    return "ok"
print(index(-3,-4,abs))
  1. 参数
    关键字参数
    位置参数
    可变参数
  2. 特殊函数

1.3. 布尔值

布尔值只有 True 和 False 两种,可以通过 andornot分别进行与、或、非运算。例如:

>>> True and True
True
>>> True or Flase
True
>>> not 5 > 1
False

4、关于requirements.txt和setup.py

1.4. 空值

空值使用None表示,类似null的含义。

python高级系列文章目录

python高级——目录

 

面向对象

class People(object):
    name="yin"  #类变量
    def __init__(self,name,age=6):  #构造函数
        self.name=name  #实例变量self.name
    def __del__(self):  #析构函数,当实例对象被垃圾回收时执行该函数
        print("end")
    def sleep(self):
        print("%s:hello,world"%self.name)
d1=People("d1",age=5)
del d1,People
  1. 继承
    重写父类方法
    重构父类方法
class Man(People):
    #第一种重构方式
    def sleep(self):
        People.sleep(self)
        print("chonggou")
    #第二种重构方式,建议使用第二种
    def sleep(self):
          super(Man,self).sleep()
          print("chonggou")

多继承父类方法查询策略:广度优先

class A(object):
    def func(self):
        print("A")
class B(A):
    # def func(self):
    #     print("B")
    pass
class C(A):
    def func(self):
        print("C")
    def f(self):
        print("1000")
class D(B,C):
    def func(self):
        super(D,self).func()
        super(D,self).f()
        print("D")
d=D()
d.func()
  1. 多态:一种接口,多种实现
  2. 方法
    静态方法@staticmethod:名义上归类管理,实际上访问不了类和实例中的任何属性
    类方法@classmethod:只能访问类变量,不能访问实例变量
    属性方法@property:把一个方法转换成静态属性
class Person(object):
    def __init__(self,first_name,last_name):
        self.first_name=first_name
        self.last_name=last_name
    @property
    def full_name(self):
        return "%s %s"%(self.first_name,self.last_name)
    @full_name.setter
    def first_namex(self,first_name):
        self.first_name=first_name
p1=Person("Mike","Driscoll")
print(p1.full_name)
p1.first_namex="lema"
print(p1.full_name)

伪私有方法:

#以双下划线开头的类方法名,在类实例化以后会自动被概念,在其名字前加 _类名. 
#因为名字被改了,所以自然无法用双下划开头的名字被访问,从而达到不可进入的目的
class Person(object):
    def __func(self):
       pass
p1=Person()
p1._Person__func()

类名.__doc__:返回该类的注释说明
__module__
__class__
__call__
def __str__(self): pass

class Dog(object):
    def __init__(self):
        print("执行init")
    def __str__(self):
        return "执行__str__"
d1=Dog()
print(d1)
  1. 反射:hasattr,getattr,setattr,delattr
def bulk():
    print("往实例对象中添加一个函数")
class Dog(object):
    def __init__(self,name):
        self.name=name
    def eat(self,food):
        print(self.name ":" food)
d1=Dog("lema")
choice=input(">>:").strip()
#反射的是函数
if hasattr(d1,choice):  #hasattr判断一个对象里是否有字符串对应的方法属性
    func=getattr(d1,choice)  
    func("rice")
else:
    setattr(d1,choice,bulk)
d1.talk()  #假设输入的是talk
#反射的是属性
print(d1.name)
if hasattr(d1,choice):
    attr=getattr(d1,choice)
    setattr(d1,choice,"ronghua")
else:
    setattr(d1,choice,22)
print(d1.name)  #假设输入的是name
print(d1.age)  #假设输入的是age

1.4. 空值

空值使用 None 表示,类似null的含义。 

  ①setup.py

  一般来说,用setup.py来管理代码的打包、安装、部署问题。业界标准的写法是用Python流行的打包工具setuptools来管理这些事情。这种方式普遍应用于开源项目中。不过这里的核心思想不是用标准化的工具来解决这些问题,而是说,一个项目一定要有一个安装部署工具,能快速便捷的在一台新机器上将环境装好、代码部署好和将程序运行起来。

  开始接触Python写项目的时候,安装环境、部署代码、运行程序这个过程全是手动完成,遇到过以下问题:

setup.py可以将这些事情自动化起来,提高效率、减少出错的概率。"复杂的东西自动化,能自动化的东西一定要自动化。"是一个非常好的习惯。

  setuptools的文档比较庞大,刚接触的话,可能不太好找到切入点。学习技术的方式就是看他人是怎么用的,可以参考一下Python的一个Web框架,flask是如何写的: setup.py

1.5. 变量

变量可以是任意数据类型,变量名必须是 大小写、数字、_组成,不能以数字开头。变量通过=赋值,例如:a = 123将变量a赋值为整数123。

python是动态语言,变量的类型是不固定的。而例如Java则是静态语言,变量在定义时必须指定类型,例如:int a = 123;,赋值时候如果类型不匹配,
则编译时会报错。与静态语言相比,动态语言更灵活。

模块

  1. 内置模块(标准库)
    sys
import sys
print("脚本名称:",sys.argv[0])
for i in sys.argv[1:]:
    print("参数",i)
#退出程序,正常退出则返回0
sys.exit(0)
#标准输入
for line in sys.stdin:
    print("abc",line)

time/datatime

import time,datatime
time.sleep(0.5)
today=datetime.date.today()
print(str(today.year) '-' str(today.month) '-' str(today.day))
now=datetime.datetime.now()  #now.minute,now.day.now.second...

random

import random
#随机生成四位验证码
checkcode=""
for i in range(4):
    checkcode =random.choice("1234567890")
print(checkcode)
print(random.randint(11,13))  #生成11或12或13
print(random.randrange(2,10,2))  #生成2,4,6,8
#打乱元素
li=[1,2,3,4,5,6,7,8]
random.shuffle(li)
print(li)

hashlib

import hashlib
m1=hashlib.md5()
m1.update(b"admin")
m1.update(b"123")
print(m1.hexdigest())
m2=hashlib.md5()
m2.update("admin123".encode())
print(m2.hexdigest())

re

import re
# re.match()从字符串初始位置开始查找,若初始位置开始匹配错误,返回None
print(re.match("chend ","rchen321"))
print(re.match("chend ","chen321").group())
# re.search()从字符串全局开始查找,只匹配第一个找到的
print(re.search("chend ","rchen321").group())
# 分离字符串,返回["abc","de","f"]
print(re.split("[0-9] ","abc12de34f"))
# 替换匹配到的字符,返回"abc11de14f"
print(re.sub("[0-9]","1","abc52de34f",count=3))
# 列表形式返回所有查找到的结果
print(re.findall("chend ","chen321 chen14"))

os

import os,os.path
# os.popen()返回一个file对象
cmd_res=os.popen("dir").read()
print(cmd_res)
# 判断文件或目录是否存在
print(os.path.exists("test.py"))
print(os.path.exists("D:softwareAnaconda"))
print(os.path.isfile("test.py"))
print(os.path.isdir("D:softwareAnaconda"))
# 路径拼接
print(os.path.join('/home/aa','/home/aa/','/home/aa/bb/c'))
# 将路径与扩展名分离
print(os.path.splitext("/home/haha.py"))  # 返回一个二元组
# 获取文件的大小
print(os.path.getsize("test.py"))  
# 获取相关文件的系统状态信息,st_atime,st_mtime,st_ctime...
print(os.stat("test.py").st_size)
# 将相对路径转换成绝对路径
print(os.path.abspath(__file__))
  1. 第三方库(开源模块)
  2. 自定义模块
  3. 导入模块与导入包:
    导入包的本质就是解释包下面的__init__.py文件
import module1_name,module2_name # 解释包下面的__init__.py文件
from module_name import *  #不推荐使用
from random import randint as ri # 解释包下面的randint.py文件
from module_name import func1,func2

#动态加载模块
mod1=__import__("baobao.test")
print(mod1)
mod1.test.func()
#官方建议使用下面的用法
import importlib
mod2=importlib.import_module("baobao.test")
print(mod2)
mod2.func()

1.5. 变量

变量可以是任意数据类型,变量名必须是 大小写、数字、_ 组成,不能以数字开头。变量通过 = 赋值,例如:a = 123 将变量a赋值为整数123。

python是动态语言,变量的类型是不固定的。而例如Java则是静态语言,变量在定义时必须指定类型,例如:int a = 123;,赋值时候如果类型不匹配, 
则编译时会报错。与静态语言相比,动态语言更灵活。 

  ②requirements.txt

  这个文件存在的目的是:

  这个文件的格式是每一行包含一个包依赖的说明,通常是flask>=0.10这种格式,要求是这个格式能被pip识别,这样就可以简单的通过 pip install -r requirements.txt来把所有Python包依赖都装好了。具体格式说明: 点这里。

1.6. 常量

常量就是不能变的变量。一般习惯上将常量大写。

python中除法有////计算结果是浮点数,//计算结果则为整数。通过%来取两个整数相除的余数。例如:

>>> 10 / 33.3333333333333335>>> 10 // 33>>> 10 % 31

文件操作

  1. 文件读取&写入
with open("test.txt","r ",encoding="utf-8") as f:
    f.write("hello456n")
    f.writelines(["hello", "world", "n"])
    #逐行读取文本内容
    for line in f:
        print(line)
    #一次性读取当前光标后的10个字符
    print(f.read(10))
    print(f.tell())  #获得当前文件的光标
    f.seek(0)  #将光标移动到最开始的地方
  1. 文件打开的模式
    "r":只读模式
    "w":创建或覆盖模式
    "a":追加模式
    "r ":读写模式

1.6. 常量

常量就是不能变的变量。一般习惯上将常量大写。

python中除法有 / 和 ///计算结果是浮点数,//计算结果则为整数。通过 % 来取两个整数相除的余数。例如:

>>> 10 / 3
3.3333333333333335
>>> 10 // 3
3
>>> 10 % 3
1 

  关于配置文件的使用方法

2. 字符串和编码

其它特性:

  1. 生成器
    把列表生成式的[]改为()
[i*2 for i in range(10000000)]  #列表生成式,[func(i) for i in range(10)]
(i*2 for i in range(1000000))  #生成器

含yield的函数

  1. 迭代
    可迭代对象:可以通过for循环来遍历的对象称为可迭代对象,比如str,dict,list,tuple,set,生成器
    迭代器:可以被next()函数调用并返回下一个值的对象称为迭代器,把可迭代对象变成iterator可以使用iter()函数
  2. 垃圾自动回收机制
    del:函数名,实例名,变量名,类名
  3. 异常处理
data={}
li=[1,2]
try:
    open("test.txt",r)
    data['name']
    li[3]
except KeyError as e:
    print("没有这个键",e)
except IndexError as e:
    print("列表操作错误",e)
except Exception as e:
    print("未知错误")
else:
    print("一切正常")
finally:
    print("不管有无错误,照常执行")

#自定义异常
class AlexException(Exception):
    def __init__(self,msg):
        self.msg=msg
    def __str__(self):
        #print(self.msg)
        return self.msg
try:
    raise AlexException("我的异常")
except AlexException as e:
    print(e)

#断言
num=13
assert type(num) is str
print("right")

2. 字符串和编码

  注意,在上面的目录结构中,没有将conf.py放在源码目录下,而是放在docs/目录下。

  很多项目对配置文件的使用做法是:

  这种做法我不太赞同:

  配置的使用,更好的方式是,

  能够佐证这个思想的是,nginx、mysql这些程序都可以自由的指定用户配置。

  所以,不应当在代码中直接import conf来使用配置文件。上面目录结构中的conf.py,是给出的一个配置样例,不是在写死在程序中直接引用的配置文件。可以通过给main.py启动参数指定配置路径的方式来让程序读取配置内容。当然,这里的conf.py你可以换个类似的名字,比如settings.py。或者你也可以使用其他格式的内容来编写配置文件,比如settings.yaml之类的。

目录: 1、装饰器 2、迭代器生成器 3、Json pickle 数据序列化 4、软件目录结构规范 一、装饰器...

2.1. 字符串

python中的字符串类型为str,在内存中以Unicode表示,一个字符对应若干字节。如果在网络上传输或保存到磁盘,就需要把str转化为字节bytesbytes类型数据用带b前缀的单引号或双引号表示:x = b'abc',注意abcstr类型,而b'abc'则是bytes类型。

str通过encode()可以将编码为指定的bytes,例如:

澳门新萄京官方网站 8

>>> '中文'.encodeb'xe4xb8xadxe6x96x87'>>> 'abc'.encodeb'abc'>>> '中文'.encodeTraceback (most recent call last):  File "<stdin>", line 1, in <module>UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range

澳门新萄京官方网站 9

英文的str可以用ASCII编码为bytes,中文的str可以用UTF-8编码为bytes,而中文的str无法通过ASCII编码,因为中文超出ASCII的编码范围,故报错。

bytes可以通过decode()方法解码为str,例如:

>>> b'xe4xb8xadxe6x96x87'.decode'中文'>>> b'abc'.decode'abc'

通过len()可以计算str的字符数或bytes的字节数。例如:

>>> len2>>> len('中文'.encode6

操作字符串时,我们经常会将str和bytes互相转换,为了避免乱码的问题,一般推荐使用utf-8编码方式。

软件目录结构规范

Foo
    bin                  # 存放一些项目的可执行文件
        一键启动.py
    core                 # 存放项目的所有源代码
        tests            # 存放单元测试代码
            __init__.py
            test_main.py
        __init__.py
        main.py
    docs                  # 存放一些文档
        conf.py
        abc.rst
    setup.py              # 安装,部署,打包的脚本
    requirements.txt      # 存放软件依赖的外部python包列表
    README                #项目说明文件
        1.软件定位,软件的基本功能
        2.运行代码的方法,安装环境,启动命令等
        3.简要的使用说明
        4.代码目录结构说明
        5.常见问题说明

2.1. 字符串

python中的字符串类型为str,在内存中以Unicode表示,一个字符对应若干字节。如果在网络上传输或保存到磁盘,就需要把str转化为字节bytesbytes类型数据用带b前缀的单引号或双引号表示:x = b'abc',注意 abcstr类型,而b'abc'则是bytes类型。

str通过encode()可以将编码为指定的bytes,例如:

澳门新萄京官方网站 10

>>> '中文'.encode('utf-8')
b'xe4xb8xadxe6x96x87'
>>> 'abc'.encode('ascii')
b'abc'
>>> '中文'.encode('ascii')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

澳门新萄京官方网站 11

英文的str可以用ASCII编码为bytes,中文的str可以用UTF-8编码为bytes,而中文的str无法通过ASCII编码,因为中文超出ASCII的编码范围,故报错。

bytes可以通过decode()方法解码为str,例如:

>>> b'xe4xb8xadxe6x96x87'.decode('utf-8')
'中文'
>>> b'abc'.decode('ascii')
'abc'

通过len()可以计算str的字符数或bytes的字节数。例如:

>>> len('中文')
2
>>> len('中文'.encode('utf-8'))
6

操作字符串时,我们经常会将str和bytes互相转换,为了避免乱码的问题,一般推荐使用utf-8编码方式。 

2.2. 格式化

python中的字符串格式化方式和C语言类似,都是通过%运算符实现。例如:

>>> "Hi, %s, you have %d" % ('peter', 100)'Hi, peter, you have 100'

有几个占位符,后面就有几个变量,顺序要对应好。常见的占位符有:

  • %s: 字符串
  • %d: 整数
  • %f: 浮点数,%.2f 表示保留2位小数

另一种格式化字符串的方法是使用字符串的format()方法,它会用传入的参数依次替换字符串内的占位符{0}、{1}...,例如:

>>> "Hi, {0}, you have {1:.2f}".format('peter', 3.1415926)'Hi, peter, you have 3.14'

多线程&多进程&协程

import threading,time
def run(n):
    print("task:",n)
    time.sleep(2)
    print(threading.current_thread()) # 返回当前线程对象
    print(threading.active_count()) # 返回当前存活线程数量
    print(threading.main_thread()) # 返回主线程对象
start_time=time.time()
t_total=[]
for i in range(50):
    t2=threading.Thread(target=run,args=("t%s"%i,))
    t2.setDaemon(True) # 把当前线程设置为守护线程
    t2.start() # 主线程启动子线程
    t_total.append(t2)
# for t in t_total:
#     t.join() # 一个线程等到另一个线程执行结束后再执行下面的代码
end_time=time.time()
print(threading.current_thread())
print(end_time-start_time)

# 线程交互
import time,threading
event=threading.Event()
def lighter():
    count=0
    event.set() # 设置标志位
    while True:
        if count>5 and count<=10: # 变红灯
            event.clear() # 把标志位清空
            print("红灯停")
        elif count>10:
            event.set() # 变绿灯
            count=0
        else:
            print("绿灯行")
        time.sleep(1)
        count =1
light=threading.Thread(target=lighter,)
light.start()
def car(name):
    while True:
        if event.is_set():
            print("     %s正在行驶"%name)
            time.sleep(1)
        else:
            print("     %s正在等待"%name)
            time.sleep(1)
            event.wait()
car1=threading.Thread(target=car,args=("奔驰",))
car2=threading.Thread(target=car,args=("兰博基尼",))
car1.start()
car2.start()

# queue队列
# queue.Queue(maxsize=0) 顺序先入先出
# queue.LifoQueue(maxsize=0) 顺序后入先出,last in first out
# queue.PriorityQueue(maxsize=0) 存储数据时可设置优先级
import queue
try:
    q=queue.Queue(maxsize=3)
    q.put("d1")
    q.put("d2")
    q.put("d3")
    q.put("d4",block=False)
    print(q.qsize()) # 返回队列长度
    print(q.get())
    print(q.get_nowait())
    print(q.get_nowait())
    print(q.get(block=False)) # 非阻塞
    print(q.get(timeout=3))
    print(q.get_nowait())
except queue.Empty as e:
    print("队列为空")
except queue.Full as e:
    print("队列满了")

q2=queue.PriorityQueue()
q2.put((-2,"lema"))
q2.put((34,"asd"))
q2.put((11,"qwe"))
print(q2.get())
print(q2.get())
print(q2.get())

2.2. 格式化

python中的字符串格式化方式和C语言类似,都是通过%运算符实现。例如:

>>> "Hi, %s, you have %d" % ('peter', 100)
'Hi, peter, you have 100'

有几个占位符,后面就有几个变量,顺序要对应好。常见的占位符有:

  • %s: 字符串
  • %d: 整数
  • %f: 浮点数,%.2f 表示保留2位小数

另一种格式化字符串的方法是使用字符串的format()方法,它会用传入的参数依次替换字符串内的占位符{0}、{1}...,例如:

>>> "Hi, {0}, you have {1:.2f}".format('peter', 3.1415926)
'Hi, peter, you have 3.14' 

3. 基本数据结构

3. 基本数据结构

3.1 list

list是内置的数据结构:列表,表示有序的数据集合。例如:books = ['a', 'b', 'c'],books就是一个list。使用的一些方法如下:

澳门新萄京官方网站 12

>>> books = ['a', 'b', 'c']>>> books['a', 'b', 'c']>>> len  # 计算list元素的个数3>>> books[0]    # 通过索引访问list中的元素,索引下标从0开始'a'>>> books[4]    # 超出list的范围会报IndexError错误,最后一个下标是 len-1Traceback (most recent call last):  File "<stdin>", line 1, in <module>IndexError: list index out of range>>> books[-1]   # 下标-1代表最后一个元素,-2是倒数第二个元素,以此类推'c'>>> books[-2]'b'>>> books.append  # 往list队尾添加元素>>> books.insert(1, ['abc', 'def'])  # 往list指定下标位置添加元素>>> books       # list内的元素可以是不同的类型['a', ['abc', 'def'], 'b', 'c', True]>>> books.pop() # 从队尾删除元素True>>> books.pop # 从list指定下标位置删除元素['abc', 'def']>>> books;['a', 'b', 'c']>>> books[1] = 'abc' # 可以类似数组,直接替换指定下标位置的元素>>> list = list   # 通过range()函数生成0-4的整数序列,再通过list()函数转换为list>>> list[0, 1, 2, 3, 4]

澳门新萄京官方网站 13

3.1 list

list是内置的数据结构:列表,表示有序的数据集合。例如:books = ['a', 'b', 'c'],books就是一个list。使用的一些方法如下:

澳门新萄京官方网站 14

>>> books = ['a', 'b', 'c']
>>> books
['a', 'b', 'c']
>>> len(books)  # 计算list元素的个数
3
>>> books[0]    # 通过索引访问list中的元素,索引下标从0开始
'a'
>>> books[4]    # 超出list的范围会报IndexError错误,最后一个下标是 len-1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
>>> books[-1]   # 下标-1代表最后一个元素,-2是倒数第二个元素,以此类推
'c'
>>> books[-2]
'b'
>>> books.append(True)  # 往list队尾添加元素
>>> books.insert(1, ['abc', 'def'])  # 往list指定下标位置(1)添加元素
>>> books       # list内的元素可以是不同的类型
['a', ['abc', 'def'], 'b', 'c', True]
>>> books.pop() # 从队尾删除元素
True
>>> books.pop(1) # 从list指定下标位置(index=1)删除元素
['abc', 'def']
>>> books;
['a', 'b', 'c']
>>> books[1] = 'abc' # 可以类似数组,直接替换指定下标位置的元素
>>> list = list(range(5))   # 通过range()函数生成0-4的整数序列,再通过list()函数转换为list
>>> list
[0, 1, 2, 3, 4] 

澳门新萄京官方网站 15

3.2 tuple

tuple是另一种有序数组,但和list不同的是tuple一经初始化就不能再修改,不能使用append()pop()等修改方法。可以和list类似使用books[0]books[-1]正常访问元素。不可变使得代码更安全。使用方法如下:

>>> books = (1,2,['a','b'])  # 通过(... , ...)定义tuple>>> books(1, 2, ['a', 'b'])>>> books[2][1]'b'

3.2 tuple

tuple是另一种有序数组,但和list不同的是tuple一经初始化就不能再修改,不能使用append()pop()等修改方法。可以和list类似使用books[0]books[-1]正常访问元素。不可变使得代码更安全。使用方法如下:

>>> books = (1,2,['a','b'])  # 通过(... , ...)定义tuple
>>> books
(1, 2, ['a', 'b'])
>>> books[2][1]
'b' 

3.3 dict

dict全称为dictionary,是python的内置字典。使用 key-value 键值对存储,一个key只对应一个value。类似 java 中的 map,使用了哈希表的数据结构,有极快的查找速度。使用方法如下:

澳门新萄京官方网站 16

>>> dict = {'a':100, 'b':200, 'c':300}>>> dict['c']           # 根据key获取value300>>> dict['Adam'] = 400  # 通过key放入value数据>>> 'Adam' in dict      # 判断key是否在字典中True>>> 'adam' in dictFalse>>> dict.get    # key如果不存在,则会返回None400>>> dict.pop       # 删除一个key-value对100

澳门新萄京官方网站 17

注意:dict的key是不可变的

3.3 dict

dict全称为dictionary,是python的内置字典。使用 key-value 键值对存储,一个key只对应一个value。类似 java 中的 map,使用了哈希表的数据结构,有极快的查找速度。使用方法如下:

澳门新萄京官方网站 18

>>> dict = {'a':100, 'b':200, 'c':300}
>>> dict['c']           # 根据key获取value
300
>>> dict['Adam'] = 400  # 通过key放入value数据
>>> 'Adam' in dict      # 判断key是否在字典中
True
>>> 'adam' in dict
False
>>> dict.get('Adam')    # key如果不存在,则会返回None
400
>>> dict.pop('a')       # 删除一个key-value对
100

澳门新萄京官方网站 19

注意:dict的key是不可变的

3.4 set

set和dict类似,也是一组key的集合,但不存储value。在set中,key不能重复。使用方法如下:

澳门新萄京官方网站 20

>>> set = set  # 新建set,以list作为输入集合>>> set.add          # 往set中添加元素,但set中元素不能重复>>> set.remove       # 从set中移除元素>>> s1 = set>>> s1{1, 2, 3}>>> s2 = set>>> s1 & s2             # 求s1和s2两个set的交集{2, 3}>>> s1 | s2             # 求s1和s2两个set的并集{1, 2, 3}

澳门新萄京官方网站 21

3.4 set

set和dict类似,也是一组key的集合,但不存储value。在set中,key不能重复。使用方法如下:

澳门新萄京官方网站 22

>>> set = set([1,2,3])  # 新建set,以list作为输入集合
>>> set.add(1)          # 往set中添加元素,但set中元素不能重复
>>> set.remove(1)       # 从set中移除元素
>>> s1 = set([1,2,3])
>>> s1
{1, 2, 3}
>>> s2 = set([2,3])
>>> s1 & s2             # 求s1和s2两个set的交集
{2, 3}
>>> s1 | s2             # 求s1和s2两个set的并集
{1, 2, 3} 

澳门新萄京官方网站 23

4. 条件和循环

4. 条件和循环

4.1. 条件判断

条件判读通过if,elif,else完成,完成形式如下:

澳门新萄京官方网站 24

if <条件判断1>:    <执行1>elif <条件判断2>:    <执行2>elif <条件判断3>:    <执行3>else:    <执行4>

澳门新萄京官方网站 25

如果一个if判断为True,则会忽略下面的判断语句

4.1. 条件判断

条件判读通过ifelifelse完成,完成形式如下:

澳门新萄京官方网站 26

if <条件判断1>:
    <执行1>
elif <条件判断2>:
    <执行2>
elif <条件判断3>:
    <执行3>
else:
    <执行4>

澳门新萄京官方网站 27

如果一个if判断为True,则会忽略下面的判断语句 

4.2. 循环

循环方式有两种,一种是for...in循环,依次将list或tuple中的元素迭代出来,计算1-100的和:

sum = 0for x in range:    sum  = xprint

另一种方式是while循环,只要条件满足while后语句,就一直循环。计算1-100的和:

sum = 0x = 1while x <= 100:    sum  = x    x  = 1print

可以通过break提前退出while循环,contince提前结束当前循环,进行下次循环。这两个语句通常需要配合if使用

4.2. 循环

循环方式有两种,一种是for...in循环,依次将list或tuple中的元素迭代出来,计算1-100的和:

sum = 0
for x in range(101):
    sum  = x
print(sum)

另一种方式是while循环,只要条件满足while后语句,就一直循环。计算1-100的和:

sum = 0
x = 1
while x <= 100:
    sum  = x
    x  = 1
print(sum)

可以通过break提前退出while循环,contince提前结束当前循环,进行下次循环。这两个语句通常需要配合if使用 

三、 函数

三、 函数

1. 调用函数

如果想调用一个函数,需要知道这个函数的名称和参数。如abs()求绝对值的函数,只要一个参数,可以通过help查看该函数的帮助信息。

澳门新萄京官方网站 28

>>> abs1>>> absTraceback (most recent call last):  File "<stdin>", line 1, in <module>TypeError: abs() takes exactly one argument >>> absTraceback (most recent call last):  File "<stdin>", line 1, in <module>TypeError: bad operand type for abs(): 'str'

澳门新萄京官方网站 29

如果传参的个数或类型不正确,会报TypeError错误,并提示错误信息。

函数名就是指向函数对象的引用,可以将函数名赋值给一个变量,相当于给函数起了个"别名":

>>> a = abs     # 将变量a指向函数abs()>>> a       # 通过a调用abs()函数1

1. 调用函数

如果想调用一个函数,需要知道这个函数的名称和参数。如abs()求绝对值的函数,只要一个参数,可以通过help(abs)查看该函数的帮助信息。

澳门新萄京官方网站 30

>>> abs(-1)
1
>>> abs(1,2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: abs() takes exactly one argument (2 given)
>>> abs('abc')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: bad operand type for abs(): 'str'

澳门新萄京官方网站 31

如果传参的个数或类型不正确,会报TypeError错误,并提示错误信息。

函数名就是指向函数对象的引用,可以将函数名赋值给一个变量,相当于给函数起了个"别名":

>>> a = abs     # 将变量a指向函数abs()
>>> a(-1)       # 通过a调用abs()函数
1 

2. 定义函数

定义函数使用def,函数的返回值使用return,例如:

澳门新萄京官方网站 32

def my_abs:    if not isinstance(x, (int, float)):     # 检查 x 的数据类型        raise TypeError("type error")       # 抛出TypeError异常    if x >= 0:        x;    else:        return -x;print(my_abs  

澳门新萄京官方网站 33

如果没有return值,则会返回None

pass作为占位符,表示什么都不会做。如果没想好怎么写函数中的代码,可以先用pass让代码运行起来。而缺少了pass,代码会报错。

if x >= 0:    pass;

函数可以返回多个返回值,但其实是返回的单一值:tuple。但写起来方便,可以使用多个变量来接受一个tuple。

澳门新萄京官方网站 34

def test:    return 1,2x, y = testprint)输出:

澳门新萄京官方网站 35

2. 定义函数

定义函数使用def,函数的返回值使用return,例如:

澳门新萄京官方网站 36

def my_abs(x):
    if not isinstance(x, (int, float)):     # 检查 x 的数据类型
        raise TypeError("type error")       # 抛出TypeError异常
    if x >= 0:
        x;
    else:
        return -x;

print(my_abs(-1))  

澳门新萄京官方网站 37

如果没有return值,则会返回None

pass作为占位符,表示什么都不会做。如果没想好怎么写函数中的代码,可以先用pass让代码运行起来。而缺少了pass,代码会报错。

if x >= 0:
    pass;

函数可以返回多个返回值,但其实是返回的单一值:tuple。但写起来方便,可以使用多个变量来接受一个tuple。

澳门新萄京官方网站 38

def test(x):
    return 1,2

x, y = test('a')
print(test('a'))
输出:
(1, 2)

澳门新萄京官方网站 39

3. 函数的参数

函数除了必选参数外,还提供了默认参数,可变参数和关键字参数,使得定义的函数能处理复杂的参数,简化开发者的调用。

1)默认参数:先定义power函数,计算x的n次方:

澳门新萄京官方网站 40

def enroll(name, gender, age=6, city='Beijing'):    # 第3、4个参数设置默认值    print('name:', name)    print('gender:', gender)    print('age:', age)    print('city:', city)    returnprint(enroll)     # 等同于调用enroll('a','F',6,'Beijing')print(enroll('a', 'F', city='BJ'))  # 当参数不按定义的顺序传递时,需要把参数名写上,此时age还使用默认值

澳门新萄京官方网站 41

设置默认参数有几点需要注意:

  1. 必选参数在前,默认参数在后。否则无法判断参数的值该是哪个
  2. 变化大的参数放前面,变化小的参数放后面。变化小的可以设置为默认参数,好处就是降低了调用函数的难度。
  3. 默认参数必须指向不可变对象

2)可变参数,传入函数的参数个数是可变的,可以是0, 1...个。可变参数是在参数前面加上了*,例如:

澳门新萄京官方网站 42

def cacl:      # number接收的是一个tuple    for x in number:        printcacl         # 函数可以传任意值nums = [1,2,3]cacl         # nums前加一个*,将list或tuple的值作为可变参数传递

澳门新萄京官方网站 43

3)关键字参数:允许传递0或任意个含参数名的参数,这些关键字参数在函数内部组装成一个dict。关键字参数可以扩展函数的功能。例如:

澳门新萄京官方网站 44

def person(name, age, **kw):    print('name', name, 'age', age, 'others', kw)# 可传入任意个关键字参数person('peter', 10, gender='M', job='Engineer')# 可先组装dict,然后通过**dict将所有key-value用关键字参数传入函数的**kw,kw获得dict的一份拷贝,对kw的改动不会影响外面的dictdict = {'gender':'M', 'job':'Engineer'}person('peter', 10, **dict)

澳门新萄京官方网站 45

4)命名关键字参数:
函数调用者可以传入任意不受限制的关键字参数,在函数内部可以通过kw检查到底传递了哪些。例如:

def person(name, age, **kw):    if 'city' in kw:        # 检查是否有city和job参数        print(kw['city'])    if 'job' in kw:        print(kw['job'])    print(name, age, kw)

如果要限制关键字参数的名字,可以使用命名关键字参数,和关键字参数**kw不同,命名关键字参数需要一个特殊的分隔符**后面的参数被视为命名关键字参数。例如:

def person(name, age, *, city, job):    # 只接收city和job作为关键字参数    print(name, age, city, job)# 命名关键字参数必须传入参数名,如果没有传入参数名,则调用会报错person('name', 18, city='city', job='job') 

3. 函数的参数

函数除了必选参数外,还提供了默认参数,可变参数和关键字参数,使得定义的函数能处理复杂的参数,简化开发者的调用。

1)默认参数:先定义power函数,计算x的n次方:

澳门新萄京官方网站 46

def enroll(name, gender, age=6, city='Beijing'):
    # 第3、4个参数设置默认值
    print('name:', name)
    print('gender:', gender)
    print('age:', age)
    print('city:', city)
    return

print(enroll('a', 'F'))     # 等同于调用enroll('a','F',6,'Beijing')
print(enroll('a', 'F', city='BJ'))  # 当参数不按定义的顺序传递时,需要把参数名写上,此时age还使用默认值

澳门新萄京官方网站 47

设置默认参数有几点需要注意:

  1. 必选参数在前,默认参数在后。否则无法判断参数的值该是哪个
  2. 变化大的参数放前面,变化小的参数放后面。变化小的可以设置为默认参数,好处就是降低了调用函数的难度。
  3. 默认参数必须指向不可变对象

2)可变参数,传入函数的参数个数是可变的,可以是0, 1...个。可变参数是在参数前面加上了*,例如:

澳门新萄京官方网站 48

def cacl(*number):      # number接收的是一个tuple
    for x in number:
        print(x)

cacl()
cacl(1,2,3)         # 函数可以传任意值
nums = [1,2,3]
cacl(*nums)         # nums前加一个*,将list或tuple的值作为可变参数传递

澳门新萄京官方网站 49

3)关键字参数:允许传递0或任意个含参数名的参数,这些关键字参数在函数内部组装成一个dict。关键字参数可以扩展函数的功能。例如:

澳门新萄京官方网站 50

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

# 可传入任意个关键字参数
person('peter', 10, gender='M', job='Engineer')

# 可先组装dict,然后通过**dict将所有key-value用关键字参数传入函数的**kw,kw获得dict的一份拷贝,对kw的改动不会影响外面的dict
dict = {'gender':'M', 'job':'Engineer'}
person('peter', 10, **dict)

澳门新萄京官方网站 51

4)命名关键字参数: 
函数调用者可以传入任意不受限制的关键字参数,在函数内部可以通过kw检查到底传递了哪些。例如:

def person(name, age, **kw):
    if 'city' in kw:        # 检查是否有city和job参数
        print(kw['city'])
    if 'job' in kw:
        print(kw['job'])
    print(name, age, kw)

如果要限制关键字参数的名字,可以使用命名关键字参数,和关键字参数**kw不同,命名关键字参数需要一个特殊的分隔符**后面的参数被视为命名关键字参数。例如:

def person(name, age, *, city, job):    # 只接收city和job作为关键字参数
    print(name, age, city, job)

# 命名关键字参数必须传入参数名,如果没有传入参数名,则调用会报错
person('name', 18, city='city', job='job')  

4. 递归函数

函数内部可以调用其他函数,如果一个函数在内部调用本身,则这个函数是递归函数。例如:计算n的阶乘用递归方式写出来就是

def func:    if n == 1:        return 1    return n * func

4. 递归函数

函数内部可以调用其他函数,如果一个函数在内部调用本身,则这个函数是递归函数。例如:计算n的阶乘用递归方式写出来就是

def func(n):
    if n == 1:
        return 1
    return n * func(n-1) 

四、高级特性

利用python的一些高级特性,可以用1行代码实现很多功能,从而帮助我们提升了开发效率。

四、高级特性

利用python的一些高级特性,可以用1行代码实现很多功能,从而帮助我们提升了开发效率。 

1. 切片

python提供了切片操作符,用于取list或tuple的部分元素。

澳门新萄京官方网站 52

>>> L = ['a','b','c','d','e']>>> L[0:3]              # 取前3个元素,从索引0到索引3的元素['a', 'b', 'c']>>> L[:3]               # 如果第一个索引是0,可以省略['a', 'b', 'c']>>> L[-2:-1]            # 倒数切片,倒数第2个元素,倒数第一个元素索引是-1['d']>>> L[-2:]              # 倒数前2个元素['d', 'e']>>> L[0:5:2]            # 取前5个元素,每2个取一次['a', 'c', 'e']>>> L[::2]              # 取所有元素,每2个取一次['a', 'c', 'e']

澳门新萄京官方网站 53

tuple是不可变的一种list,也支持切片操作,操作结果仍是tuple

>>> (1,2,3,4,5)[:3]

字符串"abcde"也可看做是一个list,每个元素就是一个字符,也可以使用切片操作,其结果仍旧是字符串

>>> 'abcde'[:5:2]'ace'

1. 切片

python提供了切片(Slice)操作符,用于取list或tuple的部分元素。

澳门新萄京官方网站 54

>>> L = ['a','b','c','d','e']
>>> L[0:3]              # 取前3个元素,从索引0到索引3(但不包括索引3)的元素
['a', 'b', 'c']
>>> L[:3]               # 如果第一个索引是0,可以省略
['a', 'b', 'c']
>>> L[-2:-1]            # 倒数切片,倒数第2个元素,倒数第一个元素索引是-1
['d']
>>> L[-2:]              # 倒数前2个元素
['d', 'e']
>>> L[0:5:2]            # 取前5个元素,每2个取一次
['a', 'c', 'e']
>>> L[::2]              # 取所有元素,每2个取一次
['a', 'c', 'e']

澳门新萄京官方网站 55

tuple是不可变的一种list,也支持切片操作,操作结果仍是tuple

>>> (1,2,3,4,5)[:3]
(1, 2, 3)

字符串"abcde"也可看做是一个list,每个元素就是一个字符,也可以使用切片操作,其结果仍旧是字符串

>>> 'abcde'[:5:2]
'ace' 

2. 迭代

如果给定一个list或tuple,可以使用for循环来遍历,这种遍历称为迭代(Iteration)。python中的迭代是通过for...in来完成,不仅可迭代list/tuple。还可迭代其他对象。

澳门新萄京官方网站 56

# 迭代list>>> l = list)>>> for item in l:...     print# 迭代dict,由于dict的存储不是像list那样顺序存储,所有迭代结果可能不是按顺序的>>> d = {'a':1, 'b':2}>>> for key in d:               # 默认是迭代的key...     print...ba>>> for value in d.values():    # 迭代value...     print...21>>> for k,v in d.items():       # 迭代key和value...     print...b 2a 1# 迭代字符串>>> for ch in 'abc':...     print...abc

澳门新萄京官方网站 57

当使用for时,只要作用与一个迭代对象,就可以正常运行,我们不需要关注迭代对象是list还是其他数据类型。可以通过collections模块的Iterable类型判断一个对象是否是可迭代对象:

澳门新萄京官方网站 58

>>> from collections import Iterable>>> isinstance('abc', Iterable)     # str类型可迭代True>>> isinstance(123, Iterable)       # 整数不可迭代False>>> dict={'a':1}>>> isinstance(dict, Iterable)      # dict类型可迭代True

澳门新萄京官方网站 59

python内置的enumerate函数可以将list变成索引-元素对。这样可以在for中迭代索引和对象本身:

澳门新萄京官方网站 60

>>> l = ['a','b','c','d']>>> for i,value in enumerate:...     print...0 a1 b2 c3 d

澳门新萄京官方网站 61

2. 迭代

如果给定一个list或tuple,可以使用for循环来遍历,这种遍历称为迭代(Iteration)。python中的迭代是通过for...in 来完成,不仅可迭代list/tuple。还可迭代其他对象。

澳门新萄京官方网站 62

# 迭代list
>>> l = list(range(10))
>>> for item in l:
...     print(item)

# 迭代dict,由于dict的存储不是像list那样顺序存储,所有迭代结果可能不是按顺序的
>>> d = {'a':1, 'b':2}
>>> for key in d:               # 默认是迭代的key
...     print(key)
...
b
a
>>> for value in d.values():    # 迭代value
...     print(value)
...
2
1
>>> for k,v in d.items():       # 迭代key和value
...     print(k, v)
...
b 2
a 1

# 迭代字符串
>>> for ch in 'abc':
...     print(ch)
...
a
b
c

澳门新萄京官方网站 63

当使用for时,只要作用与一个迭代对象,就可以正常运行,我们不需要关注迭代对象是list还是其他数据类型。可以通过collections模块的Iterable类型判断一个对象是否是可迭代对象:

澳门新萄京官方网站 64

>>> from collections import Iterable
>>> isinstance('abc', Iterable)     # str类型可迭代
True
>>> isinstance(123, Iterable)       # 整数不可迭代
False
>>> dict={'a':1}
>>> isinstance(dict, Iterable)      # dict类型可迭代
True

澳门新萄京官方网站 65

python内置的enumerate函数可以将list变成索引-元素对。这样可以在for中迭代索引和对象本身:

澳门新萄京官方网站 66

>>> l = ['a','b','c','d']
>>> for i,value in enumerate(l):
...     print(i, value)
...
0 a
1 b
2 c
3 d

澳门新萄京官方网站 67

3. 列表生成式

python内置了简单而强大的生成list的方式,通过使用列表生成式可以写出非常简洁的代码。

# 生成 2-10 的list>>> L=list(range>>> L[2, 3, 4, 5, 6, 7, 8, 9, 10]

此外,还可以在for...in...后面加上if进行判断。例如:生成3-10中偶数的平方的list:

>>> L=[x * x for x in range if x % 2 ==0]>>> L[16, 36, 64, 100]

等价于

澳门新萄京官方网站 68

>>> L=[]>>> for x in range:...     if x % 2 == 0:...         L.append...>>> L[16, 36, 64, 100]

澳门新萄京官方网站 69

列表生成式也可以使用两个变量来生成list:

>>> dict={'a':'1', 'b':'2'}>>> [k '=' v for k,v in dict.items()]['b=2', 'a=1']

3. 列表生成式

python内置了简单而强大的生成list的方式,通过使用列表生成式可以写出非常简洁的代码。

# 生成 2-10 的list
>>> L=list(range(2,11))
>>> L
[2, 3, 4, 5, 6, 7, 8, 9, 10]

此外,还可以在for...in...后面加上if进行判断。例如:生成3-10中偶数的平方的list:

>>> L=[x * x for x in range(3,11) if x % 2 ==0]
>>> L
[16, 36, 64, 100]

等价于

澳门新萄京官方网站 70

>>> L=[]
>>> for x in range(3,11):
...     if x % 2 == 0:
...         L.append(x * x)
...
>>> L
[16, 36, 64, 100]

澳门新萄京官方网站 71

列表生成式也可以使用两个变量来生成list:

>>> dict={'a':'1', 'b':'2'}
>>> [k '=' v for k,v in dict.items()]
['b=2', 'a=1'] 

4. 生成器

通过列表生成器,可以直接创建一个列表。但是,假如创建一个包含100万个元素的列表,需要占用大量的内存空间,而我们只需要前几个元素,那么大多数元素占用的内存空间就浪费了。

对于这种情况,python提供了生成器(generator),能一边循环一边计算,从而不需要创建完整的list,节省了内存空间。

第一种创建generator生成器的方式:将[]改为()

澳门新萄京官方网站 72

>>> L = [x * x for x in range]    # 创建list>>> L                                   # 打印list的每一个元素[1, 4, 9, 16, 25, 36, 49, 64, 81]>>> g = (x * x for x in range    # 创建generator>>> g<generator object <genexpr> at 0x1024e0bf8>>>> next     # 用next()函数获取generator下一个返回值1>>> next4

澳门新萄京官方网站 73

next()会计算g的下一个元素,当没有元素时,会抛出StopIteration异常。generator是可迭代对象,可以使用for循环来代替next()

澳门新萄京官方网站 74

>>> g = (x * x for x in range>>> for n in g:...     print...14916

澳门新萄京官方网站 75

第二种创建generator生成器的方式:函数定义中使用yield,将函数变成generator

下面是生成菲波那切数列的函数,除第一个和第二个数之外,后面每个数等于前两个数的和:

澳门新萄京官方网站 76

def fib:    n, a, b = 0, 0, 1    while n < max:        print        a, b = b, a   b        n = n   1    return 'done'fib      # 输出菲波那切数列前6个数

澳门新萄京官方网站 77

这种逻辑非常类似generator,可以从第一个元素开始,推算后面任意的元素。将print改为yield b,该函数就就变成了generator。generator和普通函数执行流程不一样:

  • 普通函数是顺序执行,遇到return或最后一行函数语句就会返回;
  • 而变为generator的函数,每次调用next()的时候执行,遇到yield中断并返回值,再次调用next()时从上次yield语句处继续执行。

澳门新萄京官方网站 78

>>> def fib:...     n, a, b = 0, 0, 1...     while n < max:...         yield b...         a, b = b, a   b...         n = n   1...     return 'done'...>>> g = fib  # 生成generator对象>>> g<generator object fib at 0x1024e0bf8>>>> next     # 调用next()函数不断获取后一个返回值1>>> next1>>> next2>>> next3>>> next5>>> next8>>> next     # 此时 n = max, 没有yield可以执行了,所有调用就报错了Traceback (most recent call last):  File "<stdin>", line 1, in <module>StopIteration: done>>> for n in fib:    # 也可以使用for循环进行generator的迭代...     print

澳门新萄京官方网站 79

4. 生成器

通过列表生成器,可以直接创建一个列表。但是,假如创建一个包含100万个元素的列表,需要占用大量的内存空间,而我们只需要前几个元素,那么大多数元素占用的内存空间就浪费了。

对于这种情况,python提供了生成器(generator),能一边循环一边计算,从而不需要创建完整的list,节省了内存空间。

第一种创建generator生成器的方式:将[]改为()

澳门新萄京官方网站 80

>>> L = [x * x for x in range(1,10)]    # 创建list
>>> L                                   # 打印list的每一个元素
[1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(1,10))    # 创建generator
>>> g
<generator object <genexpr> at 0x1024e0bf8>
>>> next(g)     # 用next()函数获取generator下一个返回值
1
>>> next(g)
4

澳门新萄京官方网站 81

next()会计算g的下一个元素,当没有元素时,会抛出StopIteration异常。generator是可迭代对象,可以使用for循环来代替next()

澳门新萄京官方网站 82

>>> g = (x * x for x in range(1,5))
>>> for n in g:
...     print(n)
...
1
4
9
16

澳门新萄京官方网站 83

第二种创建generator生成器的方式:函数定义中使用yield,将函数变成generator

下面是生成菲波那切数列的函数,除第一个和第二个数之外,后面每个数等于前两个数的和:

澳门新萄京官方网站 84

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a   b
        n = n   1
    return 'done'

fib(6)      # 输出菲波那切数列前6个数

澳门新萄京官方网站 85

这种逻辑非常类似generator,可以从第一个元素开始,推算后面任意的元素。将print(b)改为yield b,该函数就就变成了generator。generator和普通函数执行流程不一样:

  • 普通函数是顺序执行,遇到return或最后一行函数语句就会返回;
  • 而变为generator的函数,每次调用next()的时候执行,遇到yield中断并返回值,再次调用next()时从上次yield语句处继续执行。

澳门新萄京官方网站 86

>>> def fib(max):
...     n, a, b = 0, 0, 1
...     while n < max:
...         yield b
...         a, b = b, a   b
...         n = n   1
...     return 'done'
...
>>> g = fib(6)  # 生成generator对象
>>> g
<generator object fib at 0x1024e0bf8>
>>> next(g)     # 调用next()函数不断获取后一个返回值
1
>>> next(g)
1
>>> next(g)
2
>>> next(g)
3
>>> next(g)
5
>>> next(g)
8
>>> next(g)     # 此时 n = max, 没有yield可以执行了,所有调用就报错了
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration: done

>>> for n in fib(6):    # 也可以使用for循环进行generator的迭代
...     print(n) 

澳门新萄京官方网站 87

5. 迭代器

直接作用于for循环的数据类型有以下几种:

  • 集合数据类型:list,tuple,dict,set,str
  • generator:包括生成器和带yield的生成器函数

这些可作用for循环的对象统称为可迭代对象:Iterable。可通过isinstance()判断一个对象是否是Iterable:

>>> isinstance([],Iterable)True>>> isinstance((x for x in range,Iterable)True>>> isinstance(123,Iterable)False

生成器不仅可作用于for循环,还可被next()不断调用返回下一个值,直至抛出StopIteration,这类对象成为迭代器:Iterator,也可使用isinstance进行判断:

>>> from collections import Iterator>>> isinstance([],Iterator)False>>> isinstance((x for x in range, Iterator)True

迭代器Iterator表示的是一个数据流,可将数据流看做是一个有序队列,但不能提前知道队列的长度,只能通过next()函数实时按需计算下一个元素的值。

5. 迭代器

直接作用于for循环的数据类型有以下几种:

  • 集合数据类型:list,tuple,dict,set,str
  • generator:包括生成器和带yield的生成器函数

这些可作用for循环的对象统称为可迭代对象:Iterable。可通过isinstance()判断一个对象是否是Iterable:

>>> isinstance([],Iterable)
True
>>> isinstance((x for x in range(10)),Iterable)
True
>>> isinstance(123,Iterable)
False

生成器不仅可作用于for循环,还可被next()不断调用返回下一个值,直至抛出StopIteration,这类对象成为迭代器:Iterator,也可使用isinstance进行判断:

>>> from collections import Iterator
>>> isinstance([],Iterator)
False
>>> isinstance((x for x in range(10)), Iterator)
True

迭代器Iterator表示的是一个数据流,可将数据流看做是一个有序队列,但不能提前知道队列的长度,只能通过next()函数实时按需计算下一个元素的值。

五、函数式编程

五、函数式编程

1. 高阶函数

函数名是指向函数的变量,对于函数abs(),可将abs函数名看做变量,它指向可以计算绝对值的函数。另外,函数本身可以赋值给其他变量:

澳门新萄京官方网站 88

>>> abs        # 调用求绝对值的函数10>>> abs             # abs是函数本身<built-in function abs>>>> f=abs           # 将函数本身赋值给变量>>> f<built-in function abs>>>> f          # 通过变量来调用函数。直接调用abs相同10

澳门新萄京官方网站 89

既然变量可以指向函数,函数的参数能接受变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称为高阶函数。函数式编程就是指这种高度抽象的编程范式。例如:

def add:    print   fadd(-5, 6, abs)     # f=abs 作为参数传入, 最后计算abs   abs输出:11

1. 高阶函数

函数名是指向函数的变量,对于函数abs(),可将abs函数名看做变量,它指向可以计算绝对值的函数。另外,函数本身可以赋值给其他变量:

澳门新萄京官方网站 90

>>> abs(-10)        # 调用求绝对值的函数
10
>>> abs             # abs是函数本身
<built-in function abs>
>>> f=abs           # 将函数本身赋值给变量
>>> f
<built-in function abs>
>>> f(-10)          # 通过变量来调用函数。直接调用abs()和调用变量f()相同
10

澳门新萄京官方网站 91

既然变量可以指向函数,函数的参数能接受变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称为高阶函数。函数式编程就是指这种高度抽象的编程范式。例如:

def add(x, y, f):
    print(f(x)   f(y))

add(-5, 6, abs)     # f=abs 作为参数传入, 最后计算abs(-5)   abs(6)

输出:11 

1.1 map/reduce

map()函数接收两个参数,第一个是函数,第二个是Iterable。map将函数作用与序列的每一个元素,并作为结果返回Iterator。举例如下:

# 第一个参数str是str()函数,将list中的每个数字转化为str>>> result = map(str, [1,2,3,4,5])  >>> isinstance(result, Iterator)True>>> list        # 结果是Iterator惰性序列,通过list()函数将其转化为list['1', '2', '3', '4', '5']

reduce()函数也接收两个参数,第一个是函数,第二个是Iterable。reduce将函数作用在序列上,将结果继续和序列的下一个元素做累积计算。效果就是:

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

举例如下:将[1,3,5,7,9]转化为13579

>>> from functools import reduce>>> def fn:...     return x * 10   y...>>> reduce(fn, [1,3,5,7,9])13579

map()可以与reduce()配合起来使用:实现将str转化为int,只需要几行代码

>>> DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}# str也是一个Iterable>>> reduce(lambda x, y:x*10   y, map(lambda x:DIGITS[x], '13579')) 13579

1.1 map/reduce

map()函数接收两个参数,第一个是函数,第二个是Iterable(可迭代对象)。map将函数作用与序列的每一个元素,并作为结果返回Iterator(迭代器)。举例如下:

# 第一个参数str是str()函数,将list中的每个数字转化为str
>>> result = map(str, [1,2,3,4,5])  
>>> isinstance(result, Iterator)
True
>>> list(result)        # 结果是Iterator惰性序列,通过list()函数将其转化为list
['1', '2', '3', '4', '5']

reduce()函数也接收两个参数,第一个是函数,第二个是Iterable。reduce将函数作用在序列上,将结果继续和序列的下一个元素做累积计算。效果就是: 

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

举例如下:将[1,3,5,7,9]转化为13579

>>> from functools import reduce
>>> def fn(x, y):
...     return x * 10   y
...
>>> reduce(fn, [1,3,5,7,9])
13579

map()可以与reduce()配合起来使用:实现将str转化为int,只需要几行代码

>>> DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
# str也是一个Iterable
>>> reduce(lambda x, y:x*10   y, map(lambda x:DIGITS[x], '13579')) 
13579

1.2 filter

filter()也接收一个函数和一个Iterable序列,将函数依次作用与序列中的每个元素,然后保留返回True的元素,丢弃返回False的元素,最终返回Iterator序列。通过help()了解filter的说明:

澳门新萄京官方网站 92

>>> helpHelp on class filter in module builtins:class filter |  filter(function or None, iterable) --> filter object | |  Return an iterator yielding those items of iterable for which function |  is true. If function is None, return the items that are true.

澳门新萄京官方网站 93

filter()主要是实现筛选功能。例如:筛选list中的奇数

>>> def is_odd:...     return n % 2 == 1...# filter返回Iterator序列,需要用list()来获取所有结果>>> list(filter(is_odd, [1,2,3,4,5]))   [1, 3, 5]

1.2 filter

filter()也接收一个函数和一个Iterable序列,将函数依次作用与序列中的每个元素,然后保留返回True的元素,丢弃返回False的元素,最终返回Iterator序列。通过help()了解filter的说明:

澳门新萄京官方网站 94

>>> help(filter)

Help on class filter in module builtins:

class filter(object)
 |  filter(function or None, iterable) --> filter object
 |
 |  Return an iterator yielding those items of iterable for which function(item)
 |  is true. If function is None, return the items that are true.

澳门新萄京官方网站 95

filter()主要是实现筛选功能。例如:筛选list中的奇数

>>> def is_odd(n):
...     return n % 2 == 1
...
# filter返回Iterator序列,需要用list()来获取所有结果
>>> list(filter(is_odd, [1,2,3,4,5]))   
[1, 3, 5]

1.3 sorted

sorted()函数可以对Iterable序列进行排序。默认是从小到大的升序,也可指定reverse=True改为从大到小。它还可以接受一个函数key来自定义排序方法:该函数会作用与序列的每一个元素,然后根据key函数返回的结果进行排序。

澳门新萄京官方网站 96

# 对list进行排序>>> sorted([1, -5, 3])      [-5, 1, 3]# 接收key函数实现自定义排序,按绝对值大小排序>>> sorted([1, -5, 3], key=abs)     [1, 3, -5]# 反向排序>>> sorted([1, -5, 3], key=abs, reverse=True)[-5, 3, 1]

澳门新萄京官方网站 97

1.3 sorted

sorted()函数可以对Iterable序列进行排序。默认是从小到大的升序,也可指定reverse=True改为从大到小。它还可以接受一个函数key来自定义排序方法:该函数会作用与序列的每一个元素,然后根据key函数返回的结果进行排序。

澳门新萄京官方网站 98

# 对list进行排序
>>> sorted([1, -5, 3])      
[-5, 1, 3]
# 接收key函数实现自定义排序,按绝对值大小排序
>>> sorted([1, -5, 3], key=abs)     
[1, 3, -5]
# 反向排序
>>> sorted([1, -5, 3], key=abs, reverse=True)
[-5, 3, 1]

澳门新萄京官方网站 99

2. 返回函数

高阶函数除了能将函数作为参数,还可将函数作为返回值。例如:

澳门新萄京官方网站 100

>>> def lazy_sum:...     def sum():...         s = 0...         for n in args:...             s = s   n...         return s...     return sum      # 返回求和函数...>>> f=lazy_sum(1,2,3,4,5)   # 调用lazy_sum时,返回求和函数而不是求和结果>>> f<function lazy_sum.<locals>.sum at 0x101c09ae8>>>> f()                 # 调用f()时,才会计算求和结果15

澳门新萄京官方网站 101

闭包:在上面的例子中,lazy_sum函数中定义了函数sum,内部sum函数可以引用外部函数lazy_sum的参数和局部变量。当lazy_sum返回sum时,相关参数和变量都保存在返回的sum函数中,这种成为闭包。返回闭包时候需要注意一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。

2. 返回函数

高阶函数除了能将函数作为参数,还可将函数作为返回值。例如:

澳门新萄京官方网站 102

>>> def lazy_sum(*args):
...     def sum():
...         s = 0
...         for n in args:
...             s = s   n
...         return s
...     return sum      # 返回求和函数
...
>>> f=lazy_sum(1,2,3,4,5)   # 调用lazy_sum时,返回求和函数而不是求和结果
>>> f
<function lazy_sum.<locals>.sum at 0x101c09ae8>
>>> f()                 # 调用f()时,才会计算求和结果
15

澳门新萄京官方网站 103

闭包:在上面的例子中,lazy_sum函数中定义了函数sum,内部sum函数可以引用外部函数lazy_sum的参数和局部变量(args)。当lazy_sum返回sum时,相关参数和变量(args)都保存在返回的sum函数中,这种成为闭包。返回闭包时候需要注意一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。

3. 匿名函数

我们在传入函数时,有时候不需要显式的定义函数,直接传入匿名函数更方便。关键字lambda表示匿名函数,例如:lambda x: x * x表示计算x的平方的函数,冒号前面的x表示函数参数,lambda只需要一个表达式,不需要写return,返回值就是表达式的值。

# map第一个参数为传入的函数>>> list(map(lambda x : x * x, [1,2,3]))[1, 4, 9]

3. 匿名函数

我们在传入函数时,有时候不需要显式的定义函数,直接传入匿名函数更方便。关键字lambda表示匿名函数,例如:lambda x: x * x表示计算x的平方的函数,冒号前面的x表示函数参数,lambda只需要一个表达式,不需要写return,返回值就是表达式的值。

# map第一个参数为传入的函数
>>> list(map(lambda x : x * x, [1,2,3]))
[1, 4, 9] 

4. 装饰器

装饰器:在代码运行期间动态的增加函数功能的方式称为装饰器。例如:有一个now()函数,希望在函数调用的前后打印日志,而又不修改函数的定义,从而增加now()函数的功能。

澳门新萄京官方网站 104

# 定义能打印日志的装饰器,接收一个函数作为参数,并返回一个函数import functoolsdef log:    # 将原始函数now的__name__等属性复制到wapper中,否则部分依赖函数签名的代码执行时会出错    @functools.wraps          def wapper(*args, **kw):        print("call %s" % func.__name__)        return func(*args, **kw)    return wapper# 使用@语法,将装饰器置于函数的定义处@logdef now():    print("2018-01-01")now()   # 调用now函数,不仅运行now本身,也会在now之前打印一行日志---call now2018-01-01

澳门新萄京官方网站 105

将@log放置在now函数定义处,相当于执行了now = log,log()是一个装饰器,返回一个函数,所以现在now指向了新的函数wapper()(即在log内定义的函数)。wapper函数的参数定义是*args, **kw,因此wapper可以接收任何参数。

4. 装饰器

装饰器:在代码运行期间动态的增加函数功能的方式称为装饰器。例如:有一个now()函数,希望在函数调用的前后打印日志,而又不修改函数的定义,从而增加now()函数的功能。

澳门新萄京官方网站 106

# 定义能打印日志的装饰器,接收一个函数作为参数,并返回一个函数
import functools

def log(func):
    # 将原始函数now的__name__等属性复制到wapper中,否则部分依赖函数签名的代码执行时会出错
    @functools.wraps(func)      
    def wapper(*args, **kw):
        print("call %s" % func.__name__)
        return func(*args, **kw)
    return wapper

# 使用@语法,将装饰器置于函数的定义处
@log
def now():
    print("2018-01-01")

now()   # 调用now函数,不仅运行now本身,也会在now之前打印一行日志

---
call now
2018-01-01

澳门新萄京官方网站 107

将@log放置在now函数定义处,相当于执行了now = log(now),log()是一个装饰器,返回一个函数,所以现在now指向了新的函数wapper()(即在log内定义的函数)。wapper函数的参数定义是*args, **kw,因此wapper可以接收任何参数。 

5. 偏函数

int()能将字符串转化为整数,默认是按10进制进行转化转换,还提供了额外的base参数来指定做N进制的转换。

>>> int123>>> int('123', base=8)  # 按8进制进行转换83

可以通过functional.partial帮我们创建一个偏函数,创建一个新的函数int2函数的base参数设置默认值,从而使用int2()函数转化2进制会更方便一些。注意:新的int2函数中base=2是默认值,也可以设置为其他值:

>>> import functools>>> int2=functools.partial(int, base=2)>>> int237>>> int2('100101',base=10)100101

5. 偏函数

int()能将字符串转化为整数,默认是按10进制进行转化转换,还提供了额外的base参数来指定做N进制的转换。

>>> int('123')
123
>>> int('123', base=8)  # 按8进制进行转换
83

可以通过functional.partial帮我们创建一个偏函数,创建一个新的函数int2(),将int()函数的base参数设置默认值,从而使用int2()函数转化2进制会更方便一些。注意:新的int2函数中base=2是默认值,也可以设置为其他值:

>>> import functools
>>> int2=functools.partial(int, base=2)
>>> int2('100101')
37
>>> int2('100101',base=10)
100101

六、模块

一个.py文件称为一个模块,使用模块提升了代码的可维护性,编写完一个模块,可以在其他模块引用。使用模块还能避免函数和变量名冲突,相同名字的函数和变量可以在不同的模块中。如果为了避免模块名冲突,python又按目录来组织模块的方法,称为

mycompany├─ __init__.py├─ abc.py└─ xyz.py

以上目录存放例子,mycompany是一个顶层包名,abc.py的模块名就是mycompany.abc。每个目下会有一个__init__.py文件,这个文件是必须的,否则python会将它看做是一个普通的目录,而不是一个包,init.py本身就是一个模块,模块名为mycompany。

自己创建模块时需要注意不要和系统自带的模块名冲突,例如,系统自带了sys模块,自己的模块就不能命名为sys.py。

使用python本身内置的模块,只需要import 模块名就可以了。例如:import sys,就导入了sys模块,变量sys就指向该模块,利用sys变量,就可以访问sys模块的所有功能。

六、模块

一个.py文件称为一个模块(module),使用模块提升了代码的可维护性,编写完一个模块,可以在其他模块引用。使用模块还能避免函数和变量名冲突,相同名字的函数和变量可以在不同的模块中。如果为了避免模块名冲突,python又按目录来组织模块的方法,称为包(package)

mycompany
├─ __init__.py
├─ abc.py
└─ xyz.py

以上目录存放例子,mycompany是一个顶层包名,abc.py的模块名就是mycompany.abc。每个目下会有一个__init__.py文件,这个文件是必须的,否则python会将它看做是一个普通的目录,而不是一个包,init.py本身就是一个模块,模块名为mycompany。

自己创建模块时需要注意不要和系统自带的模块名冲突,例如,系统自带了sys模块,自己的模块就不能命名为sys.py。

使用python本身内置的模块,只需要import 模块名就可以了。例如:import sys,就导入了sys模块,变量sys就指向该模块,利用sys变量,就可以访问sys模块的所有功能。 

七、面向对象编程

面向对象编程,简称OOP(Object Oriented Programming),是一种程序设计思想,将对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。python中,所有数据类型都可以视为对象,也可以自定义对象,自定义的对象数据类型就是类的概念。面向对象的三大特点:封装、继承、多态。

七、面向对象编程

面向对象编程,简称OOP(Object Oriented Programming),是一种程序设计思想,将对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。python中,所有数据类型都可以视为对象,也可以自定义对象,自定义的对象数据类型就是类(Class)的概念。面向对象的三大特点:封装、继承、多态。

1. 类和实例

类是抽象的模板,而实例是根据类创建出来的一个个具体的"对象",每个对象拥有相同的方法,而各自的数据不同。

澳门新萄京官方网站 108

# class关键字定义类,后面object表示Student是从object继承的,class Student:        # 通过定义特殊的__init__方法,在创建类时,将必须绑定的属性强制填写进去    # __init__第一个参数是self,表示实例本身,在内部将name和score属性绑定到self上    def __init__(self, name, score):        self.name = name        self.score = score    def print:        print("%s %s" % (self.name, self.score))# 创建Student实例,必须传入与__init__方法匹配的参数std = Student("name", 90)   # Student实例将name和score数据封装起来,通过调用实例的方法,操作对象的内部数据std.print()     

澳门新萄京官方网站 109

1. 类和实例

类(Class)是抽象的模板,而实例(Instance)是根据类创建出来的一个个具体的"对象",每个对象拥有相同的方法,而各自的数据不同。

澳门新萄京官方网站 110

# class关键字定义类,后面object表示Student是从object继承的,
class Student(object):

    # 通过定义特殊的__init__方法,在创建类时,将必须绑定的属性强制填写进去
    # __init__第一个参数是self,表示实例本身,在内部将name和score属性绑定到self上
    def __init__(self, name, score):
        self.name = name
        self.score = score

    def print(self):
        print("%s %s" % (self.name, self.score))

# 创建Student实例,必须传入与__init__方法匹配的参数
std = Student("name", 90)   
# Student实例将name和score数据封装起来,通过调用实例的方法,操作对象的内部数据
std.print()     

澳门新萄京官方网站 111

2. 访问限制

上例中,仍可以通过std.name来访问和修改实例的name属性。如果要将name和score内部属性设置为私有变量,可以在属性的名称前加两个下划线__,只有内部可以访问,外部不可以访问。如下:

class Student:    def __init__(self, name, score):        self.__name = name        self.__score = score    def print_score:        print("%s, %s" % (self.__name, self.__score))

变量名类似__xxx__,前后都有两个下划线的是特殊变量,特殊变量可以直接访问,不是private的。

2. 访问限制

上例中,仍可以通过std.name来访问和修改实例的name属性。如果要将name和score内部属性设置为私有变量(private),可以在属性的名称前加两个下划线__,只有内部可以访问,外部不可以访问。如下:

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

变量名类似__xxx__,前后都有两个下划线的是特殊变量,特殊变量可以直接访问,不是private的。

3. 继承与多态

定义一个新的class可以继承已有的class,从而获得父类的全部功能。例如:

澳门新萄京官方网站 112

class Animal:    def run:        print('animal run')# Cat类继承自Animal类class Cat:    # 将父类中的run方法覆写掉    def run:        print('cat run')

澳门新萄京官方网站 113

Cat类也可以覆写run方法,从而代码调用时,会调用子类的run方法。这样,我们会获得了多态

澳门新萄京官方网站 114

# 该函数接受Animal类型的变量>>> def run_twice:...     animal.run()...     animal.run()...>>> run_twice     # 当传入Animal对象时animal runanimal run>>> run_twice        # 当传入Cat对象时cat runcat run

澳门新萄京官方网站 115

对于传入的不同的Animal子类,run_twice()函数不需要做任何修改,只需要接受Animal类型就可以了。因为Cat等子类也算是Animal类型,然后可以按照Animal的类型进行操作,可以放心的调用run()方法,而具体的run()方法是作用在Animal、Cat对象上,由运行时该对象的确切类型决定。这就是多态的好处:

  • 对扩展开放:允许新增Animal的子类
  • 对修改封闭:不需要修改依赖Animal类型的run_twice()函数

静态语言 vs 动态语言:

  • 对于静态语言:如果需要传入Animal类型,则传入的对象必须是Animal类型或它的子类,否则将无法调用run()
  • 对于动态语言:则不一定需要传入Animal类型,只需要保证传入的对象有一个run()方法就行。

这就是动态语言的鸭子类型:不像静态语言那样要求严格的继承体系,一个对象"看起来像鸭子,走起路来像鸭子",那它就可以看做是鸭子。

3. 继承与多态

定义一个新的class可以继承已有的class,从而获得父类的全部功能。例如:

澳门新萄京官方网站 116

class Animal(object):
    def run(self):
        print('animal run')

# Cat类继承自Animal类
class Cat(Animal):
    # 将父类中的run方法覆写掉
    def run(self):
        print('cat run')

澳门新萄京官方网站 117

Cat类也可以覆写run方法,从而代码调用时,会调用子类的run方法。这样,我们会获得了多态

澳门新萄京官方网站 118

# 该函数接受Animal类型的变量
>>> def run_twice(animal):
...     animal.run()
...     animal.run()
...
>>> run_twice(Animal())     # 当传入Animal对象时
animal run
animal run
>>> run_twice(Cat())        # 当传入Cat对象时
cat run
cat run

澳门新萄京官方网站 119

对于传入的不同的Animal子类,run_twice()函数不需要做任何修改,只需要接受Animal类型就可以了。因为Cat等子类也算是Animal类型,然后可以按照Animal的类型进行操作,可以放心的调用run()方法,而具体的run()方法是作用在Animal、Cat对象上,由运行时该对象的确切类型决定。这就是多态的好处:

  • 对扩展开放:允许新增Animal的子类
  • 对修改封闭:不需要修改依赖Animal类型的run_twice()函数

静态语言 vs 动态语言:

  • 对于静态语言(例如Java):如果需要传入Animal类型,则传入的对象必须是Animal类型或它的子类,否则将无法调用run()
  • 对于动态语言(例如python):则不一定需要传入Animal类型,只需要保证传入的对象有一个run()方法就行。

这就是动态语言的鸭子类型:不像静态语言那样要求严格的继承体系,一个对象"看起来像鸭子,走起路来像鸭子",那它就可以看做是鸭子。

4. 获取对象信息

可以使用type()来判断对象的类型:

澳门新萄京官方网站 120

# 判断基本类型>>> type<class 'int'>>>> type<class 'str'># 如果一个变量指向一个类或函数>>> type<class '__main__.Cat'>>>> type<class 'builtin_function_or_method'>

澳门新萄京官方网站 121

type返回Class类型,可以比较两个type是否相同:

>>> type==typeTrue>>> type==strTrue>>> type==typeFalse

对类的继承关系,type不太好判断,可以使用instance()函数,告诉我们一个对象是否是该类型,或该类型的子类。例如:Cat类继承了Animal:

澳门新萄京官方网站 122

>>> a = Animal()>>> c = Cat()>>> isinstance(a, Animal)True>>> isinstance(c, Animal)True>>> isinstanceFalse# 判断基本类型>>> isinstanceTrue>>> isinstance('123', int)False

澳门新萄京官方网站 123

可以使用dir()获得一个对象的所有属性和方法,配合getattr()setattr()hasattr(),操作一个对象的状态:

澳门新萄京官方网站 124

>>> a = Animal()>>> dir['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'run']>>> hasattr         # 是否有'x'属性False>>> setattr(a, 'x', 10)     # 设置属性'x'>>> getattr         # 获取属性'x'10>>> fn = getattr  # 获取a对象的run方法,赋值到变量fn>>> fn()                    # fn是一样的animal run

澳门新萄京官方网站 125

4. 获取对象信息

可以使用type()来判断对象的类型:

澳门新萄京官方网站 126

# 判断基本类型
>>> type(123)
<class 'int'>
>>> type('123')
<class 'str'>

# 如果一个变量指向一个类或函数
>>> type(Cat())
<class '__main__.Cat'>
>>> type(abs)
<class 'builtin_function_or_method'>

澳门新萄京官方网站 127

type返回Class类型,可以比较两个type是否相同:

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

对类的继承关系,type不太好判断,可以使用instance()函数,告诉我们一个对象是否是该类型,或该类型的子类。例如:Cat类继承了Animal:

澳门新萄京官方网站 128

>>> a = Animal()
>>> c = Cat()
>>> isinstance(a, Animal)
True
>>> isinstance(c, Animal)
True
>>> isinstance(a, Cat)
False

# 判断基本类型
>>> isinstance(123, int)
True
>>> isinstance('123', int)
False

澳门新萄京官方网站 129

可以使用dir()获得一个对象的所有属性和方法,配合getattr()setattr()hasattr(),操作一个对象的状态:

澳门新萄京官方网站 130

>>> a = Animal()
>>> dir(a)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'run']
>>> hasattr(a, 'x')         # 是否有'x'属性
False
>>> setattr(a, 'x', 10)     # 设置属性'x'
>>> getattr(a, 'x')         # 获取属性'x'
10

>>> fn = getattr(a, 'run')  # 获取a对象的run方法,赋值到变量fn
>>> fn()                    # fn()与a.run()是一样的
animal run 

澳门新萄京官方网站 131

5. 实例属性和类属性

python是动态语言,根据类创建的实例可以任意绑定属性。给实例绑定属性时通过实例变量或self:

>>> a = Animal()>>> a.score = 123

如果直接在Animal类本身绑定一个属性,可在class中定义,这种属性时类属性

澳门新萄京官方网站 132

>>> class Animal:...     name = "name"...>>> a = Animal()>>> a.name      # 实例a没有name属性,会查找class的name属性'name'>>> Animal.name # 打印类的name属性'name'>>> a.name='name_object'    # 给实例a绑定name属性>>> a.name                  # 实例属性优先级比类属性高,所有屏蔽了类的name属性'name_object'

澳门新萄京官方网站 133

实例属性归各个实例所有,互不干扰。类属性属于类所有,所有实例共享一个类属性。不要对实例属性和类属性使用相同的名字,否则将发生难以发现的错误

5. 实例属性和类属性

python是动态语言,根据类创建的实例可以任意绑定属性。给实例绑定属性时通过实例变量或self:

>>> a = Animal()
>>> a.score = 123

如果直接在Animal类本身绑定一个属性,可在class中定义,这种属性时类属性

澳门新萄京官方网站 134

>>> class Animal(object):
...     name = "name"
...
>>> a = Animal()
>>> a.name      # 实例a没有name属性,会查找class的name属性
'name'
>>> Animal.name # 打印类的name属性
'name'
>>> a.name='name_object'    # 给实例a绑定name属性
>>> a.name                  # 实例属性优先级比类属性高,所有屏蔽了类的name属性
'name_object'

澳门新萄京官方网站 135

实例属性归各个实例所有,互不干扰。类属性属于类所有,所有实例共享一个类属性。不要对实例属性和类属性使用相同的名字,否则将发生难以发现的错误

八、面向对象高级编程

八、面向对象高级编程

1. 使用slots

在程序运行时可以动态给class绑定属性,但如果想限制实例的属性,例如只允许给Student类添加name或age属性,可以在提供定义class时,设置一个特殊的__slots__变量:

澳门新萄京官方网站 136

>>> class Student:...     __slots__=('name','age')    # 通过tuple设置允许绑定的属性明恒...>>> a = Student()>>> a.name="name"       # 绑定属性name>>> a.other=123         # 绑定属性other,不在__slots__定义中,出现错误Traceback (most recent call last):  File "<stdin>", line 1, in <module>AttributeError: 'Student' object has no attribute 'other'

澳门新萄京官方网站 137

other不在__slots__定义中,所以不能绑定other属性,得到AttributeError错误。__slots__定义的属性仅对当前实例起作用,对继承的子类不起作用。

1. 使用slots

在程序运行时可以动态给class绑定属性,但如果想限制实例的属性,例如只允许给Student类添加name或age属性,可以在提供定义class时,设置一个特殊的__slots__变量:

澳门新萄京官方网站 138

>>> class Student(object):
...     __slots__=('name','age')    # 通过tuple设置允许绑定的属性明恒
...
>>> a = Student()
>>> a.name="name"       # 绑定属性name
>>> a.other=123         # 绑定属性other,不在__slots__定义中,出现错误
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'other'

澳门新萄京官方网站 139

other不在__slots__定义中,所以不能绑定other属性,得到AttributeError错误。__slots__定义的属性仅对当前实例起作用,对继承的子类不起作用。

2. 使用@property

在java中,如果定义了一个属性,一般会实现这个属性的getter和setter方法。在python中,可以通过@property装饰器将方法变成属性调用,这样既能检查参数,又能用属性这样简单的方式来访问变量。

澳门新萄京官方网站 140

>>> class Student:...     @property   ...     def score:...         return self._score......     @score.setter...     def score(self, value):...         if not isinstance(value,int):...             raise ValueError('score must be integer')...         if value > 100 or value < 0:...             raise ValueError('score must between 0-100')...         self._score=value>>> s = Student()>>> s.score=-1Traceback (most recent call last):  File "<stdin>", line 1, in <module>  File "<stdin>", line 10, in scoreValueError: score must between 0-100>>> s.score=10      # 实际转化为s.set_score>>> s.score         # 实际转化为s.get_score()10

澳门新萄京官方网站 141

@property将getter方法变成属性,此时@property本身又创建了@score.setter装饰器,负责将setter方法变为属性赋值,于是可以对score进行属性操作。如果只定义了getter方法,没有定义setter方法,那么就是只读属性。通过@property可以让调用者写出简洁的代码,同时保证了参数的校验。

2. 使用@property

在java中,如果定义了一个属性,一般会实现这个属性的getter和setter方法。在python中,可以通过@property装饰器将方法变成属性调用,这样既能检查参数,又能用属性这样简单的方式来访问变量。

澳门新萄京官方网站 142

>>> class Student(object):
...     @property   
...     def score(self):
...         return self._score
...
...     @score.setter
...     def score(self, value):
...         if not isinstance(value,int):
...             raise ValueError('score must be integer')
...         if value > 100 or value < 0:
...             raise ValueError('score must between 0-100')
...         self._score=value

>>> s = Student()
>>> s.score=-1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 10, in score
ValueError: score must between 0-100
>>> s.score=10      # 实际转化为s.set_score(10)
>>> s.score         # 实际转化为s.get_score()
10

澳门新萄京官方网站 143

@property将getter方法变成属性,此时@property本身又创建了@score.setter装饰器,负责将setter方法变为属性赋值,于是可以对score进行属性操作。如果只定义了getter方法,没有定义setter方法,那么就是只读属性。通过@property可以让调用者写出简洁的代码,同时保证了参数的校验。

3. 多重继承

设计类的继承关系时,通常主线都是单一继承下来的,如果需要加入额外的功能,通过多重继承就可以实现,这种设计称为MixIn,例如:让Dog除了继承Animal,同时继承Runnable,为了更好的看出继承关系,一般将Runnable改为RunnableMixIn:

class Dog(Animal, RunnableMixIn):    pass

设计类的时候,我们优先考虑多重继承来组合多个MixIn的功能,可快速构造所需的子类。

3. 多重继承

设计类的继承关系时,通常主线都是单一继承下来的,如果需要加入额外的功能,通过多重继承就可以实现,这种设计称为MixIn,例如:让Dog除了继承Animal,同时继承Runnable,为了更好的看出继承关系,一般将Runnable改为RunnableMixIn:

class Dog(Animal, RunnableMixIn):
    pass

设计类的时候,我们优先考虑多重继承来组合多个MixIn的功能,可快速构造所需的子类。

4. 定制类

python中有许多特殊用途的函数可以帮助我们定制类。
__str__():打印对象时,自定义返回的字符串

澳门新萄京官方网站 144

>>> class Student:...     def __init__(self,name):...         self.name = name...     def __str__:...         return 'student object ' % self.name...>>> print(Studentstudent object (name:apple)

澳门新萄京官方网站 145

__iter__:如果一个类想用于for...in,类似list或tuple,就需要实现__iter__()方法,该对象返回一个迭代对象,然后for循环会不断调用迭代对象的__next__()方法拿到下一个值,直至遇到StopIteration时退出循环。例如,for循环迭代菲波那切数列:

澳门新萄京官方网站 146

>>> class Fib:...     def __init__:...         self.a, self.b = 0, 1   # 初始化计数器 a,b...     def __iter__:...         return self             # 返回迭代对象自己...     def __next__:...         self.a, self.b = self.b, self.a   self.b    # 计算下一个值...         if self.a > 100:        # 退出循环的条件...             raise StopIteration()...         return self.a           # 返回下一个值...>>> for n in Fib():...     print

澳门新萄京官方网站 147

__getitem__:上面Fib()可像list一样用于for循环,如果想像list那样按下标取元素,需要实现__getitem__()方法。与之对应的是__setitem__()方法,把对象视作list来对集合赋值,__delitem__(),用于删除某个元素。

__getattr_:当调用类的方法或属性时,如果不存在会报错。没有找到属性的情况下,会调用__getattr__,该方法可把一个类的所有属性和方法全都动态化处理。例如:

澳门新萄京官方网站 148

>>> class Student:...     def __getattr__(self, attr):...         if attr=='age':...             return 18...         if attr=='name':...             return lambda:'name'...>>> stu.name()'name'>>> stu.age18

澳门新萄京官方网站 149

4. 定制类

python中有许多特殊用途的函数可以帮助我们定制类。 
__str__():打印对象时,自定义返回的字符串

澳门新萄京官方网站 150

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

澳门新萄京官方网站 151

__iter__:如果一个类想用于for...in,类似list或tuple,就需要实现__iter__()方法,该对象返回一个迭代对象,然后for循环会不断调用迭代对象的__next__()方法拿到下一个值,直至遇到StopIteration时退出循环。例如,for循环迭代菲波那切数列:

澳门新萄京官方网站 152

>>> class Fib(object):
...     def __init__(self):
...         self.a, self.b = 0, 1   # 初始化计数器 a,b

...     def __iter__(self):
...         return self             # 返回迭代对象自己

...     def __next__(self):
...         self.a, self.b = self.b, self.a   self.b    # 计算下一个值
...         if self.a > 100:        # 退出循环的条件
...             raise StopIteration()
...         return self.a           # 返回下一个值
...
>>> for n in Fib():
...     print(n)

澳门新萄京官方网站 153

__getitem__:上面Fib()可像list一样用于for循环,如果想像list那样按下标取元素,需要实现__getitem__()方法。与之对应的是__setitem__()方法,把对象视作list来对集合赋值,__delitem__(),用于删除某个元素。

__getattr_:当调用类的方法或属性时,如果不存在会报错。没有找到属性的情况下,会调用__getattr__,该方法可把一个类的所有属性和方法全都动态化处理。例如:

澳门新萄京官方网站 154

>>> class Student(object):
...     def __getattr__(self, attr):
...         if attr=='age':
...             return 18
...         if attr=='name':
...             return lambda:'name'
...
>>> stu.name()
'name'
>>> stu.age
18 

澳门新萄京官方网站 155

5. 使用枚举类

通过Enum类能实现枚举功能。

澳门新萄京官方网站 156

>>> from enum import Enum>>> Sex=Enum('Sex', ('Male', 'Female'))     # 获得Sex类型的枚举类>>> for name, member in Sex.__members__.items():    # Sex所有成员...     print(name, '->', member, '->', member.value)...# value属性从1开始自动赋值给枚举成员Male -> Sex.Male -> 1Female -> Sex.Female -> 2

澳门新萄京官方网站 157

如果要更精确的控制枚举类型,可以从Enum中派生自定义类:

澳门新萄京官方网站 158

>>> from enum import Enum, unique>>>>>> @unique     # unique装饰器检查没有重复值... class Sex:...     Male=10     # 自定义设置value...     Female=20# 使用枚举类型>>> print Sex.Male>>> print(Sex.Male.value)10>>> print      # 根据value值获取枚举常量Sex.Male

澳门新萄京官方网站 159

5. 使用枚举类

通过Enum类能实现枚举功能。

澳门新萄京官方网站 160

>>> from enum import Enum
>>> Sex=Enum('Sex', ('Male', 'Female'))     # 获得Sex类型的枚举类

>>> for name, member in Sex.__members__.items():    # Sex所有成员
...     print(name, '->', member, '->', member.value)
...
# value属性从1开始自动赋值给枚举成员
Male -> Sex.Male -> 1
Female -> Sex.Female -> 2

澳门新萄京官方网站 161

如果要更精确的控制枚举类型,可以从Enum中派生自定义类:

澳门新萄京官方网站 162

>>> from enum import Enum, unique
>>>
>>> @unique     # unique装饰器检查没有重复值
... class Sex(Enum):
...     Male=10     # 自定义设置value
...     Female=20

# 使用枚举类型
>>> print(Sex.Male) 
Sex.Male
>>> print(Sex.Male.value)
10
>>> print(Sex(10))      # 根据value值获取枚举常量
Sex.Male 

澳门新萄京官方网站 163

九、错误处理

一般语言的错误处理机制类似:try...except...finally...,大致实现如下:

try:    运行代码...except ValueError as e:    # try中代码如果出错,会跳转至except语句块处理对应的异常finally:    # 执行完except后,最终会到finally语句块(不出现错误,也会执行finally)

错误也是一个class,所有错误类型基本继承自BaseException,在使用except时,也会将错误的子类一起捕获。如果错误没有被捕获,那么会按调用栈一层层往上抛,最终被python解释器捕获并打印错误日志,然后程序退出,所以我们捕获错误时,可以将错误堆栈打印出来,这样便于分析错误原因,同时也能让程序继续下去。

我们编写函数时,也可以通过raise主动抛出错误:

def foo:    n = int    if n==0:        raise ValueError('invalid value: %s' % s)    return 10 / n

九、错误处理

一般语言的错误处理机制类似:try...except...finally...,大致实现如下:

try:
    运行代码...
except ValueError as e:
    # try中代码如果出错,会跳转至except语句块处理对应的异常
finally:
    # 执行完except后,最终会到finally语句块(不出现错误,也会执行finally)

错误也是一个class,所有错误类型基本继承自BaseException,在使用except时,也会将错误的子类一起捕获。如果错误没有被捕获,那么会按调用栈一层层往上抛,最终被python解释器捕获并打印错误日志,然后程序退出,所以我们捕获错误时,可以将错误堆栈打印出来,这样便于分析错误原因,同时也能让程序继续下去。

我们编写函数时,也可以通过raise主动抛出错误:

def foo(s):
    n = int(s)
    if n==0:
        raise ValueError('invalid value: %s' % s)
    return 10 / n 

十、IO编程

IO即指Input/Output,IO中,Stream流是一个重要的概念,可理解为一个一个水管,数据就是水管里的水,只能单向流动

  • Input Stream 就是数据从外面流进内存
  • Output Stream 就是数据从内存流到外面

十、IO编程

IO即指Input/Output,IO中,Stream流是一个重要的概念,可理解为一个一个水管,数据就是水管里的水,只能单向流动

  • Input Stream 就是数据从外面(磁盘、网络)流进内存
  • Output Stream 就是数据从内存流到外面

1. 文件读写

读写文件就是请求OS打开一个文件对象,然后通过OS提供的接口从文件对象中读写数据。

读文件:

澳门新萄京官方网站 164

>>> try:        # 以读文件方式打开文件对象,如果文件不存在,会抛出IOError错误...     f = open('/Users/butterfly/test.txt', 'r')  ...     print     # 一次读取文件的全部内容到内存中... finally:...     if f:        # 最终,要关闭文件,文件使用后必须关闭,因为文件对象会占用OS的资源,并且OS同一时间打开的文件数量是有限制的...        f.close()        

澳门新萄京官方网站 165

使用try...finally比较繁琐,可使用with简化,会自动调用close方法:

>>> with open('/Users/zhangqi/test.txt', 'r') as f:...     print

读文件时,可以通过read指定每次最多读取size个字节内容。readline()每次读取一行内容。读取二进制文件时,可以指定rb模式打开文件。open()方法可以通过encoding参数指定读取文件的编码方式,errors指定读取出现错误时如何处理:

>>> f = open('/Users/michael/gbk.txt', 'r', encoding='gbk', errors='ignore')

写文件:

>>> with open('/Users/zhangqi/test.txt', 'w') as f:...     f.write('hello world')

写文件与读文件唯一区别在于,传入标识符w或者wb表示写文本文件或二进制文件。当写文件时,OS往往不会立即把数据写入磁盘,而是缓存在内存中,在空闲时候再慢慢写入,只有调用close()时,OS才保证将没写入的数据写入到磁盘。所以需要with来保证最后会close。

此外,可以给open()方法传入encoding参数将字符串转换为指定编码,w模式写文件会覆盖已有文件,如果想追加内容到文件末尾,可以传入a以追加模式写入。

1. 文件读写

读写文件就是请求OS打开一个文件对象(成为文件描述符),然后通过OS提供的接口从文件对象中读写数据。

读文件:

澳门新萄京官方网站 166

>>> try:
        # 以读文件方式打开文件对象,如果文件不存在,会抛出IOError错误
...     f = open('/Users/butterfly/test.txt', 'r')  
...     print(f.read())     # 一次读取文件的全部内容到内存中
... finally:
...     if f:
        # 最终,要关闭文件,文件使用后必须关闭,因为文件对象会占用OS的资源,并且OS同一时间打开的文件数量是有限制的
...        f.close()        

澳门新萄京官方网站 167

使用try...finally比较繁琐,可使用with简化,会自动调用close方法:

>>> with open('/Users/zhangqi/test.txt', 'r') as f:
...     print(f.read())

读文件时,可以通过read(size)指定每次最多读取size个字节内容。readline()每次读取一行内容。读取二进制文件时,可以指定rb模式打开文件。open()方法可以通过encoding参数指定读取文件的编码方式,errors指定读取出现错误时如何处理:

>>> f = open('/Users/michael/gbk.txt', 'r', encoding='gbk', errors='ignore')

写文件:

>>> with open('/Users/zhangqi/test.txt', 'w') as f:
...     f.write('hello world')

写文件与读文件唯一区别在于,传入标识符w或者wb表示写文本文件或二进制文件。当写文件时,OS往往不会立即把数据写入磁盘,而是缓存在内存中,在空闲时候再慢慢写入,只有调用close()时,OS才保证将没写入的数据写入到磁盘。所以需要with来保证最后会close。

此外,可以给open()方法传入encoding参数将字符串转换为指定编码,w模式写文件会覆盖已有文件,如果想追加内容到文件末尾,可以传入a以追加(append)模式写入。

2. StirngIO和BytesIO

StringIO可实现在内存中读写str。写str到StringIO:

澳门新萄京官方网站 168

>>> from io import StringIO>>> f = StringIO()>>> f.write('hellonworldn')   # 像文件一样写入12>>> print(f.getvalue         # 获取写入后的strhelloworld

澳门新萄京官方网站 169

操作二进制数据,就需要使用BytesIO:

>>> from io import BytesIO>>> f = BytesIO()>>> f.write('中文'.encode     # 写入经过utf-8编码的bytes到BytesIO6>>> print(f.getvalueb'xe4xb8xadxe6x96x87'

2. StirngIO和BytesIO

StringIO可实现在内存中读写str。写str到StringIO:

澳门新萄京官方网站 170

>>> from io import StringIO
>>> f = StringIO()
>>> f.write('hellonworldn')   # 像文件一样写入
12
>>> print(f.getvalue())         # 获取写入后的str
hello
world

澳门新萄京官方网站 171

操作二进制数据,就需要使用BytesIO:

>>> from io import BytesIO
>>> f = BytesIO()
>>> f.write('中文'.encode('utf-8'))     # 写入经过utf-8编码的bytes到BytesIO
6
>>> print(f.getvalue())
b'xe4xb8xadxe6x96x87' 

3.操作文件和目录

os模块封装了操作系统的目录和文件操作,在内部调用了操作系统提供的接口函数。下面是一些常用方法:

澳门新萄京官方网站 172

# 环境变量>>> import os>>> os.environ      # 查看操作系统中定义的环境变量>>> os.environ.get      # 获取某个环境变量中的值# 目录操作>>> os.path.abspath        # 查看当前目录的绝对路径>>> os.mkdir('/Users/michael/testdir')   # 创建一个新目录>>> os.rmdir('/Users/michael/testdir')   # 删除一个目录 # 将路径拆分为两部分,后一部分是最后级别的目录或文件名>>> os.path.split('/Users/michael/testdir/file.txt')    ('/Users/michael/testdir', 'file.txt')# 通过splitext可直接获得文件的扩展名>>> os.path.splitext('/path/to/file.txt')('/path/to/file', '.txt')# 文件操作>>> os.rename('test.txt', 'test.py')    # 对文件重命名>>> os.remove('test.py')                # 删除文件# 可方便的列举当前目录下的.py文件>>> [x for x in os.listdir if os.path.isfile and os.path.splitext[1]=='.py']

澳门新萄京官方网站 173

3.操作文件和目录

os模块封装了操作系统的目录和文件操作,在内部调用了操作系统提供的接口函数。下面是一些常用方法:

澳门新萄京官方网站 174

# 环境变量
>>> import os
>>> os.environ      # 查看操作系统中定义的环境变量
>>> os.environ.get('PATH')      # 获取某个环境变量中的值

# 目录操作
>>> os.path.abspath('.')        # 查看当前目录的绝对路径
>>> os.mkdir('/Users/michael/testdir')   # 创建一个新目录
>>> os.rmdir('/Users/michael/testdir')   # 删除一个目录 
# 将路径拆分为两部分,后一部分是最后级别的目录或文件名
>>> os.path.split('/Users/michael/testdir/file.txt')    
('/Users/michael/testdir', 'file.txt')
# 通过splitext可直接获得文件的扩展名
>>> os.path.splitext('/path/to/file.txt')
('/path/to/file', '.txt')

# 文件操作
>>> os.rename('test.txt', 'test.py')    # 对文件重命名
>>> os.remove('test.py')                # 删除文件

# 可方便的列举当前目录下的.py文件
>>> [x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py'] 

澳门新萄京官方网站 175

基础,python python基础 # 是注释。通过空格进行缩进,当一行语句以 : 结尾时,缩进的语句视为一段代码块。按约定俗成的规范,使用...

本文由澳门新萄京官方网站发布于www.8455.com,转载请注明出处:澳门新萄京官方网站:python的根底三,一等目的

关键词: