Python Study Note(1)
变量
- 除法
>>> 9 / 3
3.0
>>> 10 // 3
3
- 字符串多个空行
print('''line1
line2
line3''')
list,tuple
-
list:可变数组
classmates = ['Michael', 'Bob', 'Tracy']
classmates[-1] #末尾元素
classmates.pop() #删除末尾元素
classmates.pop(1) #删除索引1元素
classmates[1] = "Chen" ##替代元素
classmates.insert(1,'Jack')
classmates.append('Bai')
-
tuple:不可变数组
classmates = ('Michael', 'Bob', 'Tracy')
t = (1,)
#只有一个元素时须加,
条件判断
age = 3
if age >= 18:
print('your age is', age)
print('adult')
else:
print('your age is', age)
print('teenager')
":"代表后面缩进的部分都是他的块。
循环
- for x in ...: 遍历
sum = 0
for x in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:
sum = sum + x
print(sum)
- random()函数:
>>> range(5)
[0, 1, 2, 3, 4]
- while
sum = 0
n = 99
while n > 0:
sum = sum + n
n = n - 2
print(sum)
- break:在循环过程中直接退出循环
- continue:提前结束本轮循环,并直接开始下一循环
字典
判断key是否存在
- in
>>> 'Thomas' in d
False
- get
>>> d.get('Thomas') #返回None的时候,交互式命令行不显示结果
>>> d.get('Thomas', -1) #如果key不存在,返回None或者指定的value
-1
基本操作
- 删除key
>>> d.pop('Bob')
set:也是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key
>>> s = set([1, 1, 2, 2, 3, 3])
>>> s
{1, 2, 3}
函数
- 内联函数:http://www.cottonclub.com.cn/UploadFiles/004.mp3
- 参数类型检查:
if not isinstance(x, (int, float)):
raise TypeError('bad operand type')
函数参数
-
位置参数
def power(x):
-
默认参数
def power(x, n=2): # power(5)相当于power(5,2)
注意: 默认参数必须指向不变对象
- 可变参数:可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。
def calc(*numbers): #在函数内部,参数numbers接收到的是一个tuple
sum = 0
for n in numbers:
sum = sum + n * n
return sum
calc(1, 2)
如果已经有一个list或者tuple
>>> nums = [1, 2, 3]
>>> calc(*nums)
- 关键字参数:关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。
def person(name, age, **kw):
print('name:', name, 'age:', age, 'other:', kw)
>>> person('Adam', 45, gender='M', job='Engineer')
name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}
如果已经有一个dict
>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, **extra)
- 命名关键字参数:如果要限制关键字参数的名字,就可以用命名关键字参数。
def person(name, age, *, city, job): #只接受city,job作为关键字参数
print(name, age, city, job)
如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:
def person(name, age, *args, city, job):
print(name, age, args, city, job)
- 参数组合:参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
使用args和*kw是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。
切片
L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
>>> L[:3]
['Michael', 'Sarah', 'Tracy']
>>> L[1:3]
['Sarah', 'Tracy']
>>> L[-2:]
['Bob', 'Jack']
>>> L[-2:-1]
['Bob']
tuple和字符串也可以使用。
>>> L[:10:2] 前10个数,每两个取一个:
[0, 2, 4, 6, 8]
高级特性
迭代
dict迭代:默认情况下,dict迭代的是key。如果要迭代value,可以用for value in d.values(),如果要同时迭代key和value,可以用for k, v in d.items()。
其他语言中是通过下标完成,如下
for (i=0; i<list.length; i++) {
n = list[i];
}
如果我们希望在python中使用,Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身:
>>> for i, value in enumerate(['A', 'B', 'C']):
... print(i, value)
...
0 A
1 B
2 C
以上形式,在python中较为常用。
>>> for x, y in [(1, 1), (2, 4), (3, 9)]:
... print(x, y)
...
1 1
2 4
3 9
列表生成式
>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]
>>> [m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
生成器
将列表生成器变为生成器
>>> L = [x * x for x in range(10)]
>>> g = (x * x for x in range(10))
>>> next(g) #一个一个打印
>>> 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:
yield b #加入yield
a, b = b, a + b
n = n + 1
return 'done'
>>> for n in fib(6):
... print(n)
...
1
1
2
3
5
8
例子
def triangles():
n, L = 1, []
while True:
n, L = n+1, [1 if(i == len(L) or i == 0) else L[i - 1] + L[i] for i in range(len(L)+1)]
yield L
n = 0
for t in triangles():
print(t)
n = n + 1
if n == 10:
break
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1]
[1, 7, 21, 35, 35, 21, 7, 1]
[1, 8, 28, 56, 70, 56, 28, 8, 1]
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
迭代器
- 可迭代对象Iterable:可以直接作用于for循环的对象统称为可迭代对象。一类是集合数据类型,如list、tuple、dict、set、str等;一类是generator,包括生成器和带yield的generator function。
可以使用isinstance()判断一个对象是否是Iterable对象:
>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False
- 迭代器Iterator:可以被next()函数调用并不断返回下一个值的对象称为迭代器,表示的是一个数据流。
可以使用isinstance()判断一个对象是否是Iterator对象:
>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False
- 把list、dict、str等Iterable变成Iterator可以使用iter()函数:
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True
函数式编程
- map:map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。
>>> def f(x):
... return x * x
...
>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> list(r) #list()函数让它把整个序列都计算出来并返回一个list。
[1, 4, 9, 16, 25, 36, 49, 64, 81]
- reduce:reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
将str变为int并计算
>>> from functools import reduce
>>> 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]
...
>>> reduce(fn, map(char2num, '13579'))
13579
- filter:主要用于过滤,把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
def is_odd(n):
return n % 2 == 1
list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
# 结果: [1, 5, 9, 15]
- sort:除普通排序外,它还可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序。
>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]
L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
def by_name(t):
return t[0]
L2=sorted(L,key=by_name)
key=str.lower 忽略大小写 reverse=True 反向排序
匿名函数
lambda x: x * x
**等价于下列内容**
def f(x):
return x * x
装饰器
def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
@log #把@log放到now()函数的定义处,相当于执行了语句:now = log(now)
def now():
print('2015-3')
now()
$ python a.py
call now():
2015-3
带参数的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('execute') #相当于>>> now = log('execute')(now)
偏函数
ef int2(x, base=2):
return int(x, base)
##把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。
>>> import functools
>>> int2 = functools.partial(int, base=2)
内置函数
https://docs.python.org/3/library/functions.html
模块
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
' a test module ' #文档注释
__author__ = 'Michael Liao'
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__': #当我们在命令行运行hello模块文件时,Python解释器把一个特殊变量__name__置为__main__,而如果在其他地方导入该hello模块时,if判断将失败,因此,这种if测试可以让一个模块通过命令行运行时执行一些额外的代码,最常见的就是运行测试。
test()
使用域
- 公开的,可以被直接引用:比如:abc,x123,PI等;
- 特殊的:类似xxx这样的变量是特殊变量,可以被直接引用,但是有特殊用途,比如上面的author,name就是特殊变量。
- 非公开的:类似_xxx和__xxx这样的函数或变量就是非公开的(private),不应该被直接引用,比如_abc,__abc等。
面向对象编程
访问限制
class Student(object):
"""docstring for Student."""
def __init__(self, name, score):
self.__name = name #__name私有变量
self.__score = score
def set_score(self, score): #从外部修改私有变量,
self._score = score
def set_name(self, name):
self._name =name
def get_score(self): #从外部访问获取私有变量
return self.__score
def get_name(self):
return self.__name
def print_score(self):
print('%s:%s' % (self._name,self._score))
Bai = Student('Bai', 100)
BaiName = Bai.get_name()
获取对象信息
- type
>>> import types
>>> def fn():
... pass
...
>>> type(fn)==types.FunctionType
True
>>> type(abs)==types.BuiltinFunctionType
True
>>> type(lambda x: x)==types.LambdaType
True
>>> type((x for x in range(10)))==types.GeneratorType
True
>>> type('abc')==str
True
>>> type(123)==int
True
- isinstance:相比较type,更能反映继承关系,同时可以判断是否是某些类型中的一种
>>> isinstance([1, 2, 3], (list, tuple))
True
>>> isinstance((1, 2, 3), (list, tuple))
True
- dir:获得一个对象的所有属性和方法。
>>> dir('ABC')
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
类似xxx的属性和方法在Python中都是有特殊用途的,下列就是等价的
>>> len('ABC')
3
>>> 'ABC'.__len__()
3
配合getattr()、setattr()以及hasattr(),我们可以直接操作一个对象的状态。
>>> class MyObject(object):
... def __init__(self):
... self.x = 9
... def power(self):
... return self.x * self.x
...
>>> obj = MyObject()
>>> hasattr(obj, 'x') # 有属性'x'吗?
True
>>> obj.x
9
>>> hasattr(obj, 'y') # 有属性'y'吗?
False
>>> setattr(obj, 'y', 19) # 设置一个属性'y'
>>> hasattr(obj, 'y') # 有属性'y'吗?
True
>>> getattr(obj, 'y') # 获取属性'y'
19
>>> obj.y # 获取属性'y'
19
##也可以获取方法
>>> getattr(obj, 'power') # 获取属性'power'
<bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
- slots:想要限制实例的属性.对继承的无效。
class Student(object):
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
>>> s = Student() # 创建新的实例
>>> s.name = 'Michael' # 绑定属性'name'
>>> s.age = 25 # 绑定属性'age'
>>> s.score = 99 # 绑定属性'score'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'
-@property:绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改。Python内置的@property装饰器就是负责把一个方法变成属性调用。
class Student(object):
def get_score(self):
return self._score
def set_score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
上述写法过于复杂,所以需要简化
class Student(object):
#可读可写
@property
def birth(self):
return self._birth
@birth.setter
def birth(self, value):
self._birth = value
#只可写
@property
def age(self):
return 2015 - self._birth
- str 和 repr:用于优化打印结果
class Student(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Student object (name=%s)' % self.name
__repr__ = __str__
# __str__部分
>>> print(Student('Michael'))
Student object (name: Michael)
# __repr__部分
>>> s = Student('Michael')
>>> s
<__main__.Student object at 0x109afb310>
- getattr:如果一个类没有相应属性,那么还可以写一个getattr()方法,动态返回一个属性。一般默认返回None.(只有在没有找到属性的情况下,才调用getattr)
class Student(object):
def __init__(self):
self.name = 'Michael'
def __getattr__(self, attr):
if attr=='score':
return 99
- 枚举
from enum import Enum
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
for name, member in Month.__members__.items():
print(name, '=>', member, ',', member.value) #value默认从1开始
如果需要更精确地控制枚举类型,可以从Enum派生出自定义类:
from enum import Enum, unique
@unique # @unique装饰器可以帮助我们检查保证没有重复值。
class Weekday(Enum):
Sun = 0 # Sun的value被设定为0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6
元类
- type:函数既可以返回一个对象的类型,又可以创建出新的类型。我们说class的定义是运行时动态创建的,而创建class的方法就是使用type()函数。
>>> def fn(self, name='world'): # 先定义函数
... print('Hello, %s.' % name)
...
>>> Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello class
>>> h = Hello()
>>> h.hello()
Hello, world.
>>> print(type(Hello))
<class 'type'>
>>> print(type(h))
<class '__main__.Hello'>
要创建一个class对象,type()函数依次传入3个参数:
- class的名称;
- 继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
本笔记参考 Linux探索之旅
- class的方法名称与函数绑定,这里我们把函数fn绑定到方法名hello上。