python笔记

201 阅读10分钟

list切片

语法:
* start_index:表示是第一个元素对象,正索引位置默认为0;负索引位置默认为 -len(consequence)
* end_index:表示是最后一个元素对象,正索引位置默认为 len(consequence)-1;负索引位置默认为 -1。
* step:表示取值的步长,默认为1,步长值不能为0。

con[start_index]:返回索引值为start_index的对象。start_index为 -len(con)到len(con)-1之间任意整数。
con[start_index:end_index]:返回索引值为start_index到end_index-1之间的连续对象。
con[start_index:end_index:step]:返回索引值为start_index到end_index-1之间,并且索引值与start_index之差可以被step整除的连续对象。
con[start_index:]:缺省end_index,表示从start_index开始到序列中最后一个对象。
con[:end_index]:缺省start_index,表示从序列中第一个对象到end_index-1之间的片段。
con[:]:缺省start_index和end_index,表示从第一个对象到最后一个对象的完整片段。
con[::step]:缺省start_index和end_index,按照索引值与起始位置索引之差可以被步长整除的规律取值
  • 取前3个元素,用一行代码就可以完成切片:
>>> L[0:3]
['Michael', 'Sarah', 'Tracy']
  • L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3。即索引0,1,2,正好是3个元素。 如果第一个索引是0,还可以省略:
>>> L[:3]
['Michael', 'Sarah', 'Tracy']
  • 以从索引1开始,取出2个元素出来:
>>> L[1:3]
['Sarah', 'Tracy']
  • L[-1]取倒数第一个元素,那么它同样支持倒数切片,记住倒数第一个元素的索引是-1 取最后3个元素L[-3:],取最后2个元素,L[-3:-1],不包括最后的[-1]
str='12345678'
print(str[-3:-1])
  • L[:]取所有元素,可以用于列表的浅复制
L1 = [1,2,3,4,5]
L2 = L1[:]

结果L1和L2一样的,只不过内存地址不同

  • 列表复制:

浅复制分析:列表的append方法以及copy模块的copy方法都是浅拷贝。即列表中的项内存地址都是相同的,如下代码。所以改变一个列表中的项,其它浅拷贝的列表里的项也会变。浅复制对于列表中存在可变的可迭代对象如列表,集合,字典这样的存在也是引用的原对象的地址空间,所以会一同改变

#浅拷贝的三种方式
import copy
names = ["小明", "小红", "小黑", "小黄", "小白"]

# 浅copy 1.
names1 = copy.copy(names)
# 2.
names2 = names[:]
# 3. 工厂函数
names3 = list(names)

深复制分析:python列表的深复制是直接新建一个内存空间将原列表的所有内容全部复制。不论哪一个发生改变都不会对另一个造成影响。

l=[1,2,3,4,5]
l2=copy.deepcopy(l)
print(id(l))
print(id(l2))
  • 字符串反转

利用切片的方法来反转字符串或列表,只需指定 step 为 -1,就可以反转其中的元素

s1 = "abcdef"[::-1]
print(s1)
#输出fedcba
  • 切片赋值 切片赋值是针对原序列进行操作,改变切片区域的序列。给序列的切片部分新的赋值必须是可迭代类型
A1 = [2,3,4,6]
A1[2:3] = ['a','b']
print(A1)
#输出[2, 3, 'a', 'b', 6]

判断一个对象是可迭代对象呢?方法是通过collections模块的Iterable类型判断

>>> from collections import Iterable
>>> isinstance('abc', Iterable) # str是否可迭代
True
>>> isinstance([1,2,3], Iterable) # list是否可迭代
True
>>> isinstance(123, Iterable) # 整数是否可迭代
False

最后一个小问题,如果要对list实现类似Java那样的下标循环怎么办?Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身:

>>> for i, value in enumerate(['A', 'B', 'C']):
...     print(i, value)
...
0 A
1 B
2 C

上面的for循环里,同时引用了两个变量,在Python里是很常见的,比如下面的代码:

>>> for x, y in [(1, 1), (2, 4), (3, 9)]:
...     print(x, y)
...
1 1
2 4
3 9

列表生成式:

写列表生成式时,把要生成的元素x * x放到前面,后面跟for循环,就可以把list创建出来

#for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方:

>>> [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']

生成器和迭代器

  • 如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator

  • 要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

  • 通过调用next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象,生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了

  • 在 Python 中,使用了yield的函数被称为生成器(generator),跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield的值, 并在下一次执行 next() 方法时从当前位置继续运行。调用一个生成器函数,返回的是一个迭代器对象。

 L=(x for x in range(10))
    print(L)
输出结果:
<generator object main.<locals>.<genexpr> at 0x00000248B4995B30>

函数:

  • 函数名也是变量,既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数
def add(x, y, f):    
    return f(x) + f(y)
print(add(-5, 6, abs))
  • map函数

map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回 Python 2.x 返回列表。 Python 3.x 返回迭代器。 把这个list所有数字转为字符串:list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]))

#对列表+1操作
info = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
a = map(lambda x:x+1,info)
print(a)
for i in a:
    print(i)
#对两个列表元素相加操作
 m=map(lambda x,y:x+y,[1,2,3,4],[1,2,3,4])
    for i in m:
        print(i)
  • @property装饰器就是负责把一个方法变成属性调用
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

@property的实现比较复杂,我们先考察如何使用。把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值,于是,我们就拥有一个可控的属性操作:

>>> s = Student()
>>> s.score = 60 # OK,实际转化为s.set_score(60)
>>> s.score # OK,实际转化为s.get_score()
60
>>> s.score = 9999
Traceback (most recent call last):
  ...
ValueError: score must between 0 ~ 100!
注意到这个神奇的@property,我们在对实例属性操作的时候,就知道该属性很可能不是直接暴露的,而是通过getter和setter方法来实现的。
还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性:

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
上面的birth是可读写属性,而age就是一个只读属性,因为age可以根据birth和当前时间计算出来。
  • lambda表达式 格式:lambda 参数:表达式,这个函数返回两个参数的和: lambda a, b: a+b
dic = {'a':2,'b':1}
1、按照key排序
d = sorted(dic ,key = lambda k:k[0])
2、按照values排序
e = sorted(dic , key = lambda k:k[1])

5、 手写排序


lst = [20,5,49,59,10,40]
def sort(list):
   newlist = []
   for x  in list:   # x=20;x=5
      print(newlist) #20
      for i,v in  enumerate(newlist,0): #i=0,v=0;i=0,v=20
         if x>v:
            newlist.insert(i,x) # newlist = [20];
            break
      else:
         newlist.append(x) #不大于就放到后面
   return newlist
print(sort(lst))

def sort(list,fn = lambda a,b:a>b):
   newlist = []
   for x  in list:   # x=20;x=5
      print(newlist) #20
      for i,v in  enumerate(newlist,0): #i=0,v=0;i=0,v=20
         # flag = x>v if asc  else x<v
         if fn(x,v):
            newlist.insert(i,x) # newlist = [20];
            break
      else:
         newlist.append(x) #不大于就放到后面
   return newlist
print(sort(lst))

  • 函数注解和变量注解

python3引入 对函数的参数进行类型注解 对函数的返回值进行类型注解 只对函数参数做一个辅助说明,并不对函数参数进行类型检查 函数注解的信息,保存在__annotations__属性中 python3.6引入变量注解,就是为变量(包括类中的变量与实例变量)添加类型注解


def add(x:int,y:int)->int:
    """
    :param x:int
    :param y:int
    :return:int
    """
    return x+y
print(help(add))
print(add(4,5))
print(add("jax","zhai"))

  • filter()函数 filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回一个迭代器对象,如果要转换为列表,可以使用 list() 来转换。 该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。
lst = [20,5,49,59,10,40]
fer = filter(lambda x:x%2==0,lst)
print(list(fer))
结果:
[20, 10, 40]
  • 冒泡排序----交换排序
def bubbleSort(arr):
   length = len(arr)
   count = 0
   flag = False
   print("列表长度:",length)
   for i in  range(length): # 循环7次,第一次循环索引i=0,
      for j in range(0,length-i-1):
         count +=1
         if arr[j] > arr[j+1]:
            print("swap 前:",arr[j],arr[j+1])
            arr[j],arr[j+1] = arr[j+1],arr[j]
            print("swap 后:",arr[j],arr[j+1])
            flag = True
      if not flag:
         break
   print("次数",count)
arr = [120, 133, 420, 150, 16, 19,29]
bubbleSort(arr)
print("排序后的数组:")
for i in range(len(arr)):
   print("%d" % arr[i]),
  • 插入排序 从第二个元素开始和前面的元素进行比较,如果前面的元素比当前元素大,则将前面元素 后移,当前元素依次往前,直到找到比它小或等于它的元素插入在其后面, 然后选择第三个元素,重复上述操作,进行插入,依次选择到最后一个元素,插入后即完成所有排序
def insertion_sort(arr):
    #插入排序
    # 第一层for表示循环插入的遍数
    for i in range(1, len(arr)):
        # 设置当前需要插入的元素
        current = arr[i]
        # 与当前元素比较的比较元素
        pre_index = i - 1
        while pre_index >= 0 and arr[pre_index] > current:
            # 当比较元素大于当前元素则把比较元素后移
            arr[pre_index + 1] = arr[pre_index]
            # 往前选择下一个比较元素
            pre_index -= 1
        # 当比较元素小于当前元素,则将当前元素插入在 其后面
        arr[pre_index + 1] = current
    return arr

更多精彩关注公众号“51运维com” 个人博客