《Python基础编程》笔记

第一章 基础知识

  • 让脚本像普通程序一样运行:代码首句 #!/usr/bin/env python告诉系统这是py文件,默认用py解释程序运行。(可惜我电脑.py文件默认打开方式是pycharm…)

  • ‘ # ‘ 行注释。

  • ’\‘ 转义字符,eg:print(‘Let\\’ go!’)>> let’s go!

  • ‘’’ ‘’’ 长字符串:需要写一个跨多行或者包含特殊字符的字符串,用’’’代替普通引号。

  • r 原始字符串: 输出与原始字符串里每一个保持一致;eg:print(r’Let/‘s go!’)>> Let/‘s go!

  • u Unicode字符串:py3.x中所有字符串都是Unicode编码

第二章 列表和元组

  • 序列:Py含有六种内建序列:列表[],元组(),字符串,Unicode字符串,buffer对象,xrange对象。

  • 列表可以修改,元组不能修改

  • 通用序列操作:

    • 索引:访问单个元素
      • 从0开始,可以有负值(从右往左)eg: s=’hello’s[-1] = ‘o’;
      • 一个函数返回值是序列,就可以直接对结果进行索引操作
    • 分片:访问一定范围内元素,是一种优雅的写法
      • 格式:number[a: b : c] 序列number从起点a到b以步长c的集合。a可为空,默认0,b可为空,默认结尾,c可为空可省略,默认1.即 number[:]表示全部。
      • eg:number=[1,2,3,4,5,6,7,8,9,10]; number[1,-2,2] >>[2,4,6,8]
    • 序列相加:通过’+’可以进行序列连接操作
    • 序列相乘:eg:初始化一个长度为10列表 sequence=[None]*10
    • 成员资格:‘in’ 判断一个值是否在序列里,也可以判断字符串是不是另一个子串。
    • 长度,最小值,最大值:内建函数len(),min(),max()
  • 列表list:[]

    • list函数:字符串->list:list(‘hello’) =[‘h’,’e’,’l’,’l’,’o’]
    • 将一个字符构成的列表->字符串:’’.join([‘h’,’e’,’l’,’l’,’o’])
    • 删除元素: del list[index]
    • 分片赋值:
      • 可以使用与原序列不等长序列将分片替换:
        eg: name=list(‘Perl’) name[1:]=list(‘ython’)
          name >>['P','y','t','h','o','n'];
        
      • 分片可以在不需要替换任何原有元素的情况下插入新的元素:
        eg: number=[1,5];number[1:1]=[2,3,4]; number >>[1,2,3,4,5]
      • 以此类推,分片删除也是可行的:
        eg: number=[1,2,3,4,5]; number[1:4]=[]; number >>[1,5]
    • append(val):在末尾添加元素
    • count(val):统计某元素在列表出现的次数
    • extend([]):在末尾添加多个值,比如添加一个列表里所有元素。
    • index(val):在列表里找到某个值第一个匹配的索引位置
    • insert(index,val):在index位置插入一个对象
    • pop(index):会移除列表里index位置元素,默认是最后一个,并且返回该值。
    • remove(val):删除第一个匹配val的元素,没有返回值
    • reverse():方向反转
    • sort():无返回值,注意;sorted()函数返回排好列表;
    • 高级排序,重写cmp(),sort(cmp)

-元组tuple:() 不可变序列

  • 实现一个值的元组需要加逗号:eg : (42,)
    • tuple() 函数:和list函数类似
    • 除了创建,访问元组,没有太多操作。访问也可以用索引,切片。

第三章 使用字符串

  • 基本字符串和前面序列操作类似,但字符串是不可变,初始化后就不能赋值。
  • 字符串格式化:用% 实现 eg: print(‘Price of eggs $%d’ % 42)
  • 常用方法:

    • find(val,start,end):在一个字符串里查找子字符串val,返回子串所在位置的最左端索引。没有找到返回-1.支持提供起点start,终点end。

    • val.join(list):将一个全是字符的list用val字符连接起来组成一个新的字符串。

    • lower():返回字符串小写字母版

    • replace(‘A’,’B’):将字符串子串中’A’全部替换为’B’

    • ‘str’.split(‘A’):是join的逆方法,用A将字符串str切割成序列。
      eg:‘1+2+3+4+5’.split(‘+’) >> [‘1’,’2’,’3’,’4’,’5’];
      如果不提供分隔符,会默认空格作为分隔符.

    • strip():返回除去字符串两侧空格后的字符串

    • translate(table): 需要先完成一张转换表:转换表是以某字符替换某字符的对应关系。

      利用string里 maketrans():接收两个等长字符串的参数,表示第一个字符串每个字符都用第二个字符串中对应字符代替。

      eg:

      1
      2
      3
      4
      from string import maketrans
      table=maketrans('cs','kz')
      'this is an incredibel test'.translate(table)
      >> 'thiz iz an inkredible tezt'

第四章:字典:当索引不好用时

  • 字典创建:

    • {} : phone={‘Alice’:’123’,’Bob’:’110’}
    • dict(): 用键值对(key,vaules)来建立字典
  • 基本操作:和序列很多类似

    • len()
    • d[k]
    • d[k]=v
    • del d[k]
    • k in d:检查字典d中含有键为k的项
  • 字典的键类型为不可变元素,如整型,浮点型,字符串。

  • 字典的格式化字符串:

    1
    2
    phone={'Beth':'9102','Alice':'2341','Cecil':'3258'}
    print("Cecil's phone number is %(Cecil)s." % phone)
  • 字典方法:

    • clear()
    • copy() :深复制
    • get(key,value):访问一个不存在的健返回Node而不报错,而且可以修改权值。
    • items iteritems:
    • keys iterkeys: keys将字典键以列表形式返回
    • values itervalues: values将字典值以列表形式返回,可以包含重复的元素
    • pop(k): 将键值为k的从字典移除
    • popitem():移出随机的项
    • setdefault(key,value): 如果key不存就是添加,如果key存在,不修改返回原value.
    • update(d): 用一个字典更新另一个字典,有相同的键会进行覆盖.

第五章 条件循环其他语句

  • print(,): 逗号隔开输出内容
  • import :导不同文件函数
  • 赋值魔法:

    • 序列解包(sequence unpacking):

      • 多个赋值: x,y,z=1,2,3
      • 交换两个变量: x,y=y,x

      当函数或者方法返回元组(或其他序列,可迭代对象)时,这个特性很好用。同时所解包的序列中的元素数量必须和放置在赋值符号=左边的变量数量完全一致,否则报错。

    • 链式赋值(chained assignment)是将一个值赋给多个变量的捷径(C++中不行)。eg: x=y=z;

    • 增量赋值:x+=1

  • 循环遍历字典元素:

    • 并行迭代: 可以用序号或者zip压缩
      eg: for name,age in zip(names,ages):
    • 编号迭代: 可以使用内建函数enumerate()
      eg:

      1
      2
      3
      for index,string in enumerate(strings):
      if XXXXX:
      Strings[index]='XXXX'
  • 循环外的else子句:神奇for里面有一个break循环下面的else就不执行,和C++不同。
    eg:找100到81之间最大平方数是81,例子中81是开区间取不到。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    for n in range(99,81,-1):
    root = sqrt(n)
    if root == int(root):
    print(n);
    break
    else:
    print("Didn't find it!")
    -------> Didn't find it!
  • 列表推导式-轻量级循环(list comprehension):

    eg :[x*x for x in range(10)] -> [0,1,4,9,16,25,36,49,64,81]

    能被3整除平方数: [x*x for x in range(10) if x%3==0] -> [0,9,36,81]

    元组也行:[(x,y) for x in range(3) for y in range(3)] -> [(0,0),(0,1),(0,2),(1,0),(1,1),(1,2),(2,0),(2,1),(2,2)]

  • pass :什么都不做,可以作为占位符

  • del:用来删除变量或者数据结构一部分
  • exec(str):用字符串执行python语句 eg:
    world')")```
    1
    - eval: 用于执行python求值语句,会有一个返回值。 eg:``` print(eval(input("")))

第六章 抽象

  • 创建函数:def

    1
    2
    3
    4
    5
    6
    def fibs(nums):
    '文档字符串'
    result=[1,1]
    for i in range(nums-2):
    result.append(result[-2]+result[-1])
    return result

    文档字符串访问可以用 fibs.doc 也可以用内建函数help()

  • 参数魔法:

    • 修改参数:传入参数是否被修改取决于该类型是否为可修改类型,如字符串,整形等不能修改,list,dict等都可以被修改:
      eg:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      def init(data):
      data['first']={}
      data['middle']={}
      data['last']={}
      def lookup(data,label,name):
      return data[label].get(name)
      def store(data,full_name):
      names=full_name.split()
      if len(names)==2:name.insert(1,' ')
      labels='first','middle','last'
      for label,name in zip(labels,names):
      people=lookup(data,label,name)
      if people:
      people.append(full_name)
      else:
      data[label][name]=[full_name]
    • 关键字参数和默认值:调用函数时候,指定哪个形参值是什么,不用考虑位置对齐的问题。

    • 收集参数:星号* 意思是收集其余位置参数放在元组里。
      eg:

      1
      2
      3
      4
      5
      6
      7
      8
      def print_params(title,*params):
      print(title)
      print(params)
      if __name__ == '__main__':
      print_params('Params',1,2,3)
      ---> Params
      (1, 2, 3)
      • 处理关键字参数的收集:两个 ** 关键字参数放在字典里
        1
        2
        3
        4
        5
        def print_params(**params):
        print(params)
        if __name__ == '__main__':
        print_params(x=1,y=2,z=3)
  • 递归:

    • 二分(返回序列里第一个等于位置,不存返回None):

      1
      2
      3
      4
      5
      6
      7
      8
      def search(sequence,number,lower=0,upper=None):
      if upper==None: upper=len(sequence)-1
      if upper<lower:
      if sequence[lower]==number : return lower
      else : return None;
      middle=int((lower+upper)/2);
      if sequence[middle]>=number: return search(sequence,number,lower,middle-1);
      else : return search(sequence,number,middle+1,upper);

      非递归版:

      1
      2
      3
      4
      5
      6
      7
      8
      def search2(sequence,number,lower=0,upper=None):
      if upper==None : upper=len(sequence)-1
      while lower<=upper:
      middle=int((upper+lower)/2)
      if sequence[middle]>=number:upper=middle-1;
      else:lower=middle+1
      if sequence[upper+1] != number: return None
      else: return upper+1

第七章 更加抽象

  • 创建自己的类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class Person:
    def setName(self,name):
    self.name=name
    def getName(self):
    return self.name
    def greet(self):
    print("Hello,world! I'm %s." % self.name)
    def __inaccessible(self):
    print("Bet you cann't see me")
    def accessible(self):
    print("The secret messsage is:")
    self.__inaccessible()
    if __name__ == '__main__':
    p1=Person()
    p1.setName('yexiaoju')
    p1.greet()
    p1.accessible()
    p1._Person__inaccessible()
  • python并不直接支持私有方式,为了让方法或者特性变为私有(从外部无法直接访问),只要在它的名字前面加上双下划线即可。如上面例子。需要访问__inaccessible()方法,得加_类名+方法。

第八章:异常

Python 用异常对象(exception boject)来表示异常情况。遇到错误后,会引发异常。如果异常对象并未被处理或捕捉,程序就会被所谓的回溯终止执行。

  • 捕捉异常(try/except):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    while True:
    try:
    x=int(input('Enter the first number:'))
    y=int(input('Enter the second number:'))
    print(x/y)
    except ZeroDivisionError:# 除0异常
    print("The second number can't be zero!")
    except TypeError:#输入类型异常
    print("That wasn't a number !")
    except:#捕捉所有上面漏掉的异常
    print('There is something wrong!')

    上面例子不止一个except,如果有异常会捕捉对应类型去接受,这里有ZeroDi…和TypeError两种.也可以用一个块去捕捉多个异常。用元组将他们列出:

    1
    except(ZeroDivisionError,TypeError,NameError):

    就算程序处理好几种类型的异常,但是还是有异常会漏掉,像上面例子最后一个except:没有表明捕捉什么类型异常就是捕捉所有异常。

  • raise 语句:引发异常,可以用一个Exception异常类或者自定义异常来被raise调用。 eg: raise Exception

  • 自定义异常:继承EXception

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class MyException(Exception):
    def __init__(self,message):
    Exception.__init__(self)
    self.message=message
    if __name__ == '__main__':
    a = int(input("please input a num:"))
    if a < 10:
    try:
    raise MyException("my excepition is raised ")# 引发自定义异常,进入下面的except模块里
    except MyException as e:
    print(e.message)
  • raise 不带参数:相当于没有异常处理,又抛出这个异常信息。
    下面一个例子显示一个switch控制异常是否屏蔽的机制。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class MufiedCalcul:
    switch=False
    def cal(self,expr):
    try:
    return eval(expr)
    except ZeroDivisionError:
    if self.switch:
    print("Division by zero is illege")
    else :
    raise
  • 万事大吉(try/except/else):

    • 异常没有发生执行一段代码,可以在后面加一个else。
    • 不知道异常信息也可以打印出来。
1
2
3
4
5
6
7
8
9
10
11
while True:
try:
x=int(input('Enter the first number:'))
y=int(input('Enter the second number:'))
print(x/y)
except Exception as e:
print("Invalid input:",e)
print("please try again!")
else:
print("No Error,Quit!")
break
  • 最后finally:它可以用来可能的异常后进行清理。

    1
    2
    3
    4
    5
    6
    7
    8
    try:
    1/0;
    except ZeroDivisionError:
    print("Unknow variable")
    else:
    print("That went well")
    finally:
    print("OK?")

    不管异常有没有执行,最后finally一定会执行。

  • 异常会递归回溯到直到函数调用的那一层。

  • 异常之禅:有些时候在判断字典或对象是否存在特性时,条件语句可以实现和异常处理一样的功能,两者各有千秋。

第九章:魔法方法,属性和迭代器

  • 构造方法:init()

    1
    2
    3
    4
    5
    6
    7
    class FooBar:
    def __init__(self):
    self.somevar=42;
    if __name__ == '__main__':
    b=FooBar()
    print(b.somevar)
  • 继承:新的类的构造方法需要初始化父类的构造方法,防止父类有些特性没有继承过来。具体方法使用super函数。

  • Super函数:超类(父类)函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    class Bird:
    def __init__(self):
    self.hungry=True;
    def eat(self):
    if self.hungry== True :
    print('Aaaaah')
    self.hungry=False
    else : print("No,thanks!")
    class SongBird(Bird):
    def __init__(self):
    super(SongBird, self).__init__()#super()也可以不带参数
    self.sound="Squawk"
    def sing(self):
    print(self.sound)
    if __name__ == '__main__':
    sb=SongBird()
    sb.eat()
    sb.eat()
    sb.sing()
    • 基本序列和映射规则:
      序列和映射是对象的集合,如果对象是不可变那么只有下面前两个魔法,如果可变则可以使用下面四个魔法:

      • len(self): 返回数目
      • gettitem(self.key): 返回键值查询值,每次用索引查询都会调用这个方法
      • settitem(self.key,value): 根据索引属性key设置value
      • delitem (self,key): 删除

      实践,创建一个可以修改的无穷序列。实现了gettitem,settitem两个方法,因为是无穷的没有实现len,del方法,故调用的话就是非法报错。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      def checkIndex(key):
      if not isinstance(key,int): raise TypeError
      if key<0: raise IndexError
      class ArithmticSequence:
      def __init__(self,start=0,step=1):
      self.start=start
      self.step=step
      self.changed={}
      def __getitem__(self,key):
      checkIndex(key)
      try: return self.changed[key]
      except KeyError: return self.start+key*self.step
      def __setitem__(self, key, value):
      checkIndex(key)
      self.changed[key]=value
      if __name__ == '__main__':
      s=ArithmticSequence(1,2)
      print(s[4])
      s[4]=1
      print(s[4])
      • 子类化列表,字典和字符串:
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        class CountList(list):
        def __init__(self,*args):
        super().__init__(*args)
        self.counter=0
        def __getitem__(self, item):
        self.counter+=1
        return super().__getitem__(item)
        if __name__ == '__main__':
        c1=CountList(range(10))
        print(c1)
        del(c1[3:6])
        print(c1)
        c1[2]+=c1[4]
        print(c1.counter)
        --------------------------------
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
        [0, 1, 2, 6, 7, 8, 9]
        2
  • property 函数:

    • 将类方法转换为只读属性
    • 重新实现一个属性的setter和getter方法

eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Rectangle:
def __init__(self):
self.width=0
self.height=0
def setSize(self,size):
self.width,self.height=size
def getSize(self):
return self.width,self.height
size=property(getSize,setSize)
if __name__ == '__main__':
r=Rectangle()
r.width=10
r.height=5
print(r.size)
r.size=150,100

  • 迭代器 iter iter()返回一个迭代器(iterator),所谓迭代器就是具有 next(这个方法在调用时不需要任何参数)方法的对象。在调用next方法时,迭代器会返回它的下一个值。如果next方法被调用,但迭代器没有值可以返回,就会引起一个
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Fibs:
def __init__(self):
self.a=0
self.b=1
def __next__(self):
self.a,self.b= self.b,self.a+self.b
return self.a
def __iter__(self):
return self
if __name__ == '__main__':
f=Fibs()
for i in f:
if i >1000:
print(i)
break

迭代器实现了 iter方法,这个方法实际上返回迭代器本身。

  • 从迭代器的到序列:用list构造方法显式的将迭代器转换为列表。
1
2
3
4
5
6
7
8
9
10
11
12
class TestIterator:
value = 0
def __next__(self):
self.value += 1
if self.value > 10:raise StopIteration
return self.value
def __iter__(self):
return self
if __name__ == '__main__':
ti=TestIterator()
print(list(ti))
  • 生成器: 用普通函数定义的迭代器 yield

    • 这一段初看书,我也不是很懂,知乎上这个回答 不错。

    • 创建生成器:

      1
      2
      3
      4
      def flatten(nested):
      for sublist in nested:
      for element in sublist:
      yield element

      if name == ‘main‘:

      nested=[[1,2],[3,4]]
      for num in flatten(nested):
          print(num)
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      - 递归生成器:
      ​``` python
      def flatten(nested):
      try:
      for sublist in nested:
      for element in flatten(sublist):
      yield element
      except TypeError:
      yield nested
      if __name__ == '__main__':
      nested=[[1],2,[3,[4]]]]
      for num in flatten(nested):
      print(num)

    上面代码有一个问题,如果列表里是字符串对象,那它也是一个序列,是不会出现TypeError,所以修改一下需要对字符串判断。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    def flatten(nested):
    try:
    try:nested+''
    except:pass
    else :raise TypeError
    for sublist in nested:
    for element in flatten(sublist):
    yield element
    except TypeError:
    yield nested
    if __name__ == '__main__':
    nested=['123',['yexiaoju'],'memeda']
    for num in flatten(nested):
    print(num)
    • 通用来说生成器主要是由生成器函数和生成器迭代器组成。
  • 运用生成器编写递归问题:这一块我看了好久,输出中间变量才满满懂了一点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
def conflict(state,nextX):
nextY=len(state)
for i in range(nextY):
if abs(state[i]-nextX) in (0,nextY-i):
return True
return False
def queens(num,state=()): #运用生成器写(一段递归程序)八皇后问题
if len(state) ==num-1:
for pos in range(num):
if not conflict(state,pos):
yield (pos,)
else:
for pos in range(num):
if not conflict(state,pos):
for result in queens(num,state+(pos,)):
yield (pos,)+result
def queens2(num,state=()):#将上面程序稍微简化写法
for pos in range(num):
if not conflict(state,pos):
if len(state)==num-1:
yield (pos,)
else:
for result in queens2(num,state+(pos,)):
yield (pos,)+result
def prettyprint(solution):#将得到的八皇后结果模拟图像形象的输出
def line(pos,length=len(solution)):
return '.'*(pos)+'X'+'.'*(length-pos-1)
for pos in solution:
print(line(pos))
if __name__ == '__main__':
print(list(queens(8)))
print(len(list(queens(8))))
queens3(8)
import random
prettyprint(random.choice(list(queens(8))))

第十章:充电时刻

  • 模块:import

    • 使用dir:查看模块包含的内容
    • all():
    • help(): 获取帮助文本
  • 文档: doc 在线文档:http://python.org/doc

  • 使用源代码: file eg:print(copy. file)#输出文件本地路径,就可以查看文件代码

  • 标准库:

    • sys: 访问与python解释器联系紧密的变量和函数。

      1
      2
      import sys
      print(' '.join(reversed(sys.argv[1:]))) #反序打印命令行参数
    • os:提供访问多个操作系统服务的功能。

      1
      2
      3
      4
      5
      6
      import os
      import webbrowser
      if __name__ == '__main__': #通过命令打开程序
      os.system(r'D:\"CS 1.6"\"CS 1.6"\cstrike.exe') #文件夹名需要" "
      os.startfile(r'D:\CS 1.6\CS 1.6\cstrike.exe') # 接受一般的路径,含有空格也没有关系
      webbrower.open('mryxj.github.io')#启动浏览器打开特定网站
    • fileinput:

  • 集合:set():

  • 堆:heapq()

    • heappush(heap,x):将x入堆
    • heappop(heap):将堆中最小的元素弹出
    • heapreplace(heap,x) :将堆中最小元素弹出,并将x入堆
    • nlargest(n,iter): 返回iter中第n大的数
    • nsamallest(n,iter):返回iter中第n小的数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    from heapq import *
    from random import shuffle
    data=[1,2,3,4,5,6,7,8,9,10]
    shuffle(data)
    heap=[]
    for n in data:
    heappush(heap,n)
    heappush(heap,0.5)
    print(heap)
    ----> [0.5, 1, 2, 5, 3, 4, 9, 10, 8, 7, 6]
  • 双端队列:

    • append(x):右端增加一个元素x
    • appendleft(x):左端增加一个元素x
    • popleft(x): 左端删除一个元素x
    • roate(x):将右边前x个元素整体移到左端
    1
    2
    3
    4
    from collections import deque
    q=deque(range(5))
    q.append(5)
    q.appendleft(6)
  • time:获取当前时间,操作时间和日期。

  • random:
    • random(n):返回[0,n)之间随机数
    • getrandbits(n):以长整型形式返回n个随机数
    • uniform(a,b):返回随机数n,a<=n<b
    • randrange():
    • choice(seq):从序列seq中返回随意元素
    • shuffile(seq[,random]):
扫码也许会变得更强~!