Python学习笔记

【Python解释器:】
CPython:官方默认解释器,使用C语言开发的,命令行中使用该版本的解释器;
IPython:在CPython基础之上开发,交互方式上有所增强;
PyPy:采用动态编译技术,可以显著提高Python代码的执行速度,绝大部分Python代码都可以在PyPy下运行,但是PyPy和CPython有一些是不同的,导致相同的Python代码在两种解释器下执行可能会有不同的结果;
Jython:是运行在Java平台上的Python解释器,可以直接把Python代码编译成Java字节码执行
IronPython:IronPython和Jython类似,只不过IronPython是运行在微软.Net平台上的Python解释器,可以直接把Python代码编译成.Net的字节码。
(总结:Python的解释器很多,但使用最广泛的还是CPython。如果要和Java或.Net平台交互,最好的办法不是用Jython或IronPython,而是通过网络调用来交互,确保各程序之间的独立性。)

【Python交互模式的进入和退出:】
1.打开CMD,输入Python,界面出现如下字符串,即进入成功,如果失败,查看环境变量是否配置成功;
Python 3.4.4 (v3.4.4:737efcadf5a6, Dec 20 2015, 20:20:57) [MSC v.1600 6
Type "help", "copyright", "credits" or "license" for more information.
>>>
2.输入exit(),即可退出交互模式;

【Python文件运行:】
进入交互模式,输入python hello.py,即可执行python脚本文件

【Python编写工具:】
1.文本编辑器:Sublime Text、Notepad++等;(不能使用电脑自带的记事本)
2.IDE工具:Eclipse插件、PyCharm等;

【Python注解、缩进】
单行注释:#
多行注释:/**/
缩进为四个空格

【Python数据类型】
整数(精确计算,没有大小限制)
浮点数(存在计算误差,没有大小限制,但是超出一定范围就直接表示为inf)
字符串(使用''或者""包裹,转义使用反斜杠,r''不转义,'''...'''换行)
布尔值(True,False)
空值(None)

【Python变量】
变量的实际值为"="右边对象的内存首地址


【Python常量】
通常用大写的字符表示常量

【Python字符编码】(# -*- coding: utf-8 -*-)
>>>'中文'.encode('utf-8')
b'xe4xb8xadxe6x96x87'
>>>b'xe4xb8xadxe6x96x87'.decode('utf-8')
'中文'
# 如果bytes中只有一小部分无效的字节,可以传入errors='ignore'忽略错误的字节:
>>> b'xe4xb8xadxff'.decode('utf-8', errors='ignore')
'中'
# len()函数计算的是str的字符数,如果换成bytes,len()函数就计算字节数:
>>> len('ABC')
3
>>> len('中文')
2
>>> len(b'ABC')
3
>>> len(b'xe4xb8xadxe6x96x87')
6
>>> len('中文'.encode('utf-8'))
6

【Python字符串格式化】
>>> print('%2d-%02d' % (3, 1))
3-01
>>> print('%.2f' % 3.1415926)
3.14
常见的占位符有:
占位符 替换内容
%d 整数
%f 浮点数
%s 字符串
%x 十六进制整数
format()
>>> 'Hello, {0}, 成绩提升了 {1:.1f}%'.format('小明', 17.125)
'Hello, 小明, 成绩提升了 17.1%'

【Python列表(list)处理】(可变的有序集合)
申明:list = [1,2,3]
长度:len(list)
取值:list[i](从0开始)
赋值:list[i] = 5
新增值:
在最后添加: list.append(4)
在第i位添加: list.insert(i, 'a')
删除值:
在最后删除: list.pop()
删除第i位: list.pop(i)

【Python元祖(tuple)处理】(不可变的有序集合)
申明:tuple = (1,2,3),当只有一个元素的时候元素后面加上逗号
长度:len(tuple)
取值:tuple[i](从0开始)

【Python字段(dict)处理】(可变无序集合)
申明:dict = {'name': 'test', 'age': 18}
长度:len(dict)
取值:dict[name] 或者 dict.get('name', '1') 其中当'name'不存在时返回'1'
赋值:dict[age] = 5
检验key是否存在:'address' in dict
删除:pop('name')
字典的key是不可变对象,所以list不能做key

【Python集合(set)】(无序无重复数据的key集合)
申明:set = set([1, 1, 2, 3]) 结果:{1, 2, 3}
长度:len(set)
新增值:set.add(1)
删除值:set.remove(1)
交集: {1, 2, 3} & {2, 3, 4}
并集: {1, 2, 3} | {2, 3, 4}

【Python条件判断】
age = input()
age = int(age)
if age < 6:
print('child')
elif age>=6 and age<18:
print('your age is', age)
else:
print('adult')

【Python循环】
break和continue都可用
第一种:
for str in list(range(10)):
print(str)
第二种:
n = 0
while n<10:
print(n)
n += 1
print(n)

【Python函数】
def test(name):
print('hello', name)
pass功能占位符
#函数真实的返回值是一个tuple!但是,在语法上,返回一个tuple可以省略括号,而多个变量可以同时接收一个tuple,按位置赋给对应的值,所以,Python的函数返回多值其实就是返回一个tuple,但写起来更方便。
1.位置参数
def fun(x, y):
pass
2.默认参数
def fun(x, y=5):
pass
#一是必选参数在前,默认参数在后,否则Python的解释器会报错
#使用默认参数有什么好处?最大的好处是能降低调用函数的难度。
#定义默认参数要牢记一点:默认参数必须指向不变对象!(http://www.cnblogs.com/wuchenggong/p/9505119.html)
3.可变参数
def calc(*numbers):
pass
#调用calc(1, 2, 3)
相当于:
将参数转变成tuple:(1, 2, 3)
将列表赋给numbers
4.关键字参数
def person(name, age, **kw):
pass
#调用person(1, 2, city='shanghai',phone=12345678901)
相当于:
将参数转变成dict:{'city': 'shanghai', 'phone': 12345678901}
将字典赋给kw
5.命名关键字参数
def person(name, age, *, city, job):
pass
#使用"*"分隔固定参数和关键字参数,且只能传指定key的关键字参数
#当存在可变参数时,无需"*"分隔,例如def person(name, age, *numbers, city, job)
6.参数组合
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
7.递归函数(看到最后...^-^)
a.使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。
b.解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。
c.尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。
d.遗憾的是,大多数编程语言没有针对尾递归做优化,Python解释器也没有做优化,所以,即使把上面的fact(n)函数改成尾递归方式,也会导致栈溢出。

【Python切片】
语法:list[begin:end:gap]
范围:大于等于begin,小于end(当begin为空时,从0开始;当end为空时,从-1结束)
gap:相邻两个元素的倍数
字符串和tuple也可以切片,且返回的数据类型不变

【Python迭代】
list或者tuple或者字符串: for ... in ...
dict:
key迭代: for key in dict:
value迭代: for value in dict.values():
key-value迭代: for k, v in dict.items():
##判断一个对象是否可以迭代:
导入collections模块的iterable类型:from collections import Iterable
isinstance('abc', Iterable) #abc是否可以迭代,返回boolean类型
##迭代带下角标list:
for i, value in enumerate(list):

【Python列表生成式】
例子:list = [i * j for i in range(1, 11) for j in range(1, 11) if i % 2 == 0 and j <= 5]
i*j:变量表达式
for i in range(1, 11): 循环变量, [1,10),存在多个相当于内嵌多个循环
if i % 2 == 0 and j <= 5: 循环限制条件

【Python生成器(generator)】
在Python中,这种一边循环一边计算的机制,称为生成器:generator。
第一种:
将列表生成式的"[]"改成"()",即可生成一个generator
获取generator元素:next(g)
第二种:
如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中.对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。

【Python迭代器】
迭代对象(Iterable):
一类是集合数据类型,如list、tuple、dict、set、str等;
一类是generator,包括生成器和带yield的generator function。
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。
迭代器(Iterator):
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。(类似generator.
迭代对象和迭代器转换:Iterator = iter(Iterable)
这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算.

【Python函数式编程】
函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。
函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!
Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。

【Python高阶函数】
可以接受函数对象为参数的函数,叫做高阶函数
例如 x = fun()
其中:
x为函数的返回值;
fun为函数名,相当于一个变量,指向函数对象;
fun()为函数调用;

【Python高阶函数之map/reduce】
map函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。
reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,
使用reduce方法前,需要先引入from functools import reduce

【Python高阶函数之filter】
filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。返回为Iterator,由于filter()使用了惰性计算,所以只有在取filter()结果的时候,才会真正筛选并每次返回下一个筛出的元素。

【Python高阶函数之sorted】
不传key:
例子: sorted([36, 5, -12, 9, -21])
数字类型按照大小排序;
字符串类型按照ascll排序;
传key:
例子: sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序

【Python返回函数】
高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回.
在一个函数中创建函数,并将这个函数的函数名返回,当程序接受该返回值时并没有进行函数调用,只有当主动进行函数调用才会运行,
且每次返回的函数都是一个新的函数对象.
例子:
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
#闭包
sum称为闭包
返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
例子1:
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs

f1, f2, f3 = count()
如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变
例子2:
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
综上:例子1和例子2都存储的是函数对象,区别在于例子2绑定了参数

【Python匿名函数】
lambda x: x * x
等价于
def f(x):
return x*x
lambda表示匿名函数
":"前面的x表示参数
":"后面表示函数体
函数返回值为表达式的值,本质上是一个函数对象

【Python装饰器】
在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
本质上,decorator就是一个返回函数的高阶函数。
例子1:
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('this is now method...')
@log相当于 now = log(now)
执行log()函数->返回未执行的wrapper函数对象,并由now变量指向该函数对象
此时now.__name__等于wrapper(使用@functools.wraps(func):自定义函数的name为now)
当now执行时now(),则实际上执行的是wrapper的函数体+func(*args, **kw)
依次实现类似java的aop功能
带参数
例子2:
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('this is now method...')
@log相当于 now = log('execute')(now) 得到一个wrapper对象

【Python偏函数】
当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。
int2 = functools.partial(int, base=2)
int('12345', base=2)等价于int2('12345')

【Python模块】
每一个包目录下面都会有一个__init__.py的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录,而不是一个包。__init__.py可以是空文件,也可以有Python代码,因为__init__.py本身就是一个模块,而它的模块名就是mycompany。
mycompany
├─ __init__.py
├─ abc.py
└─ xyz.py
sys.argv:获取传入参数,默认第一个参数为.py文件的名称
当前模块中Python解释器把一个特殊变量__name__置为__main__,当引入到其他模块时失效
作用域:
__xxx__:可被引用,但是有特殊含义
_xxx:可以被引用,但是不建议引用
__xxx:不能被引用,(python隐式转换成(对象._类名__xxx))

【Python第三方模块】
使用第三方包管理工具pip安装
pip install Pillow(包名)
pypi.python.org:该网站提供大量第三方包
>>>>>>>>且慢!有更好的方法!<<<<<<<<
https://www.anaconda.com/download/
Anaconda,这是一个基于Python的数据处理和科学计算平台,它已经内置了许多非常有用的第三方库,我们装上Anaconda,就相当于把数十个第三方模块自动安装好了,非常简单易用。

【Python面向对象编程】
a.类和实例
申明一个类:(object表示该类继承自哪一个类)
class Student(object):
pass
创建对象:student = Student()
设置属性:student.name
设置默认属性:
def __init__(self, name, score):
self.name = name
self.score = score
__init__:相当于构造函数
self:相当于this
和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,并且,调用时,不用传递该参数。除此之外,类的方法和普通函数没有什么区别,所以,你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。
b.访问限制
#在Python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name__、__score__这样的变量名。
#有些时候,你会看到以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。
#双下划线开头的实例变量是不是一定不能从外部访问呢?其实也不是。不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name,所以,仍然可以通过_Student__name来访问__name变量.
c.继承和多态
相同点:和java的思想一致;
不同点:鸭子类型
当一个A类具有某个方法M,另外一个B类即使不去继承A类,但只要也具有方法M,那么isinstance(B, A)同样会返回True
##Python多重继承(java不允许多继承)
MixIn
class Dog(Mammal, RunnableMixIn, CarnivorousMixIn):
pass

【Python获取对象信息】
1.获取对象类型
a.常规类型
引入types模块:import types
type(fun) == types.FunctionType
b.isinstance()
object->Animal->Dog
isinstance(dog, Dog) >>>>>>>True
isinstance(dog, Animal) >>>>True
isinstance(dog, object) >>>>True
2.获取对象所有属性和方法
dir(obj)
3.操作对象属性和方法
setattr():设置属性
hasattr():判断属性是否存在
getattr():获取属性
obj = object()
setattr(obj, 'name', 'jl')
hasattr(obj, 'name')
getattr(obj, 'name') 或者 getattr(obj, 'age', 17) 当属性不存时返回默认参数

【Python实例属性和类属性】
在编写程序的时候,千万不要对实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性。

【Python给类和实例绑定成员】
class Test(object):
pass
test = Test()
1.给实例绑定属性和方法,则只有该实例可以使用;给类绑定属性和方法则所有实例都可以使用
2.限制实例属性
为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
class Student(object):
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
3.校验属性
把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值
例子:
class Student(object):

@property
def score(self):
return self._score

@score.setter
def 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

【Python定制类】
1.__str__()
类似java的toString()
2.__repr__()
功能和__str__()一样,前者是print触发的
3.__iter__()
实现for ... in语法需要提供的函数,与__next__()连用才能生效
4.__getitem__()
用于实现按照下标获取元素,也可兼容切片(没有对step和负数参数做处理)
5.__setitem__()
用于给对象赋值
6.__delitem__()
用于删除对象
7.__getattr__()
用于调用不存在的属性时,预防报错,且只有当对象获取不存在的属性时,才会调用该方法,当该方法中没有特殊处理的属性,一律返回None
8.__call__()
实例调用,实现该方法可以将对象当成函数使用
使用callable(obj),返回True能被调用,False不能被调用

【Python枚举类】
1. 枚举的定义
class Color(Enum):
red = 5
blue = 1
yellow = 1
1.1 定义枚举时,成员名称不允许重复
1.2 默认情况下,不同的成员值允许相同。但是两个相同值的成员,第二个成员的名称被视作第一个成员的别名 
1.3 如果枚举中存在相同值的成员,在通过值获取枚举成员时,只能获取到第一个成员
1.4 如果要限制定义枚举时,不能定义相同值的成员。可以使用装饰器@unique【要导入unique模块(from enum import Enum, unique)】
2. 枚举取值
2.1 通过成员的名称来获取成员
2.2 通过成员值来获取成员
2.3 通过成员,来获取它的名称和值
3. 迭代器
3.1 枚举支持迭代器,可以遍历枚举成员
3.2 如果枚举有值重复的成员,循环遍历枚举时只获取值重复成员的第一个成员
3.3 如果想把值重复的成员也遍历出来,要用枚举的一个特殊属性__members__
for color in Color.__members__.items():
print(color)
4. 枚举比较
4.1 枚举成员可进行同一性比较(is)
4.2 枚举成员可进等值比较(==)
4.3 枚举成员不能进行大小比较
(参考:https://www.cnblogs.com/ucos/p/5896861.html)

【Python元类】
一.type()
类的数据类型为"type"
类的实例的数据类型是"模块.类名"
通过type()创建一个类:
Hello = type('Hello', (object,), dict(hello=fn))
1.参数1:class的名称;
2.参数2:继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
3.参数3:class的方法名称与函数绑定,这里我们把函数fn绑定到方法名hello上。
二.metaclass
metaclass,直译为元类,简单的解释就是:
当我们定义了类以后,就可以根据这个类创建出实例,所以:先定义类,然后创建实例。但是如果我们想创建出类呢?那就必须根据metaclass创建出类,所以:先定义metaclass,然后创建类。连接起来就是:先定义metaclass,就可以创建类,最后创建实例。
例子:
# metaclass是类的模板,所以必须从`type`类型派生:
class ListMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs['add'] = lambda self, value: self.append(value)
return type.__new__(cls, name, bases, attrs)
class MyList(list, metaclass=ListMetaclass):
pass
当我们传入关键字参数metaclass时,魔术就生效了,它指示Python解释器在创建MyList时,要通过ListMetaclass.__new__()来创建,在此,我们可以修改类的定义,比如,加上新的方法,然后,返回修改后的定义。
__new__()方法接收到的参数依次是:
1.当前准备创建的类的对象;
2.类的名字;
3.类继承的父类集合;
4.类的方法集合。

原文地址:https://www.cnblogs.com/jinloooong/p/9609392.html