学习笔记:廖雪峰的官方网站https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000
1 输入和输出
print(“hello”, “world”)
多个字符串依次打印,遇到逗号会输出空格; name=input(‘please enter your name’)
让用户从电脑输入一些字符,返回str; #
是注释;
每一行都是一个语句,语句以冒号:结尾时缩进的语句为代码块,一般缩进为4个空格; Python是大小写敏感的。
2 数据类型
(1) 整数:1,-9,300;
(2) 浮点数:1.23,3.14,-9.01;
(3) 字符串:单引号或双引号成对括起来的文本,三引号’’’…’’’
表示多行内容; 转义符来转义字符;
r’\n\’
表示引号内部的字符串默认不转义;
字符串是不可变对象,调用对象自身的任意方法,也不会改变该对象自身的内容。相反,这些方法会创建新的对象并返回,这样,就保证了不可变对象本身永远是不可变的。
a = 'abc'
b = a.replace('a', 'A')
b='Abc'
b是新创建的, a不变。
(4) 布尔值:True, False。非零为真。 int(‘4.0’)强制转换,float(),str(),bool()强制转换
(5) list: 是可变的有序表,可以随时添加和删除其中的元素, list里面的元素的数据类型可以不同, list元素可以是另一个list。
s = ['python', 'java', ['asp', 'php'],'scheme']
s[2][1]=’php’
a=[1,2,’g’]
,len()
获取长度,索引从左到右是从0开始,反向是从-1开始。
a.append(‘a’)
追加元素到末尾 a.insert(2, 4)
插入元素到指定位置 a.pop()
删除末尾元素; a.pop(3)
删除指定位置的元素 直接赋值可以替换元素:a[1]=’sun’
(6) tuple一旦初始化就不能修改,只有1个元素的tuple定义时必须加一个逗号,
; t = ('a', 'b', ['A', 'B']) t[2][0] = 'X'
;
tuple一开始指向的list并没有改成别的list,所以,tuple所谓的“不变”是说,tuple的每个元素,指向永远不变。但指向的这个list本身是可变的。
(7) dict: 全称dictionary,使用键-值(key-value)存储,具有极快的查找速度,需要占用大量的内存,内存浪费多。
d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
d['Adam'] = 67
, 加一个键值对 判断key存在:‘a’ in d
或者 d.get(‘a’,-1)
删除key: d.pop(‘Adam’)
dict内部存放的顺序和key放入的顺序是没有关系的。dict的key必须是不可变对象。
(8) set : set和dict类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key。
重复元素在set中自动被过滤, 要创建一个set,需要提供一个list作为输入集合:
s = set([1, 2, 3])
s.add(4)
添加元素s.remove(4)
删除元素 set可以看成数学意义上的无序和无重复元素的集合,因此,两个set可以做数学意义上的交集&、并集|等操作;
3 变量
变量本身类型不固定,是动态语言即a=1或a=’w’,定义变量时不需要指定变量类型,可以把任意数值类型赋值给变量,同一个变量可以反复赋值,而且可以是不同类型的变量。
a=’w’执行时Python解释器做了两件事: (1)内存中创建’w‘字符串; (2)创建名为a的变量,并指向’w’。
4 格式化
常见的占位符有:%d整数,%f浮点数,%s字符串,%x十六进制整数;%s会把任何数据类型转换为字符串;
格式化整数和浮点数还可以指定是否补0和整数与小数的位数:’%2d,%02d’%(3,1)
字符串里面的%是一个普通字符就需要转义,用%%
来表示一个%;
5 条件判断与循环
if: elif: else:
for i in range(101):
while n>0:
range(101)是从零开始小于100的整数序列,在 循环中,break
语句可以提前退出循环。
在循环过程中,也可以通过continue
语句,跳过当前的这次循环,直接开始下一次循环。 Ctrl+C
退出程序,或者强制结束Python进程。
for key in d for value in d.values() for k, v in d.items()
for循环,作用于一个可迭代对象。通过collections模块的Iterable类型判断一个对象是可迭代对象
from collections import Iterable
isinstance('abc', Iterable)
Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身。
for循环里,可同时引用两个变量。
6 函数
函数名其实就是指向一个函数对象的引用,完全可以把函数名赋给一个变量,相当于给这个函数起了一个“别名”。
函数名其实就是指向函数的变量,也可把函数作为参数传入,这样的函数称为高阶函数。
在Python中,定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回。
pass可以用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。
Python的函数返回多值其实就是返回一个tuple, 而多个变量可以同时接收一个tuple,按位置赋给对应的值。
def mine(x,y):
if not isinstance(x, (int, float)): #数据类型检查
print('ERROR')
else:
n=str(x)
m=y*2
return m,n
7 函数的参数
(1) 位置参数:传入的值按照位置顺序传入
(2) 默认参数:默认参数必须指向不变对象
(3) 可变参数:传入的参数个数是可变的 def calc(*numbers):
numbers可以把多个参数,作为tuple传入;如有a=(1,2,3), calc(*a)
(4) 关键字参数:而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。
def person(name, age, **kw):
person('Bob', 35, city='Beijing')
也可以先组装出一个dict,然后,把该dict转换为关键字参数传进去: extra = {'city': 'B', 'job': 'E'}
person('Jack', 24, **extra)
(5) 命名关键字参数:如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收city和job作为关键字参数。
def person(name, age, *, city, job):
和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*
,*
后面的参数被视为命名关键字参数。
命名关键字参数可以有缺省值,从而简化调用。 如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了。
参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
8 高级特性
(1) 切片,L[a:b:c],包含a但不包含b, c是间隔。
(2) 列表生成式,把要生成的元素x * x放到前面,后面跟for循环, 可以加上if判断, 还可以使用两层循环 [x*x for x in range(1,10) if x%2==0]
(3) generator,循环的过程中不断推算出后续的元素 g = (x * x for x in range(10))
通过next()函数获得generator的下一个返回值generator也是可迭代对象,可以用for循环。
如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。
函数是顺序执行,遇到return语句或者最后一行函数语句就返回。
而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
直到最后抛出StopIteration
错误表示无法继续返回下一个值了。
(4) Iterator, 可以被next()函数调用并不断返回下一个值的对象称为迭代器 可以使用isinstance()判断一个对象是否是Iterator
from collections import Iterator
isinstance((x for x in range(10)), Iterator)
凡是可作用于for循环的对象都是Iterable类型; 凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象
9 高阶函数
(1) map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。list(map(str, [1, 2, 3]))
(2) reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算。from functools import reduce
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
(3) filter()也接收一个函数和一个序列。filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。filter()
函数返回的是一个Iterator
.
(4) sorted()排序sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
10 函数式编程
(1) 高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。
调用lazy_sum()
返回函数,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,称为闭包。
返回的函数并没有立刻执行,f=lazy_sum(1,2,3) 调用了 f()函数才执行。
返回函数不要引用任何循环变量,或者后续会发生变化的变量。
如果一定要引用循环变量,方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变。
def lazy_sum(*args):
def sum():
ax=0
for n in args:
ax=ax+n
return ax
return sum
(2) 匿名函数, 关键字lambda表示匿名函数,冒号前面的x表示函数参数, 冒号后面是表达式。lambda x: x * x
(3) 装饰器
(4) 偏函数,当函数的参数个数太多,需要简化时,使用functools.partial
可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。
11 模块
每一个包目录下面都会有一个__init__.py
的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录,而不是一个包。
__init__.py
可以是空文件,也可以有Python代码,因为__init__.py
本身就是一个模块。
类似__xxx__
这样的变量是特殊变量,可以被直接引用,但是有特殊用途,比如上面的__author__,__name__
就是特殊变量。
类似_xxx
和__xxx
这样的函数或变量就是非公开的(private),不应该被直接引用,比如_abc,__abc
等;
12 类
(1)由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。
通过定义一个特殊的__init__
方法。__init__
方法的第一个参数永远是self,表示创建的实例本身,
因此,在__init__
方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。
方法就是与实例绑定的函数,和普通函数不同,方法可以直接访问实例的数据;
和静态语言不同,Python允许对实例变量绑定任何属性如bart.age
。
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)
bart.age=12
(2)如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__
,
在Python中,实例的变量名如果以__
开头,就变成了一个私有变量(private)self.__name=name
,外部代码要获取name, 可以给Student类增加方法.
(3)继承可以把父类的所有功能都直接拿过来,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写。
(4)isinstance()判断的是一个对象是否是该类型本身,或者位于该类型的父继承链上。isinstance([1, 2, 3], (list, tuple)
;
dir()函数获得一个对象的所有属性方法;
getattr()、setattr()以及hasattr(),可以直接操作一个对象的属性或方法;getattr(obj, 'z', 404) # 获取属性'z',如果不存在,返回默认值404
(5)类属性,直接在class中定义属性。相同名称的实例属性将屏蔽掉类属性。
(6)给实例绑定一个方法,
s = Student()
def qage(self,age):
self.age=age
from types import MethodType
s.age=MethodType(qage,s)
s.age(9)
给类绑定方法,给class绑定方法后,所有实例均可调用 Student.qage=qage
想要限制实例的属性, 在定义class的时候,定义一个特殊的__slots__
变量,来限制该class实例能添加的属性. class Student(object):
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
_slots__
定义的属性仅对当前类实例起作用,对继承的子类是不起作用的, 除非在子类中也定义_slots__
这样,子类实例允许定义的属性就是自身的_slots__
加上父类的`slots_。
(7)Python内置的@property装饰器就是负责把一个方法变成属性调用的。
class Student(object):
@property
def age(self):
return self.__age
@age.setter
def age(self,value):
if not isinstance(value,int):
raise ValueError('wrong')
self.__age=value
(8)__str__:
print出实例,不但好看,而且容易看出实例内部重要的数据。 直接显示变量调用的不是__str__()
而是__repr__()
两者的区别是__str__()
返回用户看到的字符串,而__repr__()
返回程序开发者看到的字符串,也就是说__repr__()
是为调试服务的。__repr__()
定义后可直接显示。
class a(object):
def __init__(self,name):
self.__name=name
def __str__(self):
return 'hello %s'%self.__name
__repr__=__str__