最近毕业设计题目是研究对抗样本,要用tensorflow来搭建神经网络,因此python必不可少,这个不是一个传统的Python学习教程只是把学习Python过程中遇到的问题和经验记录下来(基于Python3.5),如果想要一步一步学习Python建议看下面的网站。
Python学习教程
Python中的迭代
只要是可迭代对象,无论是否有下标,都可以迭代,例如dict:
# -*- coding: utf-8 -*-
dict = {'a':1, 'b':2,'c':3}
# 默认情况下dict迭代的是key, dict存储不是按照list存储, 所以迭代的结果很可能不一样
for key in dict:
print(key)
# 迭代value
for value in dict.values():
print(value)
# 迭代value和key
for key,value in dict.items():
print(key, value)
判断一个类型是否可以迭代
# 判断一个类型是否可以迭代
from collections import Iterable
print(isinstance('abc', Iterable))
print(isinstance([1, 2, 3], Iterable))
print (isinstance(123, Iterable))
对list实现类似Java的下标循环,让其变成索引元素对
l = ['a', 'b', 'd', 'e']
for index, value in enumerate(l):
print(index, value)
列表生成式即List Comprehensions, 可以用来创建list的生成式
print (list(range(1, 11)))
print ([x*x for x in range(1, 11)])
# 生成全排列
print ([m+n for m in 'ABC' for n in 'DEF'])
# 列出当前目录下的所有文件和目录名
import os
print([d for d in os.listdir('.')])
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含几百万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。从下面可以看出生成式g有点神似指针。。。
# 生成式
g = (x*x for x in range(1, 11))
print(g)
# output: <generator object <genexpr> at 0x7f2518e03910>
print(next(g))
# output: 1
print(next(g))
# output: 4
for i in g:
print(i)
# !注意输出为9, 16, ...
# 利用yield产生斐波那契数列
def fib(n):
i, a, b = 0, 0, 1
while i < n:
yield b
a, b = b, a+b
i = i + 1
return 'done'
f = fib(6)
for i in f:
print(i)
可以直接作用于for循环的数据类型有以下几种:
- 一类是集合数据类型,如list、tuple、dict、set、str等
- 一类是generator,包括生成器和带yield的generator function
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable
from collections import Iterable
# 使用isinstance判断一个对象是否是Iterable对象
print(isinstance([], Iterable))
# output: True
print(isinstance((), Iterable))
# output: True
print(isinstance('abc', Iterable))
# output: True
print(isinstance((x*x for x in range(10)), Iterable))
# output: True
print(isinstance(100,Iterable))
# output: False
Iterator对象:生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到抛出stopIteration
错误表示无法继续获取下一个值。可以被next()函数调用并且不断返回下一个值的对象叫做迭代器,可以使用isinstance()
判断一个对象是否是Iterator
对象。
将list、dict、str等Iterable对象变成Iterator,使用iter()
函数
print(isinstance(iter(()), Iterator))
# output:True
print(isinstance(iter([]), Iterator))
# output:True
Python中的Iterator
对象表示的是一个数据流,Iterator对象可以被next()
函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration
错误。可以把这个数据流看做是一个有序序列,但是我们不能提前直到序列的长度,只能不断通过next()
函数按需计算下一个数据,所以Iterator
的计算是惰性的,只有在需要返回下一个数据时它才会计算。Iterator
甚至可以表示一个无限大的数据,例如全体自然数,然而list不行。
for循环的本质
it = iter([1, 2, 3, 4, 5])
while True:
try:
print(next(it))
except StopIteration:
break
Python中的函数式编程
变量可以指向函数:函数本身也可以赋值给变量,通过变量可以调用函数
print(abs(-1.5))
# output: 1.5
print(abs)
# output: <built-in function abs>
f = abs
print(f(-1.5))
# output: 1.5
传入函数:一个函数可以接收另一个函数作为参数,这种函数就称之为高阶函数
def add(x, y, f):
return f(x)+f(y)
print(add(1, -1, abs))
# output: 2
Map、reduce函数
map函数接收两个参数,一个是函数,一个是Iterable
,map将传入的函数依次作用到序列的每个元素,并且把结果作为新的Iterator
返回。
def f(x):
return x*x
r = map(f, [1, 2, 3, 4, 5, 6])
print(list(r))
res_str = map(str, [1, 2, 3, 4, 5, 6])
print(list(res_str))
reduce函数把一个函数作用在一个序列[x1,x2,x3,…]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,即:
reduce(f,[x1,x2,x3])=f(f(x1,x2),x3)
from functools import reduce
def fn(x, y):
return x * 10 + y
print(reduce(fn, [1, 4, 3, 3]))
# output:1433
def char2num(s):
digits = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
return digits[s]
print(reduce(fn, map(char2num, '1433')))
利用lambda函数整理成一个str2int函数
from functools import reduce
DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
def char2num(s):
return DIGITS[s]
def str2num(s):
return reduce(lambda x, y: 10*x+y, map(char2num, s))
print(str2num('1433'))
filter
filter()
函数用于过滤序列, 和map()
类似,filter()
函数也接收一个函数和一个队列。和map()
不同的是,filter()
把传入的函数依次作用于每个元素,然后根据返回值是True
还是False
决定保留还是丢弃该元素。
# 筛选奇数
def is_odd(n):
return n % 2 == 1
print(list(filter(is_odd, [1, 2, 4, 3])))
# filter产生的是惰性序列即Iterator, 需要用list函数获得所有结果, output:[1, 3]
sorted
print(sorted([1, 2, 3, -1, 2], key=abs))
# output:[1, -1, 2, 2, 3]
print(sorted(['bob', 'alice', 'John', 'hinton'], key=str.lower, reverse=True))
# output:['John','hinton','bob','alice']
返回函数
def lazy_sum(*args):
def sum():
res = 0
for n in args:
res += n
return res
return sum
f = lazy_sum(1, 2, 3, 4, 5)
print(f)
# output: <function lazy_sum.<locals>.sum at 0x7f995d0fb840>
print(f())
# output: 15
f1 = lazy_sum(0, 1)
f2 = lazy_sum(1, 2)
print(f1 == f2)
# output: False
一个函数可以返回一个计算结果,也可以返回一个函数。当返回一个函数时,这个函数并未执行,返回函数中不要引用任何可能会变化的变量。
def count():
fs = []
for i in range(1, 4):
def f():
return i * i
fs.append(f)
return fs
f1, f2, f3 = count()
print(f1())
print(f2())
print(f3())
# output:9 9 9
# 返回函数引用了变量i, 但它并非立刻被执行.等到三个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9
修改后
def count():
def g(j):
def f():
return j*j
return f
fs = []
for i in range(1, 4):
fs.append(g(i))
return fs
f1, f2, f3 = count()
print(f1())
print(f2())
print(f3())
# output:1, 4, 9
匿名函数
关键字lambda表示匿名函数,冒号前面的表示函数参数。匿名函数可以作为返回值返回
print(list(map(lambda x: x*x, [1, 2, 3])))
# output: [1, 4, 9]
f = lambda x: x*x
print(f)
# output:<function <lambda> at 0x7f6966041f28>
def cacl(x, y):
return lambda:x*x+y*y
print(cacl(1,3))
# output:<function cacl.<locals>.<lambda> at 0x7efc34e652f0>
print(cacl(1,3)())
# output: 10
装饰器
函数也是一个对象,而且函数对象可以被赋值給变量,所以通过变量也能调用该函数。通过函数对象的一个属性__name__
,我们可以得到函数的名字。
def now():
print('2017-12-21')
f = now
print(f.__name__)
# output:now
如果我们要增强now()
函数的功能,比如在函数调用前后自动打印日志,但是又不希望修改now()
函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器(Decorator)”
def log(func):
def warpper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return warpper
@log
def now():
print('2017-12-21')
# output:call now()
# 2017-12-21
把@log
放到now()
函数的定义处,相当于执行了语句now = log(now)
。由于log()
是一个decorator,返回一个函数,所以原来的now()
函数仍然存在,只是现在同名的now
变量指向了新的函数,于是调用now()
将执行新函数,即在log()
函数中返回的wrapper()
函数。wrapper()
函数的参数定义是(*args, **kw)
,因此,warpper()
函数可以接受任意参数的调用。在wrapper()
函数内,首先打印日志,再紧接着调用原始函数。
如果decorator本身需要传入参数,那么需要编写一个返回decorator的高阶函数,如定义log的文本:
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
@log('execute')
def now():
print('2017-12-21')
now()
# output:execute now():
# 2017-12-21
print(now.__name__)
# wrapper
和两层嵌套的decorator相比,三层嵌套的效果是这样的:now=log('execute')(now)
,首先执行log('execute')
,返回的是decorator
函数,再调用返回的参数,参数是now
函数,返回值最终是wrapper
函数。但是函数也是对象,它有name等属性,但上面代码中的经过decorator
装饰过的函数,它们的名字已经从原来的now
变成了wrapper
。
我们需要把原始函数的各种属性复制到wrapper()
函数中,否则有些依赖函数签名的代码执行就会出错。修改后如下
import functools
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
@log('execute')
def now():
print('2017-12-21')
now()
# output:execute now():
# 2017-12-21
print(now.__name__)
# now
偏函数
import functools
print(int('12345'))
print(int('12345', base=8))
# 如果要转换大量的二进制字符串,每次都传入int(x, base=2)太麻烦,容易想到的方法如下
def int2(s, base=2):
return int(s, base)
print(int2('10000'))
# output:16
# 使用偏函数
int2 = functools.partial(int, base=2)
print(int2('11'))
# output:3
'''
int2('11')相当于kw={'base': 2} int('11', **kw)
当传入max2 = functools.partial(max, 10)实际上会把10作为*args的一部分自动加到左边,也就是:
max2(5, 6, 7)相当于args=(10, 5, 6, 7) max(*args)
'''