python知识点

1. python基础

1.1 字符串

1.1.1格式化:

% 用来格式化字符串,在字符串内部,

  1. %s表示用字符串替换
  2. %d表示用整数替代
  3. %f表示浮点数
  4. %06d的,表示输出的整数显示位数,不足以0补充,超出当前位数则原样输出
  5. %.2f,表示小数点后显示的小数位数

format():它会用传入的参数依次替换字符串内的占位符{0},{1}

注:可迭代的对象

print ('%d %s cost me $%.2f.' %(2, 'books', 21.227))

"{} {}".format("hello", "world")    # 不设置指定位置,按默认顺序
'hello world'
 
"{0} {1}".format("hello", "world")  # 设置指定位置
'hello world'
 
"{1} {0} {1}".format("hello", "world")  # 设置指定位置
'world hello world' 

1.1.2 常用的操作

替换replace()、删除、截取、赋值、连接、比较、查找、分割split()等

  1. str.replace(旧子串,新子串,替换次数)
  2. capitalize():将字符串第一个字符转换为大写,其他字符全部转化为小写
  3. title():将字符串每个单词的首字母转换为大写
  4. lower():将字符串中的大写转小写
  5. upper():将字符串中小写转大写
  6. ljust(): 返回一个原字符串左对齐,并使用指定字符串(默认为空格)填充至对应长度的新字符串
  7. str.startswith(子串,开始位置下标,结束位置下标)
  8. isalpha() :如果字符串至少有一个字符并且所有字符都是字母则返回True
  9. isdigit():如果字符串只包含数字则返回True
  10. isalnum(): 如果字符串至少有一个字符并且所有字符都是字母或数字则返回True
# 1. 去除空格
str.strip()
# 2. 连接字符串  +
'love'+'lazy'

','.join(list)

# 3. 查找字符串 index 和find,区别find查找时变会返回-1,不影响程序执行
str.index('c',0,-1)
str.find('c')
# rfind 和find功能相同,但查找方向为右侧开始
# 4.比较字符串
str.cmp()
# 5. 是否包含指定字符串 in  not in
a='hello word'
print('hello' in a)

# 6. 字符串长度 len(str) 或 str.len
# 7. 大小写 str.lower() str.upper()
# 8. 将字符串放入中间位置,可指定长度以及两边的字符str.center()
s='hello world'
print(s.center(40,'*'))
# 9.字符串统计 str.count()
s='hello world'
print(s.count('o'))
# 10. 字符串切片
str[::]
# 11 分割函数,partition()分割三部分
s='alex sb alex'
print(s.partition('sb'))

# 12. 返回指定长度的字符串,原字符串右对齐
str.zfill(11)
mystr="hello"
mystr.ljust(10,'.')    # 'hello.....' 

# 结束符
print("输出的内容",end="\n") # print默认为换行符

1.2 list 和tuple

1.2.1 list常用操作:

生成、添加元素append,访问(enumerate()同时输出索引值和元素内容)、删除、排序、切片、乘等

  1. len(list),max(list)
  2. list(seq) 将元组转换为列表
  3. tuple(seq):将列表转换为元祖
  4. list.count(obj)

元组在只包含一个元素时,tuple=(2,) 加’,'消除歧义

#创建list
list=[i for i in range(10)]

# 列表去重
my_list=[3,2,1,1,2,3]
unique_list=list(set(my_list))

from collections import OrderedDict
unique_list=list(OrderedDict.fromkeys(my_list))  #去重的同是保留list中的顺序
print(unique_list)

1.2.2 list 当作参数时的注意点

def f(x,li=[]):
    print(id(li))
    for i in range(x):
        li.append(i*i)
    print(li)
# 定义函数时,会保存函数中默认参数list的值,也就是列表li=[],当两次调用时都采用默认参数时,就会在原来的基础上append追加值。
f(4)
f(5)

# 优化
def f(x,li=[]):
    if not li:      
        li=[]
    for i in range(x):
        li.append(x**2)
    print(li)

# list 函数的copy,python变量名相当于标签名,list2=list1,直接赋值,实质上指向的是同一个内存值。任何一个变量(list1 or list2)发生改变,都会影响另外一个。

list1=[1,2,3,4,5,6]
list2=list1
list3=list1[:]
print(id(list1))
print(id(list2))           # list2 是 list1的视图,指向同一个内存值
print(id(list3))          # list切片产生新的lis

"""
Python中赋值语句不复制对象,而是在目标和对象之间创建绑定关系。对于自身可变或者包含可变项的集合对象,开发者有时会需要生成其副本用于改变操作,进而避免改变原对象。copy 模块提供了通用的浅层复制 copy() 和深层复制 deepcopy() 操作。

1. copy() 仅复制对象本身,而不对其中的子对象进行复制,如果对原子对象进行修改,那么浅层复制之后的对象也会随着修改。
2. deepcopy() 是真正意义上的复制,即重新开辟一片空间,经常说的复制实际上就是 deepcopy,深层复制之后的对象不受原对象的影响,无论原对象发生什么修改,深层复制的对象都不会发生改变。
"""

import copy
list1 = [1, 2, [3, 4], 5]
list2 = copy.copy(list1)
list3 = copy.deepcopy(list1)
list2 == list3
list2 is list3

# array 数组切片,赋值,实际指向同一个内存值,任意修改其中的一个变量,其他变量值都会被修改
import numpy as np
array1=np.array([1,2,3,4])
array2=array1
array3=array1[:]

# 生成新的array
array5 = array1.copy() # 对原始的array1的复制

1.2.3 运算符

  1. “ * ” 复制 print(‘_’*10)
  2. “+ ” 合并
#添加元素
list.append() # 尾部添加
list.insert(index,object)      # 指定位置新增数据
#两个list的合并extend 、'+' ,列表结尾追加数据,如果数据是一个序列,则将这个序列的数据逐一添加到列表
list1.extend(list2)
list1+list2

#删除元素 remove和pop、 del


# 重复列表 *
l1=[1,2,3]
print(l1*3)


# 排序和反转

list.reverse() #列表元素反转
list.sort(cmp,key,reverse=False) #在原list上排序
list2=sorted(list)

# 元组
#元组中的元素不能被修改,但可以对元组进行连接组合,‘+’和'*'操作
tup1+tup2

1.3 dict 字典和 set集合

  1. items返回dict的(健,值)tuple的一个列表
  2. keys() 返回dict的健列表
  3. values()返回dict的值列表

创建集合使用{}set(),但是如果要创建空集合只能使用set(),因为{}用来创建空字典

1.3.1 常见集合操作

  1. add() 增加数据;
  2. update() 追加的数据是序列,例如,列表,集合,字符串(会依次添加每个字符)
  3. remove()删除集合中的指定数据,如果数据不存在则报错
  4. discard() 删除集合中指定数据,如果数据不存在也不会报错
  5. pop() 随机删除集合中的某个数据,并返回这个数据
  6. in/not in 查找数据
#set 并、交、差、异或,判断子集
a | b
a & b
a - b
a ^ b
a.issubset(b)

1.3.2 dict相关操作

# 1. 添加元素
dict[key]=value
dict.setdefault(key,value)

# 2. 删除指定健值对
dict1={'a':1,'b':2}
del dict1['a']
# 清空字典
dict1.clear()
# 删除字典对象
del dict1

# 3. 字典的方法
#get(key,default=None)
dict1.get('d1','no')

# has_key(key) 如果key出现dict中返回True
dict1.has_key('a')

# 4. 更新字典 update()
dict1 = {'a': 1, 2: 'b', '3': [1, 2, 3]}
dict2 = {4: 'new1', 5: 'news'}
dict1.update(dict2)
print (dict1)

# 5. 将两个list合并成一个字典
dict1={list1[i]:list2[i] for i in range(len(list1))}

# 6. 提取字典中的目标数据
count1={key:value for key,value in counts.items() if value >=200}

# 7. 按照value进行排序
d = {'a':1,'b':4,'c':2}
字典是这个,然后要对字典按照value进行排序
方法一:
sorted(d.items(),key = lambda x:x[1],reverse = True)
方法二:
import operator
sorted(d.items(),key = operator.itemgetter(1))

Python遍历嵌套字典列表,取出某些字段的值

def traverse_take_field(data, fields, currentKey=None):
    """遍历嵌套字典列表,取出某些字段的值
    :param data: 嵌套字典列表
    :param fields: 列表,某些字段
    :param values: 返回的值
    :param currentKey: 当前的键值
    :return: 列表
    """
    if isinstance(data, list):
        for i in data:
            traverse_take_field(i, fields, currentKey)
    elif isinstance(data, dict):
        for key, value in data.items():
            traverse_take_field(value, fields, key)
    else:
        values.append(data)
        # if currentKey in fields:
        #     values.append(data)

data = {"info": "2班成绩单",
        "grades": {
            "小明":
                [{"chinese": 60}, {"math": 80}, {"english": 100}],
            "小红":
                [{"chinese": 90}, {"math": 70}, {"english": 50}],
            "小蓝":
                [{"chinese": 80}, {"math": 80}, {"english": 80}],
        },
        "newGrades": {
            "info": "新增数据",
            "newChinese": 77
        }}
if __name__ == '__main__':
    values = []
    fields = ["chinese", "newChinese"]
    traverse_take_field(data, fields)
    print(values)

1.4 zip函数

将可迭代的对象作为参数,将对象中的元素打包成一个个元组,然后返回由这些元组组成的列表,如果各个迭代器中的元素个数不一致,则返回列表长度与最短的对象相同,利用* 号操作符,可以将元祖解压为列表zip(*zipped) 可以是list数组,也可以是zip函数返回的对象

a=[1,2,3]
b=[4,5,6]
c=[4,5,6,7,8]
zipped=zip(a,b)   #zip函数返回一个list对象,需要转换为list类型
iterator=zip(*zipped)
print(list(iterator))

1.5 集合的推导式

列表推导式、使用一句表达式构造一个新列表,可包括过滤、转换等操作。

#列表推导式方法
result2 = [i for i in range(10000) if i%2 == 0]

# 嵌套列表推导式:按照嵌套顺序理解
lists = [range(10), range(10, 20)]

evens = [item for lst in lists for item in lst if item % 2 == 0]
print(evens)

# 字典推导式
dict1 = {key : value for key, value in enumerate(reversed(range(10)))}
print (dict1)

# 集合推导式
set1 = {i for i in range(10)}

2. 函数

2.1 闭包

实现一个可变参数的求和,通常这样定义

def calc_sum(*args):
    ax=0
    for i in args:
        ax+=i
    return ax

如果不需要立即求和,而是在后面的代码中,根据需要在计算,可以不返回求和的结果,而是返回求和的函数

def lazy_sum(*args):
    def sum():
        ax=0
        for i in args:
            ax+=i
        return ax
    return sum
#当我们调用lazy_sum()时,返回的不是求和结果,而是求和的函数:
f = lazy_sum(1,2,3,5,7)
#调用函数f()时,才真正计算求和的结果
print(f())

"""
在这个函数lazy_sum()中又定义了sum,并且内部函数sum可以引用外部函数的参数和局部变量,当lazy_sum返回函数sum时,
相关变量和参数都保存在返回的函数中,这种称为‘闭包’closure

"""

另外需要注意的问题,返回的函数并没有立即执行,而是知道调用了f()才执行

注意:返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量

def count():
    fs=[]
    for i in range(1,4):
        def f():
            return i*i
        fs.append(f)
    return fs
f1,f2,f3=count()

"""
上面的例子中,每次循环,都创建了一个新的函数,然后,把创建的3个函数都返回,但是返回的函数都是9,原因在于
返回的函数引用了变量i,但它并没有立即执行,等到3个函数都返回时,他们所引用的变量已经变成了3,因此,最终结果为9

"""
f1()
#f2()
#f3()
#如果要引用循环变量,需要再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已经绑定到函数参数的值不变
def count():
    def f(j):
        def g():
            return j*j
        return g
    fs=[]
    for i in range(1,4):
        fs.append(f(i))
    return fs
    
f1,f2,f3=count()
f1()

2.2 匿名函数

当我们在传入函数时,有些时候,不需要显示的定义函数,直接传入匿名函数更方便,返回值就是该函数的表达式

函数调用传参时,如果有位置参数时,位置参数必须在关键字参数(键=值)的前面,但关键字参数之间不存在先后顺序

# lambda 参数列表:表达式

str_lst = ['Welcome', 'to', 'Python', 'Data', 'Analysis', 'Course']
str_lst.sort(key=lambda x:len(x)) # sort by length
print (str_lst)

str_lst.sort(key=lambda x:x[-1]) # sort by the last letter
print (str_lst)

注意:
1. lambda 表达式的参数可有可无,函数的参数在lambda表达式中完全适用
2. lambda 表达式能接收任何数量的参数但只能返回一个表达式的值

fn=lambda:100
fn1=lambda a,b,c=100:a+b+c
fn2=lambda *args :args

def sum_num(a,b,f):
    return f(a)+f(b)
result=sum_num(-1,2,abs)

2.3 函数参数

# 函数返回
def divide(a,b):
    try:
        return a*1.0/b
    except ZeroDivisionError as e:
        print(e)
        #raise e
print(divide(0,1))
print(divide(1,0))


# 正常使用函数默认参数
#不推荐使用
def gen_list(a=[],b=None):
    a.append(b)
    return a
print (gen_list(b=2))
print(gen_list(b=3))
#导致函数默认值改变,多次调用相互影响,这里只是针对传递引用类型的参数,如果是数字、字符串等类型就不存在该问题

# 推荐使用
def gen_list(a=None,b=None):
    if a is None:
        a=[]
    a.append(b)
    return a
print(gen_list(b=2))
print(gen_list(b=3))



# 全局变量:在函数内部修改全局变量的值,需要在函数内部加一条语句: global  变量

a=100
def func():
    global a
    a=200
func()
print(a)

# 不定长参数:不定长参数也叫可变参数,用于不确定调用的时候会传递多少个参数(不传递也可)的场景,此时,可用包裹(packing)位置参数或者包裹关键字进行参数传递

# 包裹位置传递 *args
def user_info(*args):
    print(args)
    
user_info('TOm',18)

#关键字传递 **kwargs

def user_info(**kwargs):
    print(kwargs)

user_info(name="TOM",age="18")


# 引用:在python中,值是靠引用传递来的,我们可以用id()来判断两个变量是否为同一个值的引用,我们可以将id值理解为那块内存的地址标识
# int类型为不可变类型
a=1
b=a
print(id(a))
print(id(b))
a=2
#print(id(b))
# 列表是可变类型
aa=[10,20]
bb=aa
print(bb)
aa.append([30,40])
print(bb)

# 递归, 特点:函数内部自己调用自己;必须有出口
def sum_numbers(num):
    # 1.出口
    if num ==1:
        return 1
    # 2.当前数字+当前数字-1的累加和
    return num+sum_numbers(num-1)

2.4多函数模

# 处理字符串
str_lst = ['$1.123', ' $1123.454', '$899.12312']

def remove_space(str):
    str_no_space = str.replace(' ', '')
    return str_no_space

def remove_dollar(str):
    """
        remove $
    """
    if '$' in str:
        return str.replace('$', '')
    else:
        return str

def clean_str_lst(str_lst, operations):
    """
        clean string list
    """
    result = []
    for item in str_lst:
        for op in operations:
            item = op(item)
        result.append(item)
    return result

clean_operations = [remove_space, remove_dollar]
result = clean_str_lst(str_lst, clean_operations)
print (result)

2.5 异常处理

"""
try:
    可能发生错误的代码
except (异常类型):
    如果出现异常执行的代码

"""
try:
    print(1/0)
except:
    print('error')

# 2. 捕获异常描述信息
try:
    print(1/0)
except ZeroDivisionErroe as result:       # except Exception as result:
    print(result)
    
# 3. 异常的else

try:
    print(1/0)
except Exception as result:      
    print(result)
else:
    print('我是else,是没有异常的时候执行的代码')

# 4. 异常的finally
try:
    f=open('text.txt','r')
except Exception as result:
    f=open('text.txt','w')
else:
    print('没有异常,我很开心')
finally:
    f.close()                    # 表示无论是否有异常都要执行的代码



# 自定义异常,在python中,抛出自定义异常的语法为raise异常对

# 自定义异常类,继承Exception
class ShortInputError(Exception):
    def __init__(self,length,min_len):
        self.length=length
        self.min_len=min_len
    #设置抛出异常的描述性息
    def __str__(self):
        return "输入的长度是%是,不能少于%s个字符串"%(self.length,self.min_len)
    
def main():
    try:
        con=input('请输入密码:')
        if len(con) <3:
            raise ShortInputError(len(con),3)
    except Exception as result:
        print(result)
    else:
        print("密码输入完成")

2.6 高阶函数map、filter、reduce

  • map():将函数依次作用到序列的每一个元素,map()在python3返回的是迭代器,不是list
  • reduce():把一个函数作用在一个序列上,reduce把结果继续和序列的下一个与元素做累积计算
  • filter():也接收一个函数和一个序列,和map()不同,filter把传入的函数依次作用在每个元素元素上,然后根据返回值是True还是False决定是保留还是丢弃该元素
# map 函数
a = [1,2,3];b = [2,3,4]
c = list(map(lambda x,y:x+y,a,b))

# filter 函数
l=[x for x in range(0,10)]
l=list(filter(lambda x : x%2==0,l))

# reduce函数
from functools import reduce
str_lst = map(str, range(5)) # ['0', '1', ...]

def make_num(str1, str2):
    return int(str1) * 10 + int(str2)

result = reduce(make_num, str_lst)

2.7 迭代器

  • 定义:可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
  • 可迭代对象 Iterable,以直接作用于for 循环的数据类型有一下几种:
  1. 集合数据类型:list,tuple,dict,set,str
  2. generator ,包含生成器和带yieldgenerator function

这些可以直接用于for循环的对象统称为可迭代对象:Iterable

2.8 生成器

生成器与列表生成式的本质区别就是:一个已经生成数据了,使用时,如果数据过大,会产生内存溢出,而生成器是只有循环时,才会生成数据

#1.把一个列表生成式的[]改成(),就创建了一个generator
g = (x * x for x in range(10))
    
# 使用了yield的函数就是生成器   
def fib(times): #打印斐波拉契数列钱times位。
    n=0
    a,b=0,1
    while n<times:
        yield b   #功能:每次执行到有yied的时候,会返回yield后面b的值给函数并且函数会暂停,直到下次调用或迭代终止。
        a,b=b,a+b    #再一次调用next方法时,程序从停止的地方开始执行
        n+=1
    return 'done'
for i in fib(10):
    print(i)

2.9 装饰器

"""
这里的deco函数就是装饰器,它的参数是一个函数,然后返回值也是一个函数。其中作为参数的这个函数f()就在返回函数wrapper的内部执行。
然后在函数f()前面加上@deco,f()函数就相当于被注入了计时功能,现在只要调用f(),它就已经变身为“新的功能更多的函数”

"""

import time
def deco(f):
    def wrapper(a,b):
        start_time=time.time()
        f(a,b)
        end_time=time.time()
        execution_time=(end_time-start_time)*1000
        print("time is %d ms"%execution_time)
    return wrapper
@deco
def f(a,b):
    print('be on')
    time.sleep(1)
    print('result is %d'%(a+b))
if __name__=='__main__':
    f(3,4)


# 2. 无固定参数的装饰器
def deco(f):
    def wrapper(*args, **kwargs):      #
        start_time = time.time()
        f(*args, **kwargs)
        end_time = time.time()
        execution_time= (end_time - start_time)*1000
        print("time is %d ms" % execution_time)
    return wrapper
@deco
def f(a,b):
    print("be on")
    time.sleep(1)
    print("result is %d" %(a+b))
@deco
def f2(a,b,c):
    print("be on")
    time.sleep(1)
    print("result is %d" %(a+b+c))


if __name__ == '__main__':
    f2(3,4,5)
    f(3,4)


# 3. 使用多个装饰器,装饰一个函数

def deco01(f):
    def wrapper(*args, **kwargs):
        print("this is deco01")
        start_time = time.time()
        f(*args, **kwargs)
        end_time = time.time()
        execution_time = (end_time - start_time)*1000
        print("time is %d ms" % execution_time)
        print("deco01 end here")
    return wrapper
def deco02(f):
    def wrapper(*args, **kwargs):
        print("this is deco02")
        f(*args, **kwargs)

        print("deco02 end here")
    return wrapper

@deco01
@deco02
def f(a,b):
    print("be on")
    time.sleep(1)
    print("result is %d" %(a+b))
if __name__ == '__main__':
    f(3,4)

3. 内建模块

3.1 datetime|time

日期和时间的库

# datetime模块下的datetime类
from datetime import datetime

3.2 hashlib

摘要算法又称哈希算法、散列算法,它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)

常用在:
任何允许用户登录的网站都会储存用户登录的用户名和口令,此时,便可以将口令用摘要算法替代

import hashlib
md5=hashlib.md5()
md5.update('how to use md5 in python hashlib?'.encode('utf-8'))
print(md5.hexdigest())

3.2 collections 模块

包含了一些特殊的容器,针对Python内置的容器,例如list、dict、set和tuple,提供了另一种选择;

  • namedtuple,可以创建包含名称的tuple

  • deque,类似于list的容器,可以快速的在队列头部和尾部添加、删除元素;

  • Counterdict的子类,计算可hash的对象;

  • OrderedDictdict的子类,可以记住元素的添加顺序;

  • defaultdictdict的子类,可以调用提供默认值的函数;

from collections import namedtuple,deque,Counter,defaultdict
# namedtuple是继承自tuple的子类。namedtuple创建一个和tuple类似的对象,而且对象拥有可访问的属性。
# 1. namedtuple 用来创建一个自定义的tuple对象,并且规定了tuple元素的个数,具备tuple的不变性,并可以用属性而不是索引来引用tuple的某个元素.


from collections import  namedtuple

User = namedtuple('User', ['name', 'age', 'gender'])
u = User('villa', 33, 'male')
print(u.name)
print(u.age)
print(u.gender)
print(u)

Point =namedtuple('Point',['x','y'])   # 第一个参数tuple_name, 第二个参数filter_name   返回值是类型,需要传参数
"""
这里其实是创建了一个类,但是class类有比较复杂,便可以通过nametuple来简化创建。第一个参数为类名,后面的list为类的属性

"""
p=Point(1,2)      # 指定之后,属性值不能更改
print(p)
print(isinstance(p,tuple))
print(isinstance(p,Point))

# 2. deque: 解决list线性插入和删除效率低的问题,deque是为了高效的实现插入和删除操作的双向列表,适合用于队列和栈

q=deque([1,2,3,4])
q.append(5)
q.appendleft(0)
q.pop()
q.popleft()


# 3. Counter: 简单的计数器,例如统计字符的出现次数
c=Counter
print(c('hello'))   # 可以是字符串,list


# 4. OrderedDict: 使用dict时,key是无序的,在对dict做迭代时,我们无法确定key的顺序,可以使用OrderdDict保持key的顺序
d=dict([('a',1),('aa',2),('c',3)])   #python中的字典是无序的,因为它是按照hash来存储的
d['d']=4
d['ff']=6
d['ef']=5
#先后顺序不保证
for key,value in d.items():
    print(key,value)

od=OrderedDict([('a',1),('b',2),('c',3)])   #OrderedDict 的key会按照插入的顺序排序,而不是key本身排序
print(od)

# 5. defaultdict: 使用dict时,如果引用的key不存在,就会抛出keyError,如果希望key不存在时,返回一个默认值,就可以使用defaultdict
d=defaultdict(lambda:'N/A')
d['key1']='abc'
print(d['key1'])
print(d['key2'])

cnt={}
for char in ["a",'b','c','b','d','a','a']:
    if char not in cnt:
        cnt[char]=0
    cnt[char]+=1
print(cnt)
# 方法二
cnt=defaultdict(int)    # 指定类型int函数,int的默认值为0
for char in ["a",'b','c','b','d','a','a']:
    cnt[char]+=1
print(cnt)

3.3 itertools

提供了非常有用的用于操作可迭代对象的函数
迭代器的特点是:惰性求值(Lazy evaluation),即只有当迭代至某个值时,它才会被计算,这个特点使得迭代器特别适合于遍历大文件或无限集合等,因为我们不用一次性将它们存储在内存中。

itertools 模块提供的迭代器函数有以下几种类型:

  • 无限迭代器:生成一个无限序列,比如自然数序列 1, 2, 3, 4, …;
  • 有限迭代器:接收一个或多个序列(sequence)作为参数,进行组合、分组和过滤等;
  • 组合生成器:序列的排列、组合,求序列的笛卡儿积等;
import itertools
# 1. itertools 模块提供了三个函数(事实上,它们是类)用于生成一个无限序列迭代器:count(firstval=0, step=1)、cycle(iterable)、repeat(object [,times]

nums =itertools.count(1) #自然序列

# cycle 用于对iterable中的元素反复执行循环

cycle_string=itertools.cycle('ABC')

# repeat 用于反复生成一个object
for item in itertools.repeat([1,2,3,4],3):
    print(item)

# 2. 合并器:chain() 与 izip(),chain()函数接收n个可迭代对象,然后返回一个他们的合集的迭代器,纵向合并;izip()函数接收n个可迭代对象,然后将其合并成tuples,横向合并,功能类似zip(),只是返回的是iterator,而不是list。

for i in itertools.chain([1,2,3],['a','b','c']): #chain() 可以把一组迭代对象串联起来,形成一个更大的迭代器
    print (i)
    

for i, j in itertools.izip([1,2,3],['a','b','c']):
    print (i)

# 3. 切分迭代器: islice(),函数接收一个迭代器,然后返回其切片,类似于list的slice切片操作。参数有start,stop和step,其中start和step参数时可选参数。


# 4. Map迭代器,imap()函数对迭代器进行转换,类似于python内置的map()函数。下例把range(5)乘以2。
print ("Multiples:")
for i in itertools.imap(lambda x,y:(x, y, x*y), range(5),range(5,10)):
    print ('%d * %d = %d' % i)

# groupby() 把迭代器中的相邻重复元素挑出来放一起
for key,group in itertools.groupby('AAAABBBCCAAA'):
    print(key,list(group))

3.4 OS 操作文件和目录

  1. os.mkdir 创建目录
  2. os.rmdir 删除目录
  3. os.rename 重命名
  4. os.walk 遍历目录
  5. os.path.join 连接目录和文件名
  6. os.path.split 分割文件和文件名
  7. os.path.exists() 判断路径是否存在
  8. os.getcwd() 方法用于返回当前工作目录
  9. os.path.dirname():去掉脚本的文件名,返回目录os.path.dirname(os.path.realname(__ file__)):获得所引用模块所在的绝对路径,__ file __ 为内置属性
  10. os.remove() 删除文件
  11. os.path.isdir()
  12. os.path.isfile()
  13. os.system():system函数可以将字符串转化成命令在服务器上运行
  14. os.listdir() 获取目录列表
# 常用实例

import os
# 全局变量
cur_dir =os.getcwd()
new_dir=os.path.join(cur_dir,'tmp')
#判断new_dir是否存在,如何存在删除之后再创建,不存在,直接创建
if not os.path.exists(new_dir):
    os.mkdir(new_dir)      # 删除一个目录 os.rmdir(filepath)
else:
    os.rmdir(new_dir)
    os.mkdir(new_dir)
# 创建tmp.log 文件并写入内容

new_file=os.path.join(new_dir,'tmp.log')
with open(new_file,'w') as f:
    f.write('test')
  
# 查找d:\dir_temp目录下的所有文件,以绝对路径输出文件
search_dir = 'd:\\dir_temp'
for root, dirs, files in os.walk(search_dir):
    for name in files:
        print (os.path.join(root, name))

# 操作文件和目录一部分在os模块中,一部分在os.path中
os.path.abspath('.') # 查看当前目录的绝对路径

path=os.path.join('path','newdir') # 在一个目录下创建一个新目录,首先把新目录的完整路径表示出来

os.path.split('/Users/desktop/testdir/file.txt') # 把一个路径拆分两部分,后一部分总是最后级别的目录或文件名
# /Users/desktop/testdir   + file.txt

os.path.splitext() # 可以直接得到文件的扩展名
# /Users/desktop/testdir/file     txt     返回的list 

[x for x in os.listdir('.') if os.path.isdir(x)] # 列出当前目录下的所有目录

[ x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py']  # 列出所有的.py 文件

3.5 re 正则表达式

  1. re.match() 方法
  2. re.search() 方法 re.search扫描整个字符串并返回第一个成功的匹
  3. re.sub() 方法 用于替换字符串中的匹配
  4. re.compile() 方法
  5. re.finditer 作为迭代器返回
# re.match 函数 尝试从字符串的起始位置匹配一个模块,如果不是起始位置匹配成功的话,match() 就会返回None,re.match(pattern,string,flags=0),flags: 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等
# 使用group(num)获取匹配的表达式

import re

line="Cats are smarter than dogs"

matchObj=re.match( r'(.*) are (.*?) .*',line ,re.M|re.I)

if matchObj:
	print("matchObj.group():" ,matchObj.group())
	print("matchObj.group(1):" ,matchObj.group(1))
	print("matchObj.group(2):" ,matchObj.group(2))

# re.sub 
phone="2004-959-559  # 这是一个国外电话号码"

#删除注释

num=re.sub(r"#.*","",phone)
print("电话号码是:",num)

#删除非数字的字符串

num=re.sub(r'\D',"",phone)

print("电话号码是:",num)


# compile 函数用于编译正则表达式,生成一个正则表达式pattern,供match和search这两个函数使用,re.compile(pattern,flags),pattern:一个字符串形式的正则表达式,flags : 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
"""
    1. re.I 忽略大小写
    2. re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
    3. re.M 多行模式
    4. re.S 即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
    5. re.S 即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
"""
 
pattern =re.compile(r'\d+')

m=pattern.match('one12twothree34four',2,10) # 从'e'的位置开始匹配,没有匹配

# re.finditer 作为迭代器返回,在字符串中找到正则表达是所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表
result= pattern.findall("runoob 123 google 456",0,10)
print(result)

3.6 sys模块

  1. sys.argv : 用来获取当前正在执行的命令行参数列表 sys.argv[0]: 是程序名,sys.argv[1] 是第一个参数,以此类推
  2. sys.exit(n)
  3. sys.path
  4. sys.stdin\stdout\stder
# 1. sys.argv,实现从程序外部向程序传递参数。
import sys

# 获取脚本名称
print('the name of this program is : %s ' % sys.argv[0])
# 获取参数列表
print('the command line argument are:')
for i in sys.argv:
    print(i)
# 统计参数的个数
print(' there are %s arguments.'%(len(sys.argv)-1))

for index, arg in enumerate(sys.argv):
    print("第%d个参数是: %s" % (index, arg))

# 2. sys.exit([arg]),程序中间的退出,arg=0为正常退出。

# 3. sys.path: 获取指定模块搜索路径的字符串集合,可以将写好的模块放在得到的某个路径下,就可以在程序中import时正确找到,当我们导入一个模块时:import  xxx,
# 默认情况下python解析器会搜索当前目录、已安装的内置模块和第三方模块,搜索路径存放在sys模块的path中
#对于模块和自己写的脚本不在同一个目录下,在脚本开头加sys.path.append('xxx')
sys.path.append('引用模块的地址')  
#不同目录下在a.py中导入b.py
sys.path.append('b模块的绝对路径')

import b

# 4. sys.stdin
#单行输入
line=sys.stdin.readline().strip()   #获取输入的话,不要忘了去掉末尾的换行符,可以用strip( )函数

# 直接使用文件作为整体的输入
#for line in sys.stdin.readlines(): # 等效于 for line in sys.stdin:

# 使用方法,将文件重定向到输入中去就可以很方便的使      python test.py  < 123.txt

# 5. sys.stdout
sys.stderr.write() #等效于 print() sys.stdout.write()和sys.stderr.write()均是向屏幕打印的语句


import  time 
import sys

for  i in  range(5):
    print(i)
    sys.stdout.flush()
    time.sleep(1)

# 这个脚本的本意是每个一秒输出一个数字,但如果把这句话sys.stdout.flush() 去除的话。就只能等到程序执行完毕,屏幕上才会一次性输出 0,1,2,3,4,


# 6. flush() 方法是用来刷新缓冲区的,即将缓冲区中的数据立刻写入文件,同时清空缓冲区,不需要是被动的等待输出缓冲区写入。一般情况下,文件关闭后会自动刷新缓冲区,但有时你需要在关闭前刷新它,这时就可以使用 flush() 方法。
f.flush()

3.7 joblib

Joblib是一个可以将Python代码转换为并行计算模式的包,可以大大简化我们写并行计算代码的步骤。我们可以通过操作该包内的函数来实现目标代码的并行计算,从而提高代码运行效率

# 1. 首先,定义一个简单的函
from joblib import Parallel ,delayed
import time
def single(a):
    time.sleep(1)
    print(a)
    return a 

# 2. 使用for 循环运行10次,并记录时
start=time.time()
for i in range(10):
    single(i)
Time=time.time()-start
print(str(Time)+'s')

# 3. 使用joblib库里面的Parallel函数及delayed函数来执行10次循环函数的操作,实现并行化处理。Parallel函数会创建一个进程池,以便在多进程中执行每一列表项。

start = time.time()  # 记录开始的时间
res=Parallel(n_jobs=3,verbose=1)(delayed(single)(i) for i in range(10))   # 并行化处理,    notebook 上函数中的print不打印
# n_jobs: int, default: None —— 设置并行执行任务的最大数量。
print(res)
Time = time.time() - start  # 计算执行的时间
print(str(Time)+'s')

3.8 堆(heap)

是一个可以被看成近似完全二叉树的数组。树上的每一个结点对应数组的一个元素。除了最底层外,该树是完全充满的,而且是从左到右填充。又被称为优先队列(priority queue),但不是队列,在堆中,是按照元素的优先级取出元素的。

完全二叉树(complete binary tree)树的深度是log2

默认为顶堆,对每一个元素取负,可以构造大顶堆

left_son_id=father_id * 2

right_son_id=father_id * 2+1

father_id =son_id / 2

import heapq
# 1.heapq.heappush(heap,item)   heap为定义堆,item 增加的元素;并且item可以为元组类型,Python按元素对元组进行排序,确保要排序元组的对象排在第一位
heap=[]
heapq.heappush(heap, 2)

# 2.heapq.heapify(list)        将列表转换为堆
list=[5,8,0,3,6,7,9,1,4,2]
heapq.heapify(list) 
heapq.heappop(list)
list

# 3.heapq.heappop(heap)        删除最小的值
heap=[2, 4, 3, 5, 7, 8, 9, 6]   # 默认为堆
heapq.heappop(heap) 

# 4.heapq.heapreplace(heap, item)     删除最小元素值,添加新的元素值
heap=[2, 4, 3, 5, 7, 8, 9, 6]
heapq.heapreplace(heap, 11)

# 5.heapq.heappushpop(heap, item)     首判断添加元素值与堆的第一个元素值对比,如果大于则删除最小元素,然后添加新的元素值,否则不更改堆
heap=[2, 4, 3, 5, 7, 8, 9, 6]
heapq.heappushpop(heap, 9)

# 6.heapq.merge(...)             将多个堆合

# 7.heapq.nlargest (n, heap)     查询堆中的最大元素,n表示查询元素个数
heap=[2, 3, 5, 6, 4, 8, 7, 9]
heapq.nlargest (1, heap)

# 8.heapq.nsmallest(n, heap)     #查询堆中的最小元素,n表示查询元素个数
heap=[2, 3, 5, 6, 4, 8, 7, 9]
heapq.nsmallest(2, heap)

3.9 argparse

argparse 是python内置的一个用于命令项生成选项与参数解析的模块,通过在程序中定义我们需要的参数,argparse将会从sys.argv中解析这些参数,并自动的生成帮助和使用信息
三个步骤:

  • 创建ArgumentParser()对象

  • 调用add_argument()方法添加参数

  • 使用parse_args()解析添加的参数

import argparse
parser=argparse.ArgumentParser()
parser.add_argument("dilename",default='text.txt')
parser.add_argument('integer',type=int,help='display an integer')
args=parser.parse_args()
print(args.integer)

# 基本框架
import argparse

def get_parser():
    parser=argparse.ArgumentParser(description="Demo of argparse")
    parser.add_argument('--name',default="word")    #default 表示命令行没有设置该参数的时候,程序中用什么值来替代
    
    return parser
if __name__=="__main__":
    parser=get_parser()
    args=parser.parse_args()
    name=args.name
    print("Hello {}" .format(name))

# 可选参数,"-"或"--" 开头定义的命令行参数,都属于可选参数,单个字母用- ,多个字母用 --   位置参数 :必须配置的参数

parser = argparse.ArgumentParser()

parser.add_argument("--square", help="display a square of a given number", type=int)
parser.add_argument("--cubic", help="display a cubic of a given number", type=int)
parser.add_argument("--arch",required=True,choices=['alexnet','vgg'])    # required:表示这个参数是否一定需要设置
# choices :参数值只能从集合选项里面选择
args = parser.parse_args()

if args.square:
    print(args.square**2)

if args.cubic:
    print(args.cubic**3)

# 混合参数, 定位参数和选项参数可以混合使用,看下面一个例子,给一个整数序列,输出它们的和或最大值(默认):

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
                   help='an integer for the accumulator')     #  nargs是用来说明传入的参数个数,'+' 表示传入至少一个参数
parser.add_argument('--sum', dest='accumulate', action='store_const',
                   const=sum, default=max,
                   help='sum the integers (default: find the max)')

args = parser.parse_args()
print(args.accumulate(args.integers))

3.10 IO文本读写

# 1. 读文件
filepath='./lucy.txt'
with open(filepath,'r') as f:      #open函数打开文件   r:读
    print(f.read())      # ready一次性读取文件内容,把内容存放到内存中
    f.readline() # 每次读取一行内容
    f.readlines()  #一次读取全部内容并按行返回list 
# r: 表示文本文件
# rb:读取二进制文件,比如图像、视频

# 实际开发中通常使用
with open(filepath,'r') as f:
    for line in f:
        lst=line.strip().split()

# 2. seek() 作用:用来移动文件指针 , 文件对象.seek(偏移量,起始位置)
# 3. 写文件,同读文件,w:写入文本文件,wb:写入二进制文件
with open(filepath,'w' ) as f:
    f.write('hello python')

3.11 pickle & json 字符串序列化

我们把变量从内存中变成可储存或传输的过程称为序列化

json:是文本序列化格式

pickle:是二进制序列化格式(特定于python)

# 序列化 pickle 模块
#首先,把一个对象序列化并写入文件
import pickle,json
d=dict(name='bob',age=20,score=90)
pickle.dumps(d)

'''
pickle.dumps() 方法把任意对象序列化成一个bytes,然后就可以把这个btypes 写入文件,或者用另一个方法pick.dump(d,f)直接序列化并写入

'''

# 使用pickle.load()直接反序列化出对象,完成从磁盘到内存
with open(filepath,'rb') as f:
    d=pickle.dump(f)
    print(d)

# JSON 如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准化格式,json格式就是一个字符串,可以被所有的语言读取

# 把python对象变成一个json
d=dict(name='bob',age=20,score=90)
json.dumps(d)  # dumps()返回一个标准的dtr,内容是标准的json,可以使用dump直接写入文件
fw.write(json.dumps(result)+"\n")    # 将json格式的字符串写入文件

json.load() # json 反序列为 python 对象
line=json.loads(t_json)  # 将对应的json字符串load下来,转化为正常格式

data={"status": "OK", "count": 2, "results": [{"age": 27, "name": "Oz", "lactose_intolerant": 'true'}, {"age": 29, "name": "Joe", "lactose_intolerant": 'false'}]}
print(json.dumps(data,indent=2))


# json 进阶,对python 中的类进行序列

class Student():
    def __init__(self,name,age,score):
        self.name=name
        self.age=age
        self.score=score
s=Student('Bob',20,90)
# json 无法直接对s实例对象进行json序列化,可选参数default可以把任何一个对象序列化为json对象,
#需要为Student专门写一个转换函数,再把函数传进去
def student2dict(std):
    return {
        'name':std.name,
        'age':std.age,
        'score':std.score
    }

print(json.dumps(s,default=student2dict))

#也可以直接把任何class 的实例变为dict
json.dumps(s,default=lambda obj: obj.__dict__)


#同样json 先转化为dict,再到类实例
def dict2student(d):
    return Student(d['name'],d['age'],d['score'])
json.loads(json_str,object_hook=dict2student)

3.12 operator

operator 中三个类

  1. attrgetter:可以获取对象的属性,然后进行排序
  2. itemgetter
  3. methocaller
sorted(students,key=attrgetter('age'),reverse=True) #按照年龄进行排序
sorted(students,key=itemgetter(1),reverse=True) #按照年龄进行排序

3.13 networkx 创建图

3. 13.1 创建一个图

import networkx as nx
G=nx.Graph()
# 添加节点
G.add_node(1) # 一次添加一个节点
G.add_nodes_from([2,3]) # 添加一个节点列表

# 边
G.add_edge(1,2) # 可以通过一次添加一条边来增长
e=(2,3)
G.add_edge(*e)    # update edge tuple*
G.add_edges_from([(1,2),(1,3)]) #也可以通过添加边列表
# 删除图中所有节点和边
G.clear()

添加新的节点和边,并且Networkx会自动的忽略任何已经存在的节点

G.add_edges_from([(1,2),(1,3)])
G.add_node(1)
G.add_edge(1,2)
print(G.number_of_nodes())
G.add_node("spam")
G.add_nodes_from("spam")
G.add_edge(3,"m")
print(G.number_of_nodes())

3.13.2 图结构的四个属性

  1. G.nodes 节点
  2. G.edges
  3. G.adj or G.neighbors() 邻接点
  4. G.degree 图中节点的成程度集
# 查看是否有点1
G.has_node(1)
# 查看是否有边(1,2)
G.has_edge(1,2)

print(list(G.nodes))
print(list(G.edges))
print(list(G.adj[1]))
print(G.degree[1])

删除边和节点的函数:

  1. Graph.remove_node()
  2. Graph.remove_nodes_from()
  3. Graph.remove_edge()
  4. Graph.remove_edges_from()

3.13.3 有向图: DiGraph()

dg = nx.DiGraph()
nodes1 = [
    ('Variable', {'name': 'avariable', 'table': 'tablename'}),
    ('Select', {'conditions': {'pro_code': 44}}),
    ('GroupBy', {'varname': 'gender'}),
    ('Mean', {}),
    ('Which1', {'level': 1}),
    ('Decimal1', {'place': 1})
]

nodes2 = [
    ('Which1', {'level': 2}),
    ('Decimal2', {'place': 1})
]

nodes3 = [
    ('Add', {})
]

dg.add_nodes_from(nodes1)
dg.add_nodes_from(nodes2)
dg.add_nodes_from(nodes3)
dg.add_edges_from([
    ('Variable', 'Select'),
    ('Select', 'GroupBy'),
    ('GroupBy', 'Mean'),
    ('Mean', 'Which1'),
    ('Mean', 'Which2'),
    ('Which1', 'Decimal1'),
    ('Which2', 'Decimal2'),
    ('Decimal1', 'Add'),
    ('Decimal2', 'Add'),
])

nx.draw(dg, with_labels=True)

在这里插入图片描述

3.13.4 属性

属性(如:权重,便签,颜色或者喜欢的python对象)可以附加到图形,节点或边上。每个图形,节点和边都可以在关联的属性字典中保存键/值属性对(键必须是可散列的)。默认情况下,这些都是空的,但是属性可以使用添加或更改add_edge,add_node或者命名的属性字典的直接操作
图形属性

G=nx.Graph(day="Friday")
print(G.graph)
# 修改属性
G.graph['day']="MOnday"
print(G.graph)

节点属性

添加节点属性使用add_node(),add_nodes_from()G.nodes

G.add_node(1,time="5pm")
G.add_nodes_from([3],time="2pm")
print(G.nodes[1])
G.nodes[1]["room"]=714
print(G.nodes.data())

边属性
添加/更改边属性add_edge(),add_edges_from()或标符号

G=nx.DiGraph()
G.add_edge(1,2,weight=4.7)
G.add_edges_from([(3,4),(4,5)],color="red")
G.add_edges_from([(1,2,{'color':'blue'}),(2,3,{"weight":8})])
G.edges[3,4]["weight"]=4.2
nx.draw(G,with_labels=True)

3.13.5 从txt文件中读入有向图的函数

nx.read_edgelist(path,comments="#",delimiter=None,create_using=None,data=True,edgetype=None,encoding='utf-8')
# create_using为创建图的类型:有向图,无向图

当要读取的文件中的数据并不是按节点一的名称,节点二的名称,权重这样的三列顺序排列的时候,而是中间还有一些其他的列,比如节点属性等。但只希望读入指定列的数据时,先将指定列读入为DataFrame结构的数据,再将其通过nx.from_pandas_edgelist读入为图

df = pd.read_csv(network_path,delimiter='\t',usecols=[0,3])
dg = nx.from_pandas_edgelist(df,'node1','node2')

# 或者
df = pd.read_csv(network_path,delimiter='\t',names=['node1','node2'])
dg = nx.from_pandas_edgelist(df,'node1','node2')
textline = '1 2 3'
fh = open('test.edgelist','w')
d = fh.write(textline)
fh.close()
G = nx.read_edgelist('test.edgelist', nodetype=int, data=(('weight',float),))
G.nodes()
#[1, 2]
G.edges(data = True)
# [(1, 2, {'weight': 3.0})]

3.14 Queue 队列

python 的Queue模块中提供了FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。
Queue 模块中的常用方法:

  • Queue.qsize () 返回队列的大小
  • Queue.empty () 如果队列为空,返回 True, 反之 False
  • Queue.full () 如果队列满了,返回 True, 反之 False
  • Queue.full 与 maxsize 大小对应
  • Queue.get () 调用队列对象的get()方法从队头删除并返回一个项目。
  • Queue.get_nowait () 相当 Queue.get (False)
  • Queue.put (item) 调用队列对象的put()方法在队尾插入一个项目
  • Queue.put_nowait (item) 相当 Queue.put (item, False)
  • Queue.task_done () 在完成一项工作之后,Queue.task_done ()
    函数向任务已经完成的队列发送一个信号
  • Queue.join () 实际上意味着等到队列为空,再执行别的操作

4. 面向对象编程

由于类起到模版的作用,可以在创建实例的时候,把一些我们认为必须绑定的属性写进去,通过定义一个特殊的__init__方法,在创建实例的时候,就把属性绑定上去。

4.1 方法__new__() 和__init__()

self:表示实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self

class Student():
    def __init__(self,name,score):
        self.name=name
        self.score=score
    def print_score(self):
        print('%S:%s'%(self.name,self.score))

Python中存在于类中的构造方法__init__()负责将类实例化,而在__init__()执行之前,

__new__()负责制造这样的一个实例对象,以便__init__()去让该实例对象更加的丰富(为其添加属性等)。

4.2 方法__str__()

#当使用print输出对象的时候,默认打印对象的内存地址。如果类定义了__str__方法,那么就会打印这个方法中return的数据
class Wasker():
    def __init__(self,width,height):
        self.width=width
        self.height=height
    def __str__(self):
        return "这是洗衣机的说明书"

4.3 访问权限

__开头的实例变量,在python中变成了一个私有变量private

self.__name=name #实例仍然需要传参数,只是只能在内部使用

#但如果外部想要获取私有属性 ,可以给类增加get_name和get_score这样的方法
class Student(object):
    def __init__(self,name,score):
        self.__name=name
        self.__score=score
    def get_name(self):
        return self.__name
    def get_score(self):
        return self.score
    #如果又要允许外部代码修改socre,可以通过添加set_score方法:
    def set_score(self,score):
        self.__score=score

#目的:对参数做检查,防止传入无效的参数
class Student():
    def __init__(self,name,score):
        self.__name=name
        self.__score=score
    def set_score(self,score):
        if 0<=score<=100:
            self.__score=score
        else:
            raise ValueError('bad score')

4.4 继承和多态

#当子类和父类具有相同的方法是,子类的方法会覆盖父类的方法,这也就是获得了继承的另一个好处:多态

class People():

    def __init__(self,name,age,weight):
        self.name=name
        self.age=age
        self.__weight=weight

    def speak(self):
        print('{} 说:我今年{}岁了,体重是{:.2f}kg'.format(self.name,self.age,self.__weight))

class Student(People):
    def __init__(self,name,age,weight,grade):
        People.__init__(self,name,age,weight)
        self.grade=grade

    #重写父类方法

    def speak(self):

        print('{}说:我今年{}岁了,我在上海读{}年级。'.format(self.name,self.age,self.grade))

class Spearker():

    def __init__(self,name,topic):
        self.name=name
        self.topic=topic
    def speak(self):
        print("我叫 %s,我是一名演说家,我今天演讲的主题是%s" %(self.name,self.topic))


#多重继承
class Sample(Spearker,Student):
    def __init__(self,name,age,weight,grade,topic):
        Student.__init__(self,name,age,weight,grade)
        Spearker.__init__(self,name,topic)



test=Sample('tim',10,40.123,6,'python')
test.speak()  #方法名同,默认调用的是在括号中排前地父类的方法

4.5 方法重写

class Parent:  # 定义父类
    def myMethod(self):
        print('调用父类方法')


class Child(Parent):  # 定义子类
    def myMethod(self):
        print('调用子类方法')


c = Child()  # 子类实例
c.myMethod()  # 子类调用重写方法
super(Child, c).myMethod()  # 用子类对象调用父类已被覆盖的方法

4.6 静态方法

静态方法的特点,需要使用装饰器@staticmethod来进行修饰,静态方法既不需要传递类对象也不需要传递实例对象(形参没有self/cls)。

4.7 打印类的相关信息

class Point():
    def __init__(self,x,y):
        self.x=x
        self.y=y
    def __repr__(self):             
        return "Point({self.x},{self.y})".format(self=self)
p=Point(3,5)
print(p)
# 打印类的信息,也可以不用写repr方法,直接使用p.__dict__()

5. 多进程、多线程

5.1 多线程

"""
如何保持各线程之间的通信,在这里,我们使用队列Queue作为多线程之间通信的桥梁。
使用十个线程来执行run方法消化任务队列,run方法有两个参数,一个任务队列,一个保存结果的队列。
in_q.empty(),是对列的一个方法,它是检测队列是否为空,是一个布尔值,url = in_q.get(),这个操作是拿出队列的一个值出来,然后,把它从队列里删掉。

"""
# 一个关于queue.task_done()与queue.join()的实验
from threading import Thread
import time
import random
from queue import Queue
from collections import deque

# 创建队列,设置队列最大数限制为3个
queue = Queue(3)


# 生产者线程
class Pro_Thread(Thread):
    def run(self):
        # 原材料准备,等待被生产
        tasks = deque([1, 2, 3, 4, 5, 6, 7, 8])
        global queue
        while True:
            try:
                # 从原材料左边开始生产
                task = tasks.popleft()
                queue.put(task)
                print("生产", task, "现在队列数:", queue.qsize())

                # 休眠随机时间
                time.sleep(random.random())
            # 如果原材料被生产完,生产线程跳出循环
            except IndexError:
                print("原材料已被生产完毕")
                break


# 消费者线程
class Con_Thread(Thread):
    def run(self):
        global queue
        while True:
            if queue.not_empty:
                # 通过get(),这里已经将队列减去了1
                task = queue.get()
                time.sleep(2)
                # 这里可能队列数已经空了,但是消费者手里还有正在消费的队列
                # 发出完成的信号,不发的话,join会永远阻塞,程序不会停止
                queue.task_done()
                print("消费", task)
            else:
                break


# r入口方法,主线程
def main():
    Pro_1 = Pro_Thread()
    # 把生产线程列为守护线程,否则主线程结束之后不会销毁该线程,程序不会停止,影响实验结果
    Pro_1.setDaemon(True)
    # 启动线程
    Pro_1.start()

    for i in range(2):
        Con_i = Con_Thread()
        # 把两个消费者线程列为守护线程,否则主线程结束之后不会销毁该线程,程序不会停止,影响实验结果
        Con_i.setDaemon(True)
        # 启动线程
        Con_i.start()
    global queue
    # 这里休眠一秒钟,等到队列有值,否则队列创建时是空的,主线程直接就结束了,实验失败,造成误导
    time.sleep(1)
    # 接收信号,主线程在这里等待队列被处理完毕后再做下一步
    queue.join()
    # 给个标示,表示主线程已经结束
    print("主线程结束")


if __name__ == '__main__':
    main()

5.2 多进程

"""
如何保持各线程之间的通信,在这里,我们使用队列Queue作为多线程之间通信的桥梁。
使用十个线程来执行run方法消化任务队列,run方法有两个参数,一个任务队列,一个保存结果的队列。
in_q.empty(),是对列的一个方法,它是检测队列是否为空,是一个布尔值,url = in_q.get(),这个操作是拿出队列的一个值出来,然后,把它从队列里删掉。

"""
# 一个关于queue.task_done()与queue.join()的实验
from threading import Thread
import time
import random
from queue import Queue
from collections import deque

# 创建队列,设置队列最大数限制为3个
queue = Queue(3)


# 生产者线程
class Pro_Thread(Thread):
    def run(self):
        # 原材料准备,等待被生产
        tasks = deque([1, 2, 3, 4, 5, 6, 7, 8])
        global queue
        while True:
            try:
                # 从原材料左边开始生产
                task = tasks.popleft()
                queue.put(task)
                print("生产", task, "现在队列数:", queue.qsize())

                # 休眠随机时间
                time.sleep(random.random())
            # 如果原材料被生产完,生产线程跳出循环
            except IndexError:
                print("原材料已被生产完毕")
                break


# 消费者线程
class Con_Thread(Thread):
    def run(self):
        global queue
        while True:
            if queue.not_empty:
                # 通过get(),这里已经将队列减去了1
                task = queue.get()
                time.sleep(2)
                # 这里可能队列数已经空了,但是消费者手里还有正在消费的队列
                # 发出完成的信号,不发的话,join会永远阻塞,程序不会停止
                queue.task_done()
                print("消费", task)
            else:
                break


# r入口方法,主线程
def main():
    Pro_1 = Pro_Thread()
    # 把生产线程列为守护线程,否则主线程结束之后不会销毁该线程,程序不会停止,影响实验结果
    Pro_1.setDaemon(True)
    # 启动线程
    Pro_1.start()

    for i in range(2):
        Con_i = Con_Thread()
        # 把两个消费者线程列为守护线程,否则主线程结束之后不会销毁该线程,程序不会停止,影响实验结果
        Con_i.setDaemon(True)
        # 启动线程
        Con_i.start()
    global queue
    # 这里休眠一秒钟,等到队列有值,否则队列创建时是空的,主线程直接就结束了,实验失败,造成误导
    time.sleep(1)
    # 接收信号,主线程在这里等待队列被处理完毕后再做下一步
    queue.join()
    # 给个标示,表示主线程已经结束
    print("主线程结束")


if __name__ == '__main__':
    main()

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值