python
我想说…python的语法真的是太多了,跟java真的有很多的不一样,可能是动态语言的原因,自己刚开始接触有很多不适应的地方。这一篇是自己根据廖雪峰的python教程写的笔记,初心是学习一下python的基础语法方便后续的机器学习等内容的学习,并且希望自己可以熟悉Markdown语法方便后来记笔记。自己还有很多不熟练的地方,后面继续练几个oj题并且做几个小项目跟进吧,希望自己的python能学好。
由于是快速入门,所以只写了一些我觉得比较有价值并且不熟悉的地方,对于java中也有的,我就懒得写了
python基础语法
可以用help(函数名)命令行来获得函数的信息
冒号+缩进:python语法功能的一部分,表达代码的所属关系
注释: 单行 #
多行注释 ‘’‘这里是注释’’'
续行符 \ (续行符后不能存在空格,必须直接换行)
变量:程序中用于保存和表示数据的占位符号
命名 大小写敏感,首字符不能是数字,不与保留字相同,*可以使用中文作为变量名*字符串: 使用双引号或单引号,两者没有差别
-12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 这 是 一 个 有 趣 的 字 符 串 实 例 0 1 2 3 4 5 6 7 8 9 10 11 s[N]通过序号获取某个字符
s[N:M]获取从N到M(不含)子串
用 **r’’**表示’'内部字符串默认不转义
ord() 获取字符的整数表示
chr() 把编码转换为对应的字符
print() : 可以接收多个字符串,用逗号分隔,依次打印,遇到逗号输出一个空格
input() : 可以接收字符串用作输入提示
返回的数据类型是 str
空值 : python中的控制用None表示
python中整数和浮点数没有大小限制,超出一定范围会直接表示为inf(无限大)
Unicode编码 、ASCII编码、UTF-8编码:
(1)ASCII编码是1个字节,Unicode编码是2个字节,而UTF-8编码是可变长编码
(2)计算机内存中同意使用Unicode编码,当需要保存到硬盘或传输时转换为UTF-8编码
(3)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-25iTnMGH-1570083741503)(C:\Users\difendDF\AppData\Roaming\Typora\typora-user-images\1569900537659.png)]
bytes类型数据用带 b 前缀的单引号或双引号表示 eg. x = b’ABC’
以Unicode表示的str通过 encode() 方法可以编码为指定的bytes eg.
>>> ’ABC‘.encode(‘ascii’)
b’ABC’
>>> ‘中文’.encode(‘utf-8’)
b’\xe4\xb8\xad\xe6\x96\x87
把bytes变为str需要用 decode() 方法 eg.
>>> b’ABC’.decode(‘ascii’)
‘ABC’
>>> b’\xe4\xb8\xad\xe6\x96\x87’.decode(‘utf-8’)
’中文‘
若bytes中有一小部分无效字节,传入 errors = ’ignore‘ 忽略错误的字节 eg.
>>> b’\xe4\xb8\xad\xff’.decode(‘utf-8’, errors=‘ignore’)
’中‘
len()函数计算str包含多少字符(如果是bytes则计算字节数) eg.
>>> len(‘ABC’)
3
>>> len(‘中文’.encode(‘utf-8’))
6
为了让python解释器读取源码是按UTF-8编码,在文件开头写上
#!/usr/bin/env python3 # -*- coding:utf-8 -*-第一行是告诉Linux/OS X系统这是一个python可执行程序
第二行告诉Python解释器按UTF-8编码读取源代码
格式化输出:采用 % 实现
>>> ‘Hi, %s, you have $%d.’ % (‘Michael’, 1000000)
‘Hi, Michael, you have $1000000.’
占位符 替换内容 备注 %d 整数 %f 浮点数 %s 字符串 可以把任何数据类型转换为字符串 %x 十六进制整数 format() :用传入的参数替换字符串占位符 eg.
>>> ‘Hello, {0}, 成绩提升了{1:.1f}%’.format(‘小明’, 17.125)
‘Hello, 小明,成绩提升了 17.1%’
list:一种有序的集合,可以随时添加和删除其中的元素
>>> classmates = [’Michael‘,’Bob‘,’Tracy‘]
用len()函数可以获得list元素的个数
>>> len(classmates)
用索引来访问list中每一个位置的元素,索引从 0 开始
向list中添加元素到末尾:classmates.append(’Adam‘)
将元素插到指定的位置:classmates.insert(1,‘Jack’)
删除list末尾元素:classmates.pop()
删除指定位置元素:classmates.pop(1)
替换某位置元素:classmates[1] = ‘Sarah’
list中的元素数据类型可以不同,也可以是另一个list
tuple:一旦初始化就不能修改
>>> classmates = (‘Michael’,‘Bob’,‘Tracy’)
如果tuple中只有一个元素,则必须加一个 **逗号,**来消除歧义
>>> t = (1,)
条件判断:
if <条件判断1>:
<执行1>
elif <条件判断2>:
<执行2>
elif <条件判断3>:
<执行3>
else :
<执行4>
dict:字段,使用键-值存储,具有极快的查找速度
>>> d = {‘Michael’: 95, ‘Bob’: 75, ‘Tracy’: 85}
>>> d[‘Michael’]
95
通过 in 判断key是否存在
通过**get()**方法,若key不存在范围None或指定 value
set:没有重复的key
通过 add(key) 方法添加元素
通过 remove() 方法删除元素
函数
定义函数
定义一个函数要使用 def 语句,一次写出 函数名、括号、括号中的参数和冒号:
定义一个什么事也不做的空函数可以用 pass 语句 eg.
def nop():
pass
- python中可以返回多个返回值
import math
def move(x,y,step,angle=0):
#返回的是一个(nx,ny)的元组
nx = x + step * math.cos(angle)
ny = y - step * math.sin(angle)
return nx,ny
- python中可以为参数指定默认值
def power(x,n = 2):
s = 1
while n > 0:
n = n - 1
s = s * x
return s
PS : 默认参数必须放在后面
默认参数必须指向不变对象
可变参数
允许传入0个或人一个参数,这些可变参数在函数调用时自动组装成一个tuple
def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
>>>calc(1, 2)
5
>>> calc()
0
>>> nums = [1, 2, 3]
>>> calc(*nums)
14
关键字参数
允许传入0个或人一个含参数名的参数,这些关键字参数在函数内部自动组装成一个dict
def person(name, age, **kw):
print('name:', name, 'age:', age, 'other:', kw)
>>> person(‘Bob’, 35, city=‘Beijing’)
name: Bob age: 35 other: {‘city’: ‘Beijing’}
>>> person(‘Adam’, 45, gender=‘M’, job=‘Engineer’)
name: Adam age: 45 other: {‘gender’: ‘M’, ‘job’: ‘Engineer’}
>>> extra = {‘city’: ‘Beijing’, ‘job’: ‘Engineer’}
>>> person(‘Jack’, 24, **extra)
name: Jack age: 24 other: {‘city’: ‘Beijing’, ‘job’: ‘Engineer’}
命名关键字参数
因为关键字参数可以不受限制的输入,如果我们想要限制关键字参数的名字,可以使用命名关键字参数,例如,只接受city和job作为关键字参数
def person(name,age,*,city,job):#*后面的参数被视为命名关键字参数
print(name,age,city,job)
def person(name,age,*args,city,job):
#函数中有可变参数则后面的命名关键字参数不需要一个特殊的*分隔符
print(name,age,args,city,job)
参数组合
参数定义的顺序必须是 必选参数、默认参数、可变参数、命名关键字参数、关键字参数
def f1(a, b, c=0, *args, **kw):
print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
def f2(a, b, c=0, *, d, **kw):
print('a =', a, 'b =', b, 'c =', c, 'd =' d, 'kw =', kw)
>>> f1(1, 2)
a = 1 b = 2 c = 0 args = () kw = {}
>>> f1(1, 2, c=3)
a = 1 b = 2 c = 3 args = () kw = {}
>>> f1(1, 2, 3, 'a', 'b')
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
>>> f1(1, 2, 3, 'a', 'b', x=99)
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
>>> f2(1, 2, d=99, ext=None)
a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}
高级特性
切片
选取一个范围内的元素
#设有一个列表
L = ['Michael','Sarah','Tracy','Bob','Jack']
#取前三个元素(左闭右开)
>>> L[0:3]
['Michael','Sarah','Tracy']
#若第一个索引是零,可以省略不写
>>> L[:3]
['Michael','Sarah','Tracy']
#python还支持倒数切片
>>> L[-2:]
['Bob','Jack']
>>> L[-2:-1]
['Bob']
#对于一个list可以进行跳跃取数
L = list(range(100))
>>> L[:10:2]#前10个数每两个取一个
[0,2,4,6,8]
PS:对于tuple和str也可以进行切片操作,不过tuple切片结果是tuple,str切片结果是str
迭代
python中只要是可迭代对象都可以进行迭代,通过 collections模块的Iterable类型判断 当前对象是否可迭代
>>> from collections import Iterable
>>> isinstance('abc',Iterable)#str是否可迭代
True
>>> isinstance([1,2,3],Iterable)#list是否可迭代
True
>>> isinstance(123,Iterable)#整数是否可迭代
False
python中内置的 enumerate 函数可以吧一个list变成 索引-元素对
for i, value in enumerate(['A', 'B', 'C']):
print(i,value)
结果:0 A 1 B 2 C
注意 python中for循环内经常可以同时引用两个变量
for x, y in [(1, 1),(2, 4), (3, 9)]:
print(x, y)
结果: 1 1
2 4
3 9
#可以对字典的key和value进行取值
d = {'x': A, 'y': B, 'z': C}
for k,v in d.items():
print(k,'=',v)
结果: y = B
x = A
z = C
列表生成式
List Comprehensions是python中内置的用来创建list的生成式
>>> [x * x for x in range(1,11)]#生成0~10的平方数的list
[1,4,9,16,25,36,49,64,81,100]
>>> [x * x for x in range(1,11) if x % 2 == 0]#前10个偶数的平方数
[4,16,36,64,100]
>>> [m + n for m in 'ABC' for n in 'XYZ']#生成全排列
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
生成器
在python中可以不必创建完整的list,而采用一种边循环边计算的机制就是生成器: generator
g = (x * x for x in range(10))
>>> next(g)
0
#generator是可迭代对象所以可以采用for循环
for n in g:#这种方法不会产生StopIteration错误
print(n)
#generator还可以在函数中,yield就是关键字
'''在执行过程中遇到yield就中断,下一次继续执行,
若想获取return语句的值就需要处理StopIteration异常'''
def odd():
print('step 1')
yield 1
print('step 2')
yield(3)
print('step 3')
yield(5)
>>> o = odd()
>>> next(o)
step 1
1
>>> next(o)
step 2
3
>>> next(o)
step 3
5
迭代器
可以直接作用于for循环的数据类型有:
一、集合数据类型,如:list、tuple、dict、set、str等
二、generator,包括:生成器和带yield的generator function
这些统称为可迭代对象:Iterable,不仅可以用于for循环还可以被next()函数调用
可以被next()函数调用并返回下一个值的对象成为迭代器:Iterator
*generator都是Iterator对象,list、dict、str不是Iterator,但是可以采用 **iter()*函数将Iterable转变成Iterator
函数式编程
高阶函数
python中变量可以指向函数,一个函数可以接收另一个函数作为参数,这种函数成为高阶函数
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))
[1,4,9,16,25,36,49,64,81]
reduce()函数接收两个参数,一个是函数,一个是序列,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算
reduce(f,[x1,x2,x3,x4]) = f(f(f(x1,x2),x3),x4)
#对一个序列求和
from functools import reduce
def add(x,y):
return x + y
reduce(add,[1,3,5,7,9])
25
filter
python内置filter()函数用于过滤序列,filter()函数接收一个函数和一个序列,根据返回值是True还是False决定保留还是丢弃该元素
#删除一个list中的偶数,只保留奇数
def is_odd(n):
return n % 2 == 1
list(filter(is_odd,[1,2,4,5,6,9,10,15]))
结果:[1,5,9,15]
#删除一个序列中的空字符串
def not_empty(s):
return s and s.strip()
list(filter(not_empty,['A','','B',None,'C',' ']))
结果:['A','B','C']
sorted
sorted()可以对list进行排序,还可以接收一个key函数来实现自定义排序
#按绝对值排序
sorted([36,5,-12,9,-21],key = abs)
结果:[5,9,-12,-21,36]
#字符串排序
sorted(['bob', 'about', 'Zoo', 'Credit'],key = str.lower)
结果:['about', 'bob', 'Credit', 'Zoo']
#sorted()函数默认升序排序,若想要反向排序,可以传入第三个参数reverse=True
sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
结果:['Zoo', 'Credit', 'bob', 'about']
返回函数
python中可以把函数作为结果返回
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
#当调用lazy_sum()时,返回的结果是求和函数
f = lazy_sum(1,3,5,7,9)
f()
25
闭包
返回函数不要引用任何循环变量,或者后续会发生变化的变量
匿名函数
关键字 lambda表示匿名函数,冒号前面的变量表示函数参数,匿名函数只能有一个表达式,返回值就是该表达式的结果
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等价于
def f(x):
return x * x
装饰器
函数也是一个对象,函数对象有一个 **__name__**属性,可以拿到函数的名字
def now():
print('2019-10-3')
>>> now.__name__
'now'
在代码运行期间动态增加功能的方式成为 装饰器(Decorator)
#想要在函数调用前后自动打印日志,但是不修改now()函数的定义
def log(func):
def wrapper(*args,**kw):
print('call %s()' % func.__name__)
return func(*args,**kw)
return wrapper
#可以看出decorator是一个返回函数的高阶函数
@log
def now():
print('2019-10-2')
>>> now()
call now()
2019-10-2
#使用functools.wraps可以防止返回函数的名字被修改
import functools
def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('call %s():' % func.__name__) return func(*args, **kw)
return wrapper
#针对带参数的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
偏函数
python的functools模块提供了很多有用的功能,其中一个就是偏函数(Partial function) 非数学意义上的偏函数
#int()函数可以将字符串默认按十进制转换,还有一个base参数,可以按照我们想要的进制转换
>>> int('12345',base = 8)
5349
#functools.partial就是帮我们创建一个偏函数,把一个函数的某些参数给固定住,返回一个新函数,调用这个新函数会更简单
import functools
int2= funtools.partial(int,base = 2)
>>> int2('1000000')
64
#注意,int2仅仅把参数base的默认值设定为2,仍可以传入其他的值
>>> int2('1000000',base = 10)
1000000
模块
在Python中,一个.py文件称为一个模块(Module)
使用模块
#!/usr/bin/env python3 #让这个py文件直接在Unix/Linux/Mac上运行
#-*- coding: utf-8 -*- #表示这个py文件本身使用标准UTF-8编码
' a test module ' #模块的文档注释,任何模块代码第一个字符串被视为文档注释
__author__ = 'difendDF'
import sys #导入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()
面向对象编程
类和实例
定义类用 class关键字,紧接着类名,类名通常是大写开头的单词,紧接着是(object),表示从哪个类继承下来,类中属性的初始化采用 **__init__**方法
class student(Object):
#参数self均不用传参
def __init__(self,name,score):
self.name = name
self.score = score
def print_score(self):
print('%s : %s' % (self.name,self.score))
访问限制
python中类也有共有和私有之分,如果想让内部属性不被外部访问,可以把属性名称前加两个下划线__,实例中变量名如果以 __ 开头就变成了一个私有变量
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))
python中 以双下划线开头,双下划线结尾的变量是特殊变量
获取对象信息
**type()**函数可以判断对象类型
>>> type(123)
<class 'int'>
>>> type('str')
<class 'str'>
>>> type(None)
<type(None) 'NoneType'>
>>> type(abs)
<class 'builtin_function_or_method'>
>>> type(a)
<class '__main__.Animal'>
>>> 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
要判断class类型可以使用**isinstance()**函数
>>> isinstance([1, 2, 3], (list, tuple))
True
>>> isinstance((1, 2, 3), (list, tuple))
True
如果要获得一个对象的所有属性和方法,可以使用**dir()**函数,返回一个包含字符串的list
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
>>> setattr(obj,'y',19) #设置一个属性‘y’
>>> getattr(obj,'y') #获取属性‘y’
19
>>> getattr(obj,'z',404) #获取属性'z',若不存在则返回默认值404
面向对象高级编程
使用__slots__
python是动态语言,我们可以随时给class的实例添加属性或方法,但是如果想要限制实例的属性的话就需要**__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'
注意:__slots__定义的属性仅对当前类实例起作用,对继承的子类不起作用
定制类
__str__
>>> class Student(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Student object (name: %s)' % self.name
>>> print(Student('Michael'))
Student object (name: Michael)
现
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'
注意:__slots__定义的属性仅对当前类实例起作用,对继承的子类不起作用
定制类
__str__
>>> class Student(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Student object (name: %s)' % self.name
>>> print(Student('Michael'))
Student object (name: Michael)