1、切片(Slice)操作符
示例一:
# 取L前三个元素之笨方法
L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
print([L[0], L[1], L[2]])
# 聪明方法1
r = []
n = 3
for i in range(n):
r.append(L[i])
print(r)
# 聪明方法2:L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3
print(L[0:3]) # 0可以省略不写
print(L[-2:]) # 包括最后一个元素
print(L[-2:-1]) # 不包括最后一个元素
示例二:
# 用list创建一个 0-99 的数列
L = list(range(100)) # 包括0不包括100
print(L)
# 两者不同,后10个数,后10个数去除最后一个数
print(L[-10:])
print(L[-10:-1])
# 前11-20个数
L[10:20]
# 前 10 个数,每两个取一个
L[:10:2]
# 所有数,从第一个数开始,每 5 个取一个:
print(L[::5])
# 只写[:]就可以原样复制一个 list
L[:]
# tuple 也可以用切片操作,只是操作的结果仍是 tuple
(0, 1, 2, 3, 4, 5)[:3]
# 字符串也可以用切片操作,只是操作结果仍是字符串
'ABCDEFG'[:3]
2、迭代
2.1 默认情况下,dict 迭代的是 key。如果要迭代 value,可以用 for value ind.values() ,如果要同时迭代 key 和 value,可以用 for k, v in d.items() 。
# 在 Python 中,迭代是通过 for ... in 来完成的
d = {'a': 1, 'b': 2, 'c': 3} # dict
for key in d:
print(key)
# 迭代对象为字符串
for ch in 'ABC':
print(ch)
2.2 通过 collections.abc 模块的 Iterable 类型判断一个对象是否可迭代
from collections.abc import Iterable
print(isinstance('abc', Iterable)) # str 是否可迭代
print(isinstance([1,2,3], Iterable)) # list 是否可迭代
print(isinstance(123, Iterable)) # 整数是否可迭代
# enumerate 函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身:
for i, value in enumerate(['A', 'B', 'C']):
print(i, value)
# 同时引用了两个变量
for x, y in [(1, 1), (2, 4), (3, 9)]:
print(x, y)
3、列表生成式
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
a=list(range(1, 11))
print(a)
# 生成 [1x1, 2x2, 3x3, ..., 10x10]
# 方法一:
L = []
for x in range(1, 11):
L.append(x * x)
print(L) # 循环里输出和循环外输出
# 方法二
a=[x * x for x in range(1, 11)]
print(a)
# for 循环后面还可以加上 if 判断
a=[x * x for x in range(1, 11) if x % 2 == 0]
print(a)
# 使用两层循环,可以生成全排列
a=[m + n for m in 'ABC' for n in 'XYZ']
print(a)
# 列出当前目录下的所有文件和目录名
import os
print([d for d in os.listdir('.')])
# for 循环其实可以同时使用两个甚至多个变量,比如dict的items()可以同时迭代 key 和 value:
d = {'x': 'A', 'y': 'B', 'z': 'C' }
for k, v in d.items():
print(k, '=', v)
# 列表生成式也可以使用两个变量来生成 list
d = {'x': 'A', 'y': 'B', 'z': 'C' }
print([k + '=' + v for k, v in d.items()])
# 把一个 list 中所有的字符串变成小写
L = ['Hello', 'World', 'IBM', 'Apple']
print([s.lower() for s in L])
4、生成器
在 Python 中,这种一边循环一边计算的机制,称为生成器:generator。
# 把一个列表生成式的 [] 改成 () ,就创建了一个 generator
L = [x * x for x in range(10)] # list
g = (x * x for x in range(10)) # generator
print(L)
print(g)
# 通过 next() 函数获得 generator 的下一个返回值
print(next(g))
print(next(g))
print(next(g))
# 方法二:使用for循环
g = (x * x for x in range(10))
for n in g:
print(n)
# 用函数把它打印出斐波拉契数列用列表生成式写不出来
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a + b
n = n + 1
return 'done'
print(fib(6))
# 要把 fib 函数变成generator,只需要把 print(b) 改为 yield b 就可以了
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
print(fib(6))
# 使用 for 循环来迭代,获取下一个返回值
for n in fib(6):
print(n)
# 得到generator的return语句的返回值
g = fib(6)
while True:
try:
x = next(g)
print('g:', x)
except StopIteration as e:
print('Generator return value:', e.value)
break
5、迭代器
5.1
可以直接作用于 for 循环的对象统称为可迭代对象: Iterable 。
# 使用 isinstance() 判断一个对象是否是 Iterable 对象
from collections.abc import Iterable
print(isinstance([], Iterable))
print(isinstance({}, Iterable))
print(isinstance('abc', Iterable))
print(isinstance((x for x in range(10)), Iterable))
print(isinstance(100, Iterable))
5.2 可以被 next() 函数调用并不断返回下一个值的对象称为迭代器:Iterator 。
from collections.abc import Iterator
a=isinstance((x for x in range(10)), Iterator)
a=isinstance([], Iterator)
a=isinstance({}, Iterator)
a=isinstance('abc', Iterator)
print(a)
# 把 list 、 dict 、 str 等 Iterable 变成 Iterator 可以使用 iter() 函数
a=isinstance(iter([]), Iterator)
a=isinstance(iter('abc'), Iterator)
print(a)
6、高阶函数
6.1 变量可以指向函数
# 函数本身也可以赋值给变量
f = abs
print(f(-10))
6.2 函数名也是变量
# 要恢复abs函数,请重启Python交互环境
abs = 10
abs(-10) # 输出有误
6.3 传入函数
一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
# 示例一
def add(x, y, f):
return f(x) + f(y)
a=add(-5, 6, abs)
print(a)
7、Python内建函数
7.1 map/reduce
map() 函数接收两个参数,一个是函数,一个是 Iterable ,map 将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator 返回。
def f(x):
return x * x
r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
print(list(r))
# 把这个list 所有数字转为字符串
print(list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9])))
# 方法二
L = []
for n in [1, 2, 3, 4, 5, 6, 7, 8, 9]:
L.append(f(n))
print(L)
reduce 把一个函数作用在一个序列 [x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce 把结果继续和序列的下一个元素做累积计算。
from functools import reduce
def add(x, y):
return x + y
a=reduce(add, [1, 3, 5, 7, 9])
print(a)
# 把str转换为int的函数
from functools import reduce
def str2int(s):
def fn(x, y):
return x * 10 + y
def char2num(s):
return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6,'7': 7, '8': 8, '9': 9}[s]
return reduce(fn, map(char2num, s))
a=str2int('13579')
print(a)
7.2 filter
filter() 也接收一个函数和一个序列。和 map() 不同的时,filter() 把传入的函数依次作用于每个元素,然后根据返回值是 True 还是 False 决定保留还是丢弃该元素。
filter() 函数返回的是一个 Iterator ,也就是一个惰性序列,所以要强迫 filter() 完成计算结果,需要用 list() 函数获得所有结果并返
回 list。
# 在一个list中,删掉偶数,只保留奇数
def is_odd(n):
return n % 2 == 1
a=list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
print(a)
# 把一个序列中的空字符串删掉
def not_empty(s):
return s and s.strip()
a=list(filter(not_empty, ['A', '', 'B', None, 'C', ' ']))
# 用 用 filter
def _odd_iter(): # 这是一个生成器,并且是一个无限序列
n = 1
while True:
n = n + 2
yield n
def _not_divisible(n): # 定义一个筛选函数
return lambda x: x % n > 0
def primes(): # 这个生成器先返回第一个素数2,然后,利用filter()不断产生筛选后的新的序列。
yield 2
it = _odd_iter() # 初始序列
while True:
n = next(it) # 返回序列的第一个数
yield n
it = filter(_not_divisible(n), it) # 构造新序列
# 打印 1000 以内的素数:
for n in primes():
if n < 1000:
print(n)
else:
break
7.3 排序算法(sorted)
# 对 list 进行排序
a=sorted([36, 5, -12, 9, -21])
print(a)
# 按绝对值大小排序
a=sorted([36, 5, -12, 9, -21], key=abs)
print(a)
# 对字符串排序,是按照ASCII的大小比较的
a=sorted(['bob', 'about', 'Zoo', 'Credit'])
print(a)
# 忽略大小写的排序
a=sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
print(a)
# 反向排序
a=sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower,reverse=True)
print(a)
7.4 返回函数:函数作为返回值
高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。
# 求和函数
def calc_sum(*args):
ax = 0
for n in args:
ax = ax + n
return ax
a=calc_sum(1, 2, 3)
print(a)
# 不返回求和的结果,而是返回求和的函数
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
f = lazy_sum(1, 3, 5, 7, 9)
print(f())
7.5 闭包
# 返回函数不要引用任何循环变量,或者后续会发生变化的变量。
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())
# 解决办法:创建一个函数,用该函数的参数绑定循环变量当前的值
def count():
def f(j):
def g():
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())
print(f2())
print(f3())
7.6 匿名函数
关键字 lambda 表示匿名函数,冒号前面的 x 表示函数参数。
# 直接传入匿名函数
a=list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
print(a)
# 把匿名函数赋值给一个变量
f = lambda x: x * x
print(f(5))
7.7 装饰器
在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
# 函数名
def now():
print('2015-3-25')
f=now
print(f())
print(now.__name__)
print(f.__name__)
# 定义一个能打印日志的 decorator
def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
@log
def now():
print('2015-3-25')
print(now())
# 自定义 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('2015-3-25')
print(now())
# 把原始函数的__name__等属性复制到wrapper()函数中
# 方法一:
import functools
def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
@log
def now():
print('2015-3-25')
print(now())
print(now.__name__)
# 方法二:针对带参数的 decorator
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
def now():
print('2015-3-25')
print(now.__name__)
7.8 偏函数
functools.partial 的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数
会更简单。(也可以在函数调用时传入其他值)
# int(x, base=N) N 进制的转换
# 创建一个新的函数 int2 :
import functools
int2 = functools.partial(int, base=2)
print(int2('1000000'))
# 把10作为*args的一部分自动加到左边
max2 = functools.partial(max, 10)
print(max2(5, 6, 7))
8、模块
在 Python 中,一个.py 文件就称之为一个模块(Module)。(尽量不要与内置函数名字冲突)
通过包(Package)来组织模块,避免冲突。引入了包以后,只要顶层的包名不与别人冲突,那所有模块都不会与别
人冲突。现在, abc.py 模块的名字就变成了 mycompany.abc ,类似的, xyz.py的模块名变成了 mycompany.xyz 。mycompany为包文件名字。
8.1 Python 模块的标准文件模板:
#!/usr/bin/env python3 # 让这个hello.py文件直接在Unix/Linux/Mac上运行
# -*- coding: utf-8 -*- # 表示.py文件本身使用标准UTF-8编码
' a test module ' # 任何模块代码的第一个字符串都被视为模块的文档注释
__author__ = 'Michael Liao' # 用 __author__ 变量把作者写进去
import sys
def test():
args = sys.argv
if len(args)==1:
print('Hello, world!')
elif len(args)==2:
print('Hello, %s!' % args[1])
else:
print('Too many arguments!')
if __name__=='__main__':
test()
print(__author__)
# 运行 python hello3.py 获得的 sys.argv 就是 ['hello.py'] ;
import sys
print( sys.argv)
8.2 安装第三方模块
# 找个图片生成缩略图
from PIL import Image
im = Image.open('test.png')
print(im.format, im.size, im.mode)
im.thumbnail((200, 100))
im.save('thumb.jpg', 'JPEG') # 无法保存
8.3 模块搜索路径
# 搜索当前目录、所有已安装的内置模块和第三方模块,搜索路径存放在sys模块的path变量中
import sys
print(sys.path)
# 一是直接修改 sys.path,添加要搜索的目录
import sys
sys.path.append('/Users/michael/my_py_scripts')
# 第二种方法是设置环境变量 PYTHONPATH ,该环境变量的内容会被自动添加到模块搜索路径中。
9、作用域
正常的函数和变量名是公开的(public),类似 __xxx__ 这样的变量是特殊变量。类似 _xxx 和 __xxx 这样的函数或变量就是非公开的(private)。
# 外部不需要引用的函数全部定义成 private,只有外部需要引用的函数才定义为 public。
def _private_1(name):
return 'Hello, %s' % name
def _private_2(name):
return 'Hi, %s' % name
def greeting(name):
if len(name) > 3:
return _private_1(name)
else:
return _private_2(name)
外部不需要引用的函数全部定义成 private,只有外部需要引用的函数才定义为 public。
def _private_1(name):
return 'Hello, %s' % name
def _private_2(name):
return 'Hi, %s' % name
def greeting(name):
if len(name) > 3:
return _private_1(name)
else:
return _private_2(name)
print(greeting('michael'))
10、面向对象编程
# 面向过程的程序可以用一个 dict 表示
std1 = { 'name': 'Michael', 'score': 98 }
std2 = { 'name': 'Bob', 'score': 81 }
def print_score(std):
print('%s: %s' % (std['name'], std['score']))
print(std1)
#
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))
#
bart = Student('Bart Simpson', 59)
lisa = Student('Lisa Simpson', 87)
bart.print_score()
lisa.print_score()
11、类和实例
# 定义类是通过 class 关键字
class Student(object): # class 后面紧接着是类名
pass
# 创建实例是通过类名+()实现的
bart = Student()
print(bart) # 内存地址
print(Student) # Student 本身则是一个类
# 给实例 bart 绑定一个 name属性
bart.name = 'Bart Simpson'
print(bart.name)
# 把name,score等属性绑上去
class Student(object):
def __init__(self, name, score): #__init__ 方法的第一个参数永远是 self ,表示创建的实例本身
self.name = name
self.score = score
bart = Student('Bart Simpson', 59)
print(bart.name)
print(bart.score)
11.1 数据封装
# 打印一个学生的成绩
class Student(object):
def __init__(self, name, score): #__init__ 方法的第一个参数永远是 self ,表示创建的实例本身
self.name = name
self.score = score
bart = Student('Bart Simpson', 59)
def print_score(std):
print('%s: %s' % (std.name, std.score))
print_score(bart)
#
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))
12 访问限制
让内部属性不被外部访问
# 把属性的名称前加上两个下划线__变成了一个私有变量(private)
class Student(object):
def __init__(self, name, score):
elf.__name = name
self.__score = score
def print_score(self):
print('%s: %s' % (self.__name, self.__score))
bart = Student('Bart Simpson', 98)
print(bart.__name)
# Student 类增加get_name 和 get_score 这样的方法
class Student(object):
...
def get_name(self):
return self.__name
def get_score(self):
return self.__score
# 允许外部代码修改 score
class Student(object):
...
def set_score(self, score):
self.__score = score
# 示例
class Student(object):
def __init__(self, name, score):
self.__name = name
self.__score = score
def get_name(self):
return self.__name
def get_score(self):
return self.__score
def set_score(self, score):
if 0 <= score <= 100:
self.__score = score
else:
raise ValueError('bad score')
def get_grade(self):
if self.__score >= 90:
return 'A'
elif self.__score >= 60:
return 'B'
else:
return 'C'
bart = Student('Bart Simpson', 59)
print('bart.get_name() =', bart.get_name())
bart.set_score(60)
print('bart.get_score() =', bart.get_score())
print('DO NOT use bart._Student__name:', bart._Student__name)
13、继承和多态
在 OOP 程序设计中,当我们定义一个 class 的时候,可以从某个现有的class 继承,新的 class 称为子类(Subclass),而被继承的 class 称为基类、父类或超类(Base class、Super class)。
# 编写了一个名为 Animal 的 class
class Animal(object):
def run(self):
print('Animal is running...')
# 从 Animal 类继承
class Dog(Animal):
pass
class Cat(Animal):
pass
dog = Dog()
dog.run()
cat = Cat()
cat.run()
# 对子类增加一些方法
class Dog(Animal):
def run(self):
print('Dog is running...')
def eat(self):
print('Eating meat...')
dog = Dog()
dog.run()
dog.eat()
# 对Dog 和 Cat 类改进
class Dog(Animal):
def run(self):
print('Dog is running...')
class Cat(Animal):
def run(self):
print('Cat is running...')
dog = Dog()
dog.run()
cat = Cat()
cat.run()
# 判断一个变量是否是某个类型可以用 isinstance() 判断
a = list()
b = Animal()
c = Dog()
a=isinstance(a, list)
print(a)
a=isinstance(b, Animal)
print(a)
a=isinstance(c, Dog)
print(a)
a=isinstance(c, Animal)
print(a)
# 反过来就不行
b = Animal()
a=isinstance(b, Dog)
print(a) # false
# 理解多态的好处
def run_twice(animal):
animal.run()
animal.run()
run_twice(Animal())
run_twice(Dog())
run_twice(Cat())
# 再定义一个 Tortoise类型
class Tortoise(Animal):
def run(self):
print('Tortoise is running slowly...')
run_twice(Tortoise())
静态语言:传入的对象必须是 Animal 类型或者它的子类 vs 动态语言:只需要保证传入的对象有一个 run() 方法就可以了
14、获取对象信息
# 判断对象类型
a=type(123)
print(a)
a=type('str')
print(a)
a=type(None)
print(a)
# 一个变量指向函数或者类
a=type(abs)
print(a)
# 比较两个变量的 type 类型是否相同
print(type(123)==type(456))
print(type(123)==int)
print(type('abc')==type('123'))
print(type('abc')==str)
print(type('abc')==type(123))
# 判断一个对象是否是函数
import types
def fn():
pass
print(type(fn)==types.FunctionType)
print(type(abs)==types.BuiltinFunctionType)
print(type(lambda x: x)==types.LambdaType)
print(type((x for x in range(10)))==types.GeneratorType)
# 能用 type() 判断的基本类型也可以用 isinstance() 判断
print(isinstance('a', str))
# 判断一个变量是否是某些类型中的一种
print(isinstance([1, 2, 3], (list, tuple)))
print(isinstance((1, 2, 3), (list, tuple)))
使用 dir()获得一个对象的所有属性和方法
# 获得一个 str 对象的所有属性和方法
print(dir('ABC'))
# 等价代码
print(len('ABC'))
print('ABC'.__len__())
# lower() 返回小写的字符串
print('ABC'.lower())
# 配合 getattr() 、 setattr() 以及hasattr() ,我们可以直接操作一个对象的状态
class MyObject(object):
def __init__(self):
self.x = 9
def power(self):
return self.x * self.x
obj = MyObject()
# 有属性'x'吗?
print(hasattr(obj, 'x'))
# 有属性'y'吗?
print(hasattr(obj, 'y'))
# 设置一个属性'y'
print(setattr(obj, 'y', 19))
# 有属性'y'吗?
print(hasattr(obj, 'y'))
# 获取属性'y'
print(getattr(obj, 'y'))
# 获取属性'y'
print(obj.y)
# 获取属性'z',如果不存在,返回默认值404
print(getattr(obj, 'z', 404))
# 有属性'power'吗?
print(hasattr(obj, 'power'))
# 获取属性'power'
print(getattr(obj, 'power'))
# 获取属性'power'并赋值到变量 fn
fn = getattr(obj, 'power')
# fn 指向 obj.power
print(fn)
print(fn())