import math mList = ['Tom','Joy','Mal'] mTuple = (1,2,'Tom') mDict = {'Tom':99,'Joy':88,'Mal':77} mSet = set([1,2,3]) mStr = 'ABCD' mInt = int(123) mGenerator = (x * x for x in range(1,10)) # def p(*x): # for s in x: # print(s) p = print r''' print('hello world')
#如果要定义一个空的tuple,可以写成(): t = () print(t) #定义一个元素 t = (1) print(t) #定义的不是tuple,是1这个数!这是因为括号()既可以表示tuple,又可以表示数学公式中的小括号,这就产生了歧义, #因此,Python规定,这种情况下,按小括号进行计算,计算结果自然是1。 #所以,只有1个元素的tuple定义时必须加一个逗号,,来消除歧义 t = (1,) print(t) ##可变的tuple t = ('a', 'b',['A', 'B']) t[2][0] = 'X' t[2][1] = 'Y' print(t) #表面上看,tuple的元素确实变了,但其实变的不是tuple的元素,而是list的元素。 #tuple一开始指向的list并没有改成别的list,所以,tuple所谓的“不变”是说,tuple的每个元素,指向永远不变。 #即指向'a',就不能改成指向'b',指向一个list,就不能改成指向其他对象,但指向的这个list本身是可变的! '''
#条件判断 r''' temp = input('输入你的年龄吧:\n') age = int(temp) if age<16: print('你是小学生吗?') print('你真的不是小学生吗?') elif age<30: print('小伙子要努力工作啦!') print('我会的啦') else: print('生活什么的才是最重要的啦') '''
#循环 r''' names = ['Tom','Joy','Mal'] for x in names: print(x) print('-------------------------------') for x in names: if x == 'Tom': print(x) #如果要计算1-100的整数之和,从1写到100有点困难,幸好Python提供一个range()函数,可以生成一个整数序列, #再通过list()函数可以转换为list。比如range(5)生成的序列是从0开始小于5的整数 temp = list(range(5)) print(temp) #range(101)就可以生成0-100的整数序列,计算如下 sum = 0 for x in range(101): sum = sum + x print(sum) #第二种循环是while循环,只要条件满足,就不断循环,条件不满足时退出循环。 sum = 0 n = 1 while n<99: sum = sum + n n = n +2 print(sum) '''
def power(x, n): s = 1 while n > 0: n = n - 1 s = s * x return s ''' #修改后的power(x, n)函数有两个参数:x和n,这两个参数都是位置参数,调用函数时,传入的两个值按照位置顺序依次赋给参数x和n。 #默认参数 #新的power(x, n)函数定义没有问题,但是,旧的调用代码失败了,原因是我们增加了一个参数,导致旧的代码因为缺少一个参数而无法正常调用 #这个时候,默认参数就排上用场了。由于我们经常计算x2,所以,完全可以把第二个参数n的默认值设定为2: r''' def power(x, n=2): s = 1 while n > 0: n = n - 1 s = s * x return s ''' #这样,当我们调用power(5)时,相当于调用power(5, 2) # #先定义一个函数,传入一个list,添加一个END再返回: r''' def add_end(L=[]): L.append('END') return L ''' r''' #当你正常调用时,结果似乎不错: add_end([1, 2, 3]) #[1, 2, 3, 'END'] #当你使用默认参数调用时,一开始结果也是对的: add_end() #['END'] #但是,再次调用add_end()时,结果就不对了: add_end() #['END', 'END'] ''' #所以,定义默认参数要牢记一点:默认参数必须指向不变对象! #要修改上面的例子,我们可以用None这个不变对象来实现: r''' def add_end(L=None): if L is None: L = [] L.append('END') return L '''
#可变参数 #在Python函数中,还可以定义可变参数。顾名思义,可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个 #要定义出这个函数,我们必须确定输入的参数。由于参数个数不确定,我们首先想到可以把a,b,c……作为一个list或tuple传进来, r''' def calc(numbers): sum = 0 for x in numbers: sum = sum + x*x return sum calc([1,2,3]) ''' #但是调用的时候,需要先组装出一个list或tuple #所以,我们把函数的参数改为可变参数: r''' def calc(*numbers): sum = 0 for n in numbers: sum = sum + n * n return sum calc(1,2,3) #如果已经有一个list或者tuple,要调用一个可变参数怎么办? nums = [1, 2, 3] calc(*nums) '''
#迭代 for x in mList: print(x) for x in mStr: print(x) from collections import Iterable print(isinstance('abc', Iterable)) # str是否可迭代 #同时引用了两个变量,在Python里是很常见的 for x, y in [(1, 1), (2, 4), (3, 9)]: print(x, y) #Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身 for i,value in enumerate(mList): print(i,value)
#列表生产式 #列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。 l = [] for x in range(1,10): l.append(x) print(l) #2 l = [] for x in range(1,10): l.append(x*x) print(l) #3 l = [x*x for x in range(1,10)] print(l) #4 包含if判断 l = [x*x for x in range(1,10) if x % 2 == 0 ] print(l) #5 双层循环 l=[m + n for m in'ABC'for n in'abc'] print(l) #6 运用列表生成式,可以写出非常简洁的代码。例如,列出当前目录下的所有文件和目录名,可以通过一行代码实现 import os #导入os模块 l = [d for d in os.listdir('.')] # os.listdir可以列出文件和目录 #7for循环其实可以同时使用两个甚至多个变量,比如dict的items()可以同时迭代key和value: for k,v in mDict.items(): print(k,'=',v)
#所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢? #这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。 #要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator l = [x * x for x in range(1,10)] #list g = (x * x for x in range(1,10)) #generator #一个一个打印出来,可以通过next()函数获得generator的下一个返回值 print(next(mGenerator)) for x in mGenerator: print(x) #如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。 deffib(max): n, a, b = 0, 0, 1 while n<max: print(b) a, b = b, a + b n = n + 1 return'done' #上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了 deffib(max): n, a, b = 0, 0, 1 while n<max: yield b a, b = b, a + b n = n + 1 return'done' #这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。 #而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。 defodd(): print('step 1') yield1 print('step 2') yield(3) print('step 3') yield(3) o = odd() print(next(o),next(o),next(o)) #但是用for循环调用generator时,发现拿不到generator的return语句的返回值。 #如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中 g = fib(6) whileTrue: try: x = next(g) print('g:', x) except StopIteration as e: print('Generator return value:', e.value) break
#迭代器 #我们已经知道,可以直接作用于for循环的数据类型有以下几种: #一类是集合数据类型,如list、tuple、dict、set、str等; #一类是generator,包括生成器和带yield的generator function。 #这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。 #可以使用isinstance()判断一个对象是否是Iterable对象: from collections import Iterable print(isinstance([], Iterable),isinstance(mList,Iterable),isinstance(mStr,Iterable),isinstance(mInt,Iterable)) from collections import Iterator print(isinstance((x for x in range(10)), Iterator)) print(isinstance([], Iterator),isinstance(mList,Iterator),isinstance(mStr,Iterator),isinstance(mInt,Iterator)) #生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。 #把list、dict、str等Iterable变成Iterator可以使用iter()函数 print(isinstance(iter([]), Iterator)) #这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据, #直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度, #只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。 #Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
#如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改, #已绑定到函数参数的值不变: defcount(): deff(j): defg(): return j*j return g fs = [] for i in range(1, 4): fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f() return fs f1, f2, f3 = count() print(f1(), f2(), f3()) #缺点是代码较长,可利用lambda函数缩短代码。
#匿名函数 #当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便。 #在Python中,对匿名函数提供了有限支持。还是以map()函数为例,计算f(x)=x*x时,除了定义一个f(x)的函数外,还可以直接传入匿名函数 print(list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))) #[1, 4, 9, 16, 25, 36, 49, 64, 81] #通过对比可以看出,匿名函数lambda x: x * x实际上就是: deff(x): return x * x #关键字lambda表示匿名函数,冒号前面的x表示函数参数。
#匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。
#用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象, #也可以把匿名函数赋值给一个变量,再利用变量来调用该函数: f = lambda x: x * x print(f(5)) #同样,也可以把匿名函数作为返回值返回 defbuild(x, y): returnlambda: x * x + y * y
#装饰器 #由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。 defnow(): print('2016-01-26') f = now f() #函数对象有一个__name__属性,可以拿到函数的名字: print(now.__name__,f.__name__) #现在,假设我们要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义, #这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
defset_score(self, value): ifnot isinstance(value, int): raise ValueError('score must be an integer!') if value < 0or value > 100: raise ValueError('score must between 0 ~ 100!') self._score = value s = Student() s.set_score(60) # ok! p(s.get_score())
@score.setter defscore(self, value): ifnot isinstance(value, int): raise ValueError('score must be an integer!') if value < 0or value > 100: raise ValueError('score must between 0 ~ 100!') self._score = value #@property的实现比较复杂,我们先考察如何使用。把一个getter方法变成属性,只需要加上@property就可以了, #此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值,于是,我们就拥有一个可控的属性操作 s = Student() s.score = 70# ok! p(s.score)
#多重继承 # Dog - 狗狗; # Bat - 蝙蝠; # Parrot - 鹦鹉; # Ostrich - 鸵鸟。 classRunnable(object): defrun(self): print('Running...')
def__next__(self): self.a, self.b = self.b, self.a + self.b # 计算下一个值 if self.a > 100000: # 退出循环的条件 raise StopIteration(); return self.a # 返回下一个值 def__getitem__(self, n): a, b = 1, 1 for x in range(n): a, b = b, a + b return a def__getattr__(self, attr): if attr=='score': return99 if attr=='age': returnlambda: 25 raise AttributeError('\'Student\' object has no attribute \'%s\'' % attr) #要让class只响应特定的几个属性,抛出AttributeError的错误:
# 任何类,只需要定义一个__call__()方法,就可以直接对实例进行调用。请看示例: classStudent(object): def__init__(self, name): self.name = name
def__call__(self): print('My name is %s.' % self.name)
s = Student('Michael') s()
#使用枚举类 #当我们需要定义常量时,一个办法是用大写变量通过整数来定义,例如月份: JAN = 1 FEB = 2 MAR = 3 NOV = 11 DEC = 12 #更好的方法是为这样的枚举类型定义一个class类型,然后,每个常量都是class的一个唯一实例。Python提供了Enum类来实现这个功能: from enum import Enum
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')) #这样我们就获得了Month类型的枚举类,可以直接使用Month.Jan来引用一个常量,或者枚举它的所有成员: for name, member in Month.__members__.items(): print(name, '=>', member, ',', member.value)
defmain(): try: bar('0') except Exception as e: logging.exception(e)
main() print('END') # 样是出错,但程序打印完错误信息后会继续执行,并正常退出: # ERROR:root:division by zero # Traceback (most recent call last): # File "err_logging.py", line 13, in main # bar('0') # File "err_logging.py", line 9, in bar # return foo(s) * 2 # File "err_logging.py", line 6, in foo # return 10 / int(s) # ZeroDivisionError: division by zero # END
# Python既支持多进程,又支持多线程,我们会讨论如何编写这两种多任务程序。 # import os
# print('Process (%s) start...' % os.getpid()) # # Only works on Unix/Linux/Mac: # pid = os.fork() # if pid == 0: # print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid())) # else: # print('I (%s) just created a child process (%s).' % (os.getpid(), pid)) # 运行结果如下:
# Process (876) start... # I (876) just created a child process (877). # I am child process (877) and my parent is 876. # 由于Windows没有fork调用,上面的代码在Windows上无法运行。由于Mac系统是基于BSD(Unix的一种)内核,所以,在Mac下运行是没有问题的,推荐大家用Mac学Python!
# multiprocessing模块提供了一个Process类来代表一个进程对象,下面的例子演示了启动一个子进程并等待其结束 from multiprocessing import Process import os # 子进程要执行的代码 defrun_proc(name): print('Run Child process name %s(%s)...' %(name, os.getpid())) if __name__ == '__main__': print('Parent Process %s' %os.getpid()) p = Process(target=run_proc, args = ('test',)) print('Child Process Will start...') p.start() p.join() print('Child Process END...')
from multiprocessing import Pool import os, time, random deflong_time_task(name): print("RUn task %s(%s)" %(name, os.getpid())) start = time.time() time.sleep(random.random() * 3) end = time.time() print('Task Run %.3f seconds.' %(name, (end - start))) if __name__=='__main__': print('Parent process %s.' %os.getpid()) pool = Pool(4) for x in range(5): pool.apply_async(long_time_task, args=(x,)) print('Waiting for all subprocess done.') pool.close() pool.join() print('All subprocess done.') # # 对Pool对象调用join()方法会等待所有子进程执行完毕,调用join()之前必须先调用close(),调用close()之后就不能继续添加新的Process了。