python3基础

元组排序

c=[(9,'a'),(8,'b'),(7,'c'),(6,'d')]
#  [i for _,i in sorted(zip(B,A))]
d=[i for _,i in sorted(c)]  #根据第一个元素从小到大排序第二个元素
e=[i for i,_ in sorted(c)]  #根据第二个元素从小到大排序第一个元素
print(d)   #['d', 'c', 'b', 'a']
print(e)   #[6, 7, 8, 9]
f=[i for _,i in sorted(c,reverse=True)]
print(f) #['a', 'b', 'c', 'd']

zip() 将两个集合构造成为元组

a=[1,2,3,4,5,6]
b=['o','i','u','y','t','r']
c=list(zip(a,b))
print(c) #[(1, 'o'), (2, 'i'), (3, 'u'), (4, 'y'), (5, 't'), (6, 'r')]
a=[1,2,3,4,5,6]
b=['o','i','u','y','r']
c=list(zip(a,b))
print(c) #[(1, 'o'), (2, 'i'), (3, 'u'), (4, 'y'), (5, 'r')]
a=[1,2,3]
b=['o','i','u','y','r']
c=list(zip(a,b))
print(c) #[(1, 'o'), (2, 'i'), (3, 'u')]

迭代器 iter()

a=[1,2,3,4,5,6,7,8]
it=iter(a)
print(it)       #<list_iterator object at 0x0000019E994B7BB0>
print(next(it)) # 1
print(next(it)) # 2
a=[1,2,3,4,5,6,7,8]
it=iter(a)
for i in it:
    print(i,end=' ') 
# 1 2 3 4 5 6 7 8 
import sys  # 引入 sys 模块

list = [1, 2, 3, 4]
it = iter(list)  # 创建迭代器对象

while True:
    try:
        print(next(it))
    except StopIteration:  #通过 StopIteration 异常标识迭代的完成 raise StopIteration 也可手动触发
        sys.exit()
'''
1
2
3
4
'''

生成器 generator

使用了 yield 的函数被称为生成器
生成器是一个返回迭代器的函数
在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
import sys
 
def fibonacci(n): # 生成器函数 - 斐波那契
    a, b, counter = 0, 1, 0
    while True:
        if (counter > n): 
            return
        yield a
        a, b = b, a + b
        counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
 
while True:
    try:
        print (next(f), end=" ")
    except StopIteration:
        sys.exit()
# 0 1 1 2 3 5 8 13 21 34 55

类迭代器

把一个类作为一个迭代器使用需要在类中实现两个方法 __iter____next__()
Python 的构造函数为 __init__(), 它会在对象初始化的时候执行。
__iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了__next__()方法并通过 StopIteration 异常标识迭代的完成。
__next__() 方法会返回下一个迭代器对象

创建一个返回数字的迭代器,初始值为 1,逐步递增 1:
class MyNumbers:
  def __iter__(self):
    self.a = 1
    return self
 
  def __next__(self):
    x = self.a
    self.a += 1
    return x
 
myclass = MyNumbers() #用类定义一个对象
myiter = iter(myclass) #myiter是该对象的迭代器
 
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
'''
1
2
3
4
5
'''

函数

在这里插入图片描述

在 python 中,类型属于对象对象有不同类型的区分变量是没有类型的
a=[1,2,3]
a=“YysJyj”
以上代码中,[1,2,3] 是 List 类型,“YysJyj” 是 String 类型,而变量 a 是没有类型,她仅仅是一个对象的引用(一个指针),可以是指向 List 类型对象,也可以是指向 String 类型对象。
在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而list,dict 等则是可以修改的对象。

  1. 不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变 a 的值,相当于新生成了 a。
  2. 可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改本身la没有动只是其内部的一部分值被修改了
python参数传递

不可变类型:类似 C++ 的值传递,如整数、字符串、元组。如 fun(a),传递的只是 a 的值,没有影响 a 对象本身。如果在 fun(a) 内部修改 a 的值,则是新生成一个 a 的对象

可变类型:类似 C++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后 fun 外部的 la 也会受影响
python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。

关键字参数

使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。

#可写函数说明
def printinfo( name, age ):
   "打印任何传入的字符串"
   print ("名字: ", name)
   print ("年龄: ", age)
   return
 
#调用printinfo函数
printinfo( age=50, name="runoob" )
默认参数

调用函数时,如果没有传递参数,则会使用默认参数。 默认参数在被调函数声明形参时赋值
以下实例中如果没有传入 age 参数,则使用默认值:

#可写函数说明
def printinfo( name, age = 35 ):
   "打印任何传入的字符串"
   print ("名字: ", name)
   print ("年龄: ", age)
   return
 
#调用printinfo函数
printinfo( age=50, name="runoob" )
print ("------------------------")
printinfo( name="runoob" )

'''
名字:  runoob
年龄:  50
------------------------
名字:  runoob
年龄:  35
'''
不定长参数

程序可能需要一个函数能处理比当初声明时更多的参数,这些参数叫做不定长参数。
加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数

# 可写函数说明
def printinfo( arg1, *vartuple ):
   "打印任何传入的参数"
   print ("输出: ")
   print (arg1)
   print (vartuple)
 
# 调用printinfo 函数
printinfo( 70, 60, 50 )

'''
输出: 
70
(60, 50)
'''

加了两个星号 ** 的参数会以字典的形式导入。

# 可写函数说明
def printinfo( arg1, **vardict ):
   "打印任何传入的参数"
   print ("输出: ")
   print (arg1)
   print (vardict)
 
# 调用printinfo 函数
printinfo(1, a=2,b=3)

'''
输出: 
1
{'a': 2, 'b': 3}
'''

声明函数时,参数中星号 * 可以单独出现,如果单独出现星号 *,则星号 * 后的参数 必须用关键字传入
参数c必须用关键字传入:c=3

>>> def f(a,b,*,c):
...     return a+b+c
... 
>>> f(1,2,3)   # 报错
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() takes 2 positional arguments but 3 were given
>>> f(1,2,c=3) # 正常
6
匿名函数

python 使用 lambda 来创建匿名函数。
匿名 : 不再使用 def 语句这样标准的形式定义一个函数。

  1. lambda 只是一个表达式,函数体比 def 简单很多。
  2. lambda 的主体是一个表达式,而不是一个代码块。仅仅能在 lambda 表达式中封装有限的逻辑进去。
  3. lambda 函数有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数
  4. 虽然 lambda 函数看起来只能写一行,却不等同于 C 或 C++ 的内联函数,后者的目的调用小函数时不占用栈内存从而增加运行效率
语法

lambda 函数的语法只包含一个语句
设置参数 a 加上 10:

fun = lambda a : a + 10
print(fun(5))

'''
15
'''
强制位置参数

python3.8 新增了一个函数形参语法/用来指明函数形参 必须使用 指定位置参数不能使用 关键字参数的形式。
在以下的例子中,a,b,/ : 形参 a 和 b 必须使用指定位置参数c 或 d 可以是位置形参 或 关键字形参,而*,e,f :e 和 f 要求为关键字形参:

def f(a, b, /, c, d, *, e, f):  
    print(a, b, c, d, e, f)

f(10, 20, 30, d=40, e=50, f=60)

python数据结构

列表

方法
list_a=[] 定义一个列表
list_a.append(x) 在列表list_a后面添加元素x
list_a.extend(list_b) 在列表list_a后面添加列表list_b的所有元素
list_a.insert(i,x) 在位置i插入一个元素(i=0,....,len(list_a)-1)
list_a.remove(x) 删除列表内第一个值为x的元素
list_a.pop(i) 弹出位置i的元素,并返回其值,空括号()则弹出最后一个元素(i=0,....,len(list_a)-1)
list_a.clear() 移除表内所有元素 等价于 del a[:] 得到一个空列表[]
list_a.index(x) 返回列表中第一个值为x元素的索引下标
list_a.count(x) 返回x在列表中出现的次数
list_a.sort() 对列表中元素进行排序
list_a.reverse() 颠倒列表中元素顺序
list_a.copy() 返回列表的浅复制 等于a[:]  浅复制: 值复制,两者独立
把list作为栈使用(LIFO)

push(x) : list_a.append(x) #将x加到栈顶
pop() : list_a.pop() #弹出栈顶元素

把list作为队列使用(FIFO)

list_a.append(x) #在尾部添加元素x
list_a.pop(0) #弹出头部元素
效率低,因为弹出头部元素时,需要逐个移动元素

列表推导式

从序列创建列表
在这里插入图片描述

list_a=[1,2,3,4,5,6]
list_b= [3*x for x in list_a ] #返回一个列表
print(list_b)

创建元组要加[ ]
不改变列表的值
可以添加if语句作为过滤器
请添加图片描述
双变量循环
在这里插入图片描述
嵌套列表解析:
将3x4的矩阵列表转换成为4x3的矩阵列表

matrix=[
    [1,2,3,4],
    [5,6,7,8],
    [9,10,11,12]
]
list_a=[[row[i] for row in matrix] for i in range(4)] 
print(list_a)
'''
row在matrix里面遍历,i遍历0,1,2,3
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
'''

del 语句

在列表中,根据索引删除一个元素或删除一个子序列。

list_a=[1,2,3,4,5,6,7,8]

del list_a[0]
print(list_a)
del list_a[3:6]  #删除元素list_a[3]~list_a[5]
print(list_a)
del list_a[:]    
print(list_a)
'''
[2, 3, 4, 5, 6, 7, 8]
[2, 3, 4, 8] #删除元素: 5,6,7
[]
'''

也可以用del删除实体变量

del list_a  
print(list_a)  # NameError: name 'list_a' is not defined

元组和序列

元组是由若干逗号分隔的值组成
元组在输出时总是由括号的,在输入时可以没有括号

a=1,2,3,4,5,6,7
print(a)
print(type(a))
'''
(1, 2, 3, 4, 5, 6, 7)
<class 'tuple'>
'''
tuple_a= 'hello',10,12,234
print(tuple_a)
tuple_b=tuple_a,"world",(1,2,3,4,5,6,7,8)
print(tuple_b)
'''
('hello', 10, 12, 234)
(('hello', 10, 12, 234), 'world', (1, 2, 3, 4, 5, 6, 7, 8))
'''

集合

无序去重
基本功能:关系测试消除重复元素
集合可以用大括号 {} 创建
注意:如果想创建一个空集合,必须要使用set(),而不是{};{}是创建一个字典dict

basket_a=set()
print(basket_a)
print(type(basket_a))
basket_a=set('YysJyj')
print(basket_a)
'''
set()
<class 'set'>
{'y', 'Y', 'J', 's', 'j'}  #集合去重,无序
'''
basket={"abc","abc","1",2,3,4,5,6,7,8}
print(basket) #无序
#{2, 3, 4, 5, 6, 7, 8, 'abc', '1'}
a="abc" in basket #测试
print(a)
#True 
basket_a={"abc","abc","1",2,3,4,5,6,7,8}
basket_b={"abcd","abc",1,2,3,4,5,100,200,300}
#集合操作 - | & ^ 
print(basket_a-basket_b) #减操作:在a中不在b中
#{8, '1', 6, 7}
print(basket_a|basket_b) #或操作:在a中或在b中
#{'abcd', 1, 2, 3, 4, 5, 6, 7, 8, 200, '1', 100, 300, 'abc'}
print(basket_a&basket_b) #与操作:a和b中都有的元素
#{2, 3, 4, 5, 'abc'}
print(basket_a^basket_b) #在a或b中但不在a交b中
#{1, 'abcd', 100, 200, 6, 7, 8, 300, '1'}

集合也支持推导式

basket_a=[x for x in 'ab_cdefg' if x not in 'a_bc']
print(basket_a)
#['d', 'e', 'f', 'g']

字典

列表是以连续的整数作为索引,而字典以关键字作为索引:键值对 ( key:value )
在同一个字典中,关键字必须是互不相同的。
dict_a={} #创建一个空字典

dict_a.keys()
dict_a.values()
dict_a = {'a':9,'b':8,'c':7,'d':6}
list_a=list(dict_a.keys())
print(list_a) #['a', 'b', 'c', 'd']
list_b=list(dict_a.values())
print(list_b) #[9, 8, 7, 6]
print(dict_a) #{'a': 9, 'b': 8, 'c': 7, 'd': 6}
list_c=sorted(dict_a.keys())
print(list_c) #['a', 'b', 'c', 'd']
list_d=sorted(dict_a.values())
print(list_d) #[6, 7, 8, 9]
dict_a = {'a':9,'b':8,'c':7,'d':6} 
b= 'a' in dict_a   #仅检验key
print(b)  #True
c= 9 in dict_a
print(c) #False

构造函数dict()直接从键值对元组列表中构建字典

tuple_a=('1','2'),(2,3),(4,5)
dict_a=dict(tuple_a)
print(dict_a)
#{2: 3, 4: 5, '1': '2'} 
#无序的

字典推导可以用来创建任意键和值的表达式

dict_a={x:x*2 for x in (2,3,4)}
print(dict_a) #{2: 4, 3: 6, 4: 8}

如果关键字只是简单的字符串,使用 关键字参数 指定 键值对 更加方便

dict_a=dict(abc=100,bcd=200,edf=19999)
print(dict_a) #{'abc': 100, 'bcd': 200, 'edf': 19999}

遍历字典时,关键字和对应的值可以使用dict_a.items()方法同时解读出来:

dict_a={'ab':10,'cd':23,'vb':45,'vgg':67,'adc':78}
for x,y in dict_a.items():
    print(x,y)

'''
ab 10
cd 23
vb 45
vgg 67
adc 78
'''

列表遍历时,索引位置和对应的值可以使用enumerate()函数同时得到

list_a=['a','b','v','f','r','y']
for x,y in enumerate(list_a):
    print(x,y)

'''
0 a
1 b
2 v
3 f
4 r
5 y
'''
dict_a={'ab':10,'cd':23,'vb':45,'vgg':67,'adc':78}
for x,y in enumerate(dict_a): #默认把字典的keys()作为了列表
    print(x,y)

'''
0 ab
1 cd
2 vb
3 vgg
4 adc
'''
dict_a={'ab':10,'cd':23,'vb':45,'vgg':67,'adc':78}
for x,y in enumerate(dict_a.values()):  #把字典的values()作为了列表
    print(x,y)

'''
0 10
1 23
2 45
3 67
4 78
'''

同时遍历两个及以上序列时,可以使用zip()组合,zip() 将两个集合构造成为元组。

questions = ['name', 'quest', 'favorite color']
answers = ['lancelot', 'the holy grail', 'blue']
for x,y in zip(questions,answers):
    print('What\'s your {0}? It\'s {1}' .format(x,y))   
    #{0}接收.format(x,y)第一个参数;{1}接收第二个参数

'''
What's your name? It's lancelot
What's your quest? It's the holy grail
What's your favorite color? It's blue
'''

反向遍历一个序列,调用reversed()函数

questions = ['name', 'quest', 'favorite color']
for i in reversed(questions):
    print(i)

'''
favorite color
quest
name
'''

要求按顺序遍历一个序列时,使用sorted()函数返回一个已经排序的序列

questions = ['name', 'quest', 'favorite color']
for i in sorted(questions):
    print(i)

'''
favorite color
name
quest
'''

python3 模块

模块是一个包含所有定义的函数和变量的文件,后缀为.py
模块可以被别的程序引入,以使用该模块中的函数的功能
这也是使用python标准库的方法。

import语句

import module1,modile2...

当解释器遇到import语句,如果模块在当前的搜索路径就会被导入。
搜索路径是一个解释器会先进行搜索的所有目录的列表。

support.py

list_a=[1,2,3,4,5,6,7,8]

hello.py

import support

print(support.list_a) #[1, 2, 3, 4, 5, 6, 7, 8]

一个模块只会被导入一次,不管你执行力多少次import,
这样可以防止导入模块被一遍又一遍的执行。
当我们使用import语句时,python解释器会依次从搜索路径的目录中寻找所引入的模块。
搜索路径是在python编译或者安装的时候确定的,安装新的库时也会修改搜索路径。
sys模块中的path变量存储搜索路径

import sys

print(sys.path)
#['D:\\python_project', 'D:\\python_project', 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python38\\python38.zip', 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python38\\DLLs', 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python38\\lib', 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python38', 'D:\\python_project\\venv', 'D:\\python_project\\venv\\lib\\site-packages']

sys.path 输出的是一个路径列表

from import

从模块中导入指定函数

from module1 import fun1

把整个模块导入进来

from module1 import *

每个模块都有一个符号表,
当在模块A里导入模块B时,
模块B的符号表将被加入模块A中。

__name__属性

一个模块被另一个程序第一次引入时,其主程序将会运行;
若我们想在模块被引入时,
模块中的某一程序不执行,
我们可以用__name__属性来使该程序仅在该模块自身运行时执行。
每个模块都有一个__name__属性,当其值为 __main__ 时,表明该模块自身在运行,否则是被引入。

hello.py

list_b=[2,3,4,5,6]

if __name__ =='__main__':
    print("I'm main !")
else:
    print("I'm not main")

support.py

import hello

if __name__=='__main__':
    print(hello.list_b)

run support.py 输出:

I'm not main
[2, 3, 4, 5, 6]

run hello.py 输出:

I'm main !

dir()函数

内置的函数dir()可以找到模块内定义的所有名称,以字符串列表的形式返回。

hello.py

list_b=[2,3,4,5,6]

support.py

import hello

print(dir(hello))

输出:

#['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'list_b']

包是管理python模块命名空间的形式,采用“点模块名称”
比如一个模块的名称为A.B,那么他表示一个包A中的子模块B
采用点模块名称不用担心不同库之间的模块重名的情况

在导入一个包时,python会根据sys.path中的目录来寻找这个包中包含的子目录。
目录只有包含·一个叫做__init__.py的文件才会被认为一个包,主要是为了避免一些命名不小心影响搜索路径中的有效模块。

导入包内模块时,

import sound.effects.echo

这样导入,后面必须用全称访问:

print(sound.effects.echo.list_a)
from sound.effects import echo

这样导入,后面可以直接用echo访问

print(echo.list_a)

模块中的变量导入也可这样:
hello.py

list_b=[2,3,4,5,6]

support.py

from hello import list_b

print(list_b) #[2,3,4,5,6]

python3 输入和输出

python 两种输出值的方式:表达式语句和print()函数
第三种方法是使用文件对象的write()方法,标准输出文件可以使用sys.stdout引用
函数 str() 返回一个用户易读的表达形式
函数 repr() 产生一个解释器易读的表达形式

str_a="hello\tworld"
print(str(str_a))
print(repr(str_a))
'''
hello	world   #用户易读
'hello\tworld'  #解释器易读
'''
str_a=repr("hello\tworld")
print(str_a) #'hello\tworld'

字符串对象的rjust()方法,它可以将字符串靠右,并在左边填充空格,类似的还有ljust()靠左,center()居中。

print('abc'.rjust(5))
print('abc'.ljust(5),'abc'.ljust(1))
print('abc'.center(10))
'''
  abc
abc   abc
   abc    
'''

zfill() 会再左边填充0

print('abc'.zfill(5))
print('abc'.zfill(5),'abc'.zfill(4))
print('abc'.zfill(10))
'''
00abc
00abc 0abc
0000000abc
'''

str.format() 使用方法

#默认顺序
print("{} 是第一个参数,{} 是第二个参数".format("First" , "Second"))
#First 是第一个参数,Second 是第二个参数
#指定顺序从0开始
print("{1} 是第一个参数,{0} 是第二个参数".format("First" , "Second"))
#Second 是第一个参数,First 是第二个参数
#还可以使用关键字
print("{Fir} 是第一个参数,{Sec} 是第二个参数".format(Fir="First" , Sec="Second"))
#First 是第一个参数,Second 是第二个参数
# !a使用ASCII  !s使用str()  !r使用repr()
print("{} 是第二个参数".format("Second"))
print("{!r} 是第二个参数".format("Second"))
'''
Second 是第二个参数
'Second' 是第二个参数
'''
# 用 : 对值进行更好的格式化
import math
print("PI 近似等于 {:.3f}".format(math.pi))
# 四舍五入地保留三为小数 3.142
#在:后面传入一个整数可以保证该域至少宽度
table = {'Google': 1, 'Runoob': 2, 'Taobao': 3}
for name, number in table.items():
    print('{0:10} ==> {1:10d}'.format(name, number))
    
'''
Google     ==>          1
Runoob     ==>          2
Taobao     ==>          3
'''
# :前面的数字控制参数传入次序
table = {'Google': 1, 'Runoob': 2, 'Taobao': 3}
for name, number in table.items():
    print('{1:10d} ==> {0:10}'.format(name, number))

'''
         1 ==> Google    
         2 ==> Runoob    
         3 ==> Taobao    
'''

** [] {key:}

table = {'Google': 1, 'Runoob': 2, 'Taobao': 3}
print('Runoob: {0[Runoob]:d}; Google: {0[Google]:d}; Taobao: {0[Taobao]:d}'.format(table))
#Runoob: 2; Google: 1; Taobao: 3
print('Runoob: {Runoob:d}; Google: {Google:d}; Taobao: {Taobao:d}'.format(**table))
#Runoob: 2; Google: 1; Taobao: 3

table = {'Google': 1, 'Runoob': 2, 'Taobao': 3}
print('Runoob: {Runoob:5d}; Google: {Google:5d}; Taobao: {Taobao:5d}'.format(**table))
#Runoob:     2; Google:     1; Taobao:     3

%操作符

import math
print("PI is %3.5f" % math.pi) #将值代入,并返回格式化后的字符串,旧式符号
#PI is 3.14159

import math
print("PI is {:3.5f}".format(math.pi))
#PI is 3.14159

读取键盘输入

python提供了input()内置函数从标准输入读入一行文本,默认的标准输入是键盘
input()括号内可以填上输入提示符

str=input("请输入一个字符串:")
print(str)
'''
请输入一个字符串:YYSJYJ
YYSJYJ
'''

读和写文件

open(filename,mode)
将会返回一个file对象
filename : 文件路径 如:“D:\python_project\venv\helloo.txt”
mode : 决定了打开文件的模式:只读,写入,追加等,文件的默认访问模式为只读 ‘r’
r: 只读
rb: 以二进制格式打开,只读
r+: 读写
rb+:以二进制格式打开,读写
w: 打开文件只用于写入,存在文件:覆盖原值; 不存在文件:创建文件;
wb: 以二进制格式打开只用于写入,存在文件:覆盖原值; 不存在文件:创建文件;
w+: 打开文件用于读写,存在文件:覆盖原值; 不存在文件:创建文件;
wb+: 以二进制格式打开文件用于读写,存在文件:覆盖原值; 不存在文件:创建文件;
a: 打开一个文件用于追加
ab: 以二进制格式打开一个文件用于追加
a+: 打开一个文件用于读写,写是追加
ab+: 以二进制格式代开一个文件用于追加

在这里插入图片描述

f=open("D:\python_project\\venv\helloo.txt", 'w')
f.write("This is my first using a file function")

位于"D:\python_project\venv\helloo.txt"的文件则被写入
This is my first using a file function

文件对象的方法

f.read(size)

为了读取一个文件的内容,调用f.read(size),这将读取一定数目的数据,然后作为字符串或字节对象返回。
size是一个可选的数字类型参数,当size被忽略或者为负数,则该文件的所有内容都将被读取并且返回。

#helloo.txt
'''
This is my first using a file function
This is my first using a file function
This is my first using a file function
'''

f=open("D:\python_project\\venv\helloo.txt", 'r')
a=f.read(10)
print(a) #This is my
f.readline()

从文件中读取单独的一行,若f.readline()返回一个空字符串,则说明已经读取到最后一行。

#helloo.txt
'''
line 1 This is my first using a file function
line 2 This is my first using a file function
line 3 This is my first using a file function
'''

f=open("D:\python_project\\venv\helloo.txt", 'r')
a=f.readline()
print(a) 
#line 1 This is my first using a file function
f.readlines(sizehint)

sizehint可选参数,读取指定长度的字节,并将这些字节按行分割

#helloo.txt
'''
line 1 This is my first using a file function
line 2 This is my first using a file function
line 3 This is my first using a file function
'''

f=open("D:\python_project\\venv\helloo.txt", 'r')
a=f.readlines(50)
print(a)
#['line 1 This is my first using a file function\n', 'line 2 This is my first using a file function\n']
#helloo.txt
'''
line 1 This is my first using a file function
line 2 This is my first using a file function
line 3 This is my first using a file function
'''

f=open("D:\python_project\\venv\helloo.txt", 'r')
for line in f:
    print(line)
'''
line 1 This is my first using a file function

line 2 This is my first using a file function

line 3 This is my first using a file function

'''
f.close()关闭打开的文件
f.write(string) 返回写入的字符数
f=open("D:\python_project\\venv\helloo.txt",'w')
num=f.write("abc")
print(num) #3
f.tell()

返回文件对象(指针)当前所在位置,它是从文件开头开始算起的字节数

f=open("D:\python_project\\venv\helloo.txt",'w')
f.write("abcd")
num=f.tell()
print(num) #4

f.close()
f.seek(offset,from_what) 返回指针当前位置(指针位置从0开始)

改变文件指针当前位置
from_what的值,如果是0表示开头,如果是1表示当前位置,2表示文件结尾,如:
seek(x,0) 从起始位置即文件首行首字符开始移动x个字符
seek(x,1) 从当前位置往后移动x个字符
seek(-x,2)文件结尾往前移动x个字符
from_what值默认是0,从开头位置。

#helloo.txt
'''
abc123abc
'''

f=open("D:\python_project\\venv\helloo.txt",'rb')
#在文本文件中,没有使用二进制模式打开的文件,只允许从文件开头开始计算相对位置,否则报错,将'r'改成‘rb'即可
a=f.seek(1)
print(a)#1
b=f.seek(1,1)
print(b)#2
c=f.seek(-2,2)
print(c)#7
f.close()

在文本文件中(打开模式没有b的),只会相对于文件起始位置进行定位。
当处理完一个文件后,调用f.close()来关闭文件并释放系统资源,如果尝试再调用该文件则会报错

f.close()
d=f.seek(-1,2)
print(d)
#ValueError: seek of closed file

当处理一个文件对象时,使用with关键字是非常好的方式,with open() as xxx
它会帮你正确的关闭文件!

#helloo.txt
'''
abc123abc
'''

with open("D:\python_project\\venv\helloo.txt",'rb') as f:
    a=f.read(5)
    print(a) #b'abc12'

pickle 模块

python的pickle模块实现了基本的数据序列反序列化
通过pickle模块的序列化操作,我们可以将程序中运行的对象信息保存到文件中去,永久存储
通过picle模块的反序列化操作,我们能够从文件中创建上一次程序保存的对象

pickle.dump(obj,file,[protocol])

import pickle

# 使用pickle模块将数据对象保存到文件
data1 = {'a': [1, 2.0, 3, 4+6j],
         'b': ('string', u'Unicode string'),
         'c': None}

selfref_list = [1, 2, 3]
selfref_list.append(selfref_list)

output = open('D:\python_project\\venv\helloo.txt', 'wb')

# Pickle dictionary using protocol 0.
pickle.dump(data1, output)

# Pickle the list using the highest protocol available.
pickle.dump(selfref_list, output, -1)

output.close()
f.open(file,mode)

open() 方法
用于打开一个文件,并返回文件对象
若文件无法打开,抛出OSError
注意:使用open()方法一定要保证关闭文件对象,即调用close()方法

f.writelines(sequence)

向文件写入一个序列字符串列表,
如果需要换行,则需要自己加入每行的换行符’\n’

python3 os 文件、目录方法

os模块提供了非常丰富的方法用来处理文件和目录

import os

os.access(path.mode) 检验权限模式
os.chdir(path) 改变当前工作目录
os.chflags(path,flags) 设置路径的标记为数字标记
os.chmod(path,mode) 更改权限
os.chown(path,uid,gid) 更改文件所有者
os.chroot(path) 改变当前进程的根目录
os.close(fd) 关闭文件描述符fd
os.closerange(fd_low,fd_high) 关闭文件描述符[fd_low,fd_high),错误会忽略
os.dup(fd) 复制文件描述符fd
os.dup2(fd,fd2) 将文件描述符复制到另一个fd2 fd-->fd2
os.fchdir(fd) 通过文件描述符改变当前工作目录
os.fdopen(fd) 通过文件描述符fd创建一个文件对象,并返回这个文件对象
os.getcwd() 返回当前工作目录

os.read(fd,n) 
从文件描述符fd中读取最多n个字节,返回包含读取字节的字符串,
文件描述符fd对应文件已达到结尾,返回一个空字符串。
os.readlink(path) 返回软连接所指向的文件
os.unlink(path) 删除文件路径
os.remove(path) 删除路径为path的文件,若path是一个文件夹,则抛出OSError
os.removedirs(path) 递归删除目录
os.rename(src,dst) 重命名文件或目录,从src-->dst
os.rmdir(path) 删除path指定的空目录,若目录非空则抛出OSError

os.write(fd,str) 写入字符串到文件描述符fd中,返回实际写入的字符串长度

os.pardir() 获取当前目录的父目录,以字符串形式显示目录名

python3 错误和异常

python assert (断言) 用于判断一个表达式,在表达式条件为false时触发异常。
异常处理:不是语法错误!

try/except 语句

在这里插入图片描述
首先执行try子句,如果没有发生异常则忽略except子句
如果执行try子句的过程中发生了异常,则会忽略try子句剩余部分,
若异常类型和except后面的名称相符,则对应的except子句将被执行,
若一个异常没有与任何一个except匹配,则这个异常将会被传递给上层的try中。

while True:
    try:
        x = int(input("请输入一个数字: "))
        break
    except ValueError:
        print("您输入的不是数字,请再次尝试输入!")
'''
请输入一个数字: a
您输入的不是数字,请再次尝试输入!
'''

一个try语句可能包含多个except子句,分别来处理不同的特定的异常,最多只有一个分支会被执行。
处理程序将只针对 对应的try子句 中的异常进行处理,而不是其他的try的处理程序中的异常。
一个except子句可以同时处理多个异常,这些异常将被放在一个括号里面组成一个元组,最后一个except子句可以忽略异常的名称,它将被当作通配符使用。

try:
    pass
except (RuntimeError , TypeError , NameError):
    pass
except:
    pass
try/except-else 语句

可选的else子句,若使用,则必须将它放在所有的except子句之后;
else子句将在try子句没有发生任何异常的时候执行。
在这里插入图片描述

try:
    x = int(input("请输入一个数字: "))

except ValueError:
    print("您输入的不是数字,请再次尝试输入!")
else:
    print("I'm else !")
'''
请输入一个数字: 3
I'm else !
'''
'''
请输入一个数字: a
您输入的不是数字,请再次尝试输入!
'''

下面示例:在try语句中判断文件是否可以被打开,如果打开文件时,没有发生异常则执行else部分的语句,读取文件内容:

for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print('cannot open', arg)
    else:
        print(arg, 'has', len(f.readlines()), 'lines')
        f.close()

使用else子句比把所有的语句都放在try子句里面要好,
这样可以避免一些意想不到的,except又无法捕获的异常。
异常处理并不仅仅处理那些直接发生在try子句中的异常,
而且还能处理子句中调用的函数(甚至是间接调用的函数)里面抛出的异常。例如:

def this_fails():
    x = 1/ 0

try:
    this_fails()
except ZeroDivisionError as err:       #ZeroDivisionError: division by zero
    print('Handling run-time error:', err)
    
#Handling run-time error: division by zero
try/except-else-finally 语句

语句无论是否发生异常都会执行最后的代码在这里插入图片描述

try:
    runoob()
except AssertionError as error:
    print(error)
else:
    try:
        with open('file.log') as file:
            read_data = file.read()
    except FileNotFoundError as fnf_error:
        print(fnf_error)
finally:
    print('这句话,无论异常是否发生都会执行。')
    
'''
这句话,无论异常是否发生都会执行。
Traceback (most recent call last):
  File "D:/python_project/hello.py", line 4, in <module>
    runoob()
NameError: name 'runoob' is not defined
'''

抛出异常

python使用raise语句抛出一个指定的异常
raise [Exception]
在这里插入图片描述
以下示例:如果x>5就触发异常

a=input("请输入任意一个小于10的数 : ")
if int(a)>=10:
    raise Exception("a值大于等于10了,a={}".format(a))
else:
    print(a)
'''
请输入任意一个小于10的数 : 10
Traceback (most recent call last):
  File "D:/python_project/hello.py", line 5, in <module>
    raise Exception("a值大于等于10了,a={}".format(a))
Exception: a值大于等于10了,a=10
'''

用户自定义异常

用户自定义异常继承自Exception类,可以直接继承,或者间接继承,

class MyError(Exception): #继承自Exception类
	def __init__(self,value):
		self.value=value
	def __str__(self):
		rerturn repr(self.value) #repr()解释器易读; str()用户易读
try:
	raise MyError(2*2)
except MyError as e:
	print("My exception occurred,value:", e.value)
#My exception occurred,value: 4
class MyError(Exception):
	def __init__(self,value):
		self.value=value
	def __str__(self):
		return repr(self.value) #repr()解释器易读; str()用户易读
try:
	raise MyError(2*2)
except MyError as e:
	print("My exception occurred,value:", e.value)
finally:
        raise MyError("oops!")
'''
Traceback (most recent call last):
  File "D:/python_project/hello.py", line 12, in <module>
    raise MyError("oops!")
__main__.MyError: 'oops!'
My exception occurred,value: 4
'''

在这个例子中,类Exception默认的__init__被覆盖。
当创建一个模块有可能抛出多种不同的异常时,
一种通常的做法是为这个包建立一个基础异常类,
然后基于这个基础类为不同的错误情况创建不同的子类;
大多数的异常的名字都是以Error结尾

定义清理行为:关闭打开的文件

如果一个异常在try子句内被抛出,而没有任何except把它拦截,
那么这个异常会再finally子句被执行后被抛出。
一些对象,定义了标准的清理行为,无论系统是否成功的使用了它,一旦不需要了,那么这个标准的清理行为就会执行。

for line in open("myfile.txt"):
	print(line,end="")

这段代码的问题是,当执行完毕后,文件会保持打开的状态,并没有被关闭;
使用关键词with语句就可以保证诸如文件之类的对象,在使用完之后一定会正确的执行他的清理方法

with open("myfile.txt") as f:
	for line in f:
		print(line,end="")

就算在处理过程中出问题了,文件f也会被关闭。
因为with关键字用于异常处理,封装了try-except-finally编码范式,
在处理文件对象时使用with是一种很好的做法。

python3 面向对象

python从设计之初就是一门面向对象的语言;
因此,在python中创建一个类和对象是很容易的。

面向对象技术简介

类(class):用来描述具有相同属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例
方法:类中定义的函数。
类变量:类变量在整个实例化的对象中是公用的
数据成员:类变量实例变量用于处理类及其实例对象的相关的数据。
方法重写:如果从父类继承的方法不能满足子类的需求可以对其进行改写,这个过程叫做方法的覆盖,也称为方法的改写。
局部变量:定义在方法中的变量,只作用于当前实例的类。
实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用self修饰的变量
继承:一个派生类继承基类字段和方法
实例化:创建一个类的实例(对象)。
对象:通过类定义的数据结构的实例。对象包括两个数据成员(类变量和实例变量) 和方法。

python 中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类,派生类可以覆盖基类中的任何方法,方法中可以调用基类中的同名方法。

对象可以包含任意数量和类型的数据。

类定义

class ClassName:
	<statement>

类实例化后,可以使用其属性,实际上,创建一个类之后,可以通过类名访问其属性。

类对象

类对象支持两种操作:属性引用和实例化
属性引用使用和python中所有属性引用一样的标准语法:obj.name
类对象创建后,类命名空间中所有的命名都是有效属性命名

class MyFirstClass:
        def __init__(self,str): #初始化
                self.str=str
        def fun0(self):
                print("百年好合")

x=MyFirstClass("YysJyj") #创建的一个新的类实例(对象)并赋值给局部变量x,x为空对象
print(x.str) #YysJyj
x.fun0() #百年好合

类有一个名为__init__()的特殊方法(构造方法),该方法在类实例化(定义对象)时会自动调用

def __init__(self):
	self.data=[]

类定义了__init__()方法,类的实例化操作会自动调用__init__()方法。
init()方法可以有参数,参数通过__init__()传递类的实例化操作上

class MyFirstClass:
        def __init__(self,str1,str2):
                self.a=str1
                self.b=str2
x=MyFirstClass("Yys","Jyj")
print(x.a,"love",x.b) #Yys love Jyj

self代表类的实例(对象),而非类

类的方法普通的函数只有一个特别的区别:它们必须有一个额外的第一个参数名称,按照惯例它的名称是self

class Test:
        def prt(self):
                print(self)
                print(self.__class__)
t=Test()
t.prt()
'''
<__main__.Test object at 0x000001C66DFB7430>
<class '__main__.Test'>
'''

从执行结果看,self代表类的实例(object),self.class指向类
self不是python的关键字,把self换成Yysjyj也可以

类的方法

在类的内部,使用def关键字来定义一个方法,与一般函数定义不同,

类方法必须包含参数self,且为第一个参数,self代表的是类的实例。

class people:
    # 定义基本属性
    name = ''
    age = 0
    # __name 定义私有属性,私有属性在类外部无法直接进行访问
    __weight = 0

    # 定义构造方法
    def __init__(self, n, a, w):
        self.name = n
        self.age = a
        self.__weight = w

    def speak(self):
        print("{} 说: 我 {} 岁。"  .format(self.name, self.age))

# 实例化类
p = people('runoob', 10, 30)
p.speak() #runoob 说: 我 10 岁。

继承

子类(派生类)会继承父类(基类)的属性和方法。
class child(parent):
	<statement>
class parent():
    def prt(self):
        print("I am parent !")

class child(parent):
    pass

x=child()
x.prt() #I am parent !

多重继承

class child(parent1,parent2,parent3):
	<statement>
class parent1():
    def prt1(self):
        print("I am parent1 !")

class parent2():
    def prt2(self):
        print("I am parent2 !")

class parent3():
    def prt3(self):
        print("I am parent3 !")

class child(parent1,parent2,parent3):
    pass

x=child()
x.prt1()
x.prt2()
x.prt3()

'''
I am parent1 !
I am parent2 !
I am parent3 !
'''

注意括号内父类的顺序,若是父类中有相同的方法名字,而在子类使用时未指定,
python从左至右搜索
当子类对象在调用一个方法,并在子类中未找到时,从左到右查找父类中是否包含方法。

方法重写

若父类的方法的功能不能满足需求,则可以在子类重写父类的方法:同名覆盖
因为对象会先搜索子类再搜索父类中的方法。

class parent0():
    def prt(self):
        print("I am parent !")

class child0(parent0):
    def prt(self):
        print("I am Child !")

x=child0()
x.prt()
super(child0,x).prt() #通过子调用父类的同名方法

'''
I am Child !
I am parent !
'''

super()函数是用于调用父类(超类)的一个方法。

类属性与方法

类的私有属性(私有变量)
__hight :两个下划线开头,声明该属性为私有,可以在类内部使用,不能在类的外部被使用或直接访问。
类的方法

在类的内部,使用def关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数self
,且为第一个参数,self代表的是类的实例。self的名字并不是规定死的,也可以使用YysJyj,但最好还是按照约定使用self

类的私有方法(私有函数)
__fun0 :两个下划线开头,声明该方法为私有方法,只能在类的内部调用,不能在类的外部调用。
class child0():
    def __prt(self):
        print("I am Child !")

x=child0()
x.__prt()

'''
Traceback (most recent call last):
  File "D:/python_project/hello.py", line 8, in <module>
    x.__prt()
AttributeError: 'child0' object has no attribute '__prt'
'''
#外部不能调用私有方法

类的专有方法

__init__:构造函数,在生成对象时调用
__del__:析构函数,释放对象时使用

析构函数与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,delete会自动调用析构函数后释放内存)。

__repr__:打印,转换
__setitem__:按照索引赋值
__getitem__:按照索引获取值
__len__:获得长度
__cmp__:比较运算
__call__:函数调用
__add__:加运算
__sub__:减运算
__mul__:乘运算
__truediv__:除运算
__mod__:求余运算
__pow__:乘方

运算符重载

class Vector:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __str__(self):
        return 'Vector (%d, %d)' % (self.a, self.b)

    def __add__(self, other):
        return Vector(self.a  + other.a, self.b + other.b)


v1 = Vector(2, 10)
v2 = Vector(5, -2)
v3 = Vector(100,300)
v4 = Vector(-100,-300)
print(v1 + v2 + v3 + v4)
#Vector (7, 8)

python3 命名空间和作用域

命名空间是从名称到对象的映射,大部分命名空间都是通过python字典来实现的。
命名空间提供了在项目中避免名字冲突的一种方法,各个命名空间是独立的没有任何关系的,所以一个命名空间中不能有重名,但不同的命名空间是可以重名而没有任何影响的。
一般有三种命名空间:
内置名称:python语言内置的名称,比如abs、char、和异常名称BaseException、Exception等等。
全局名称:模块中定义的名称,记录了模块的变量,包括函数、类、其他导入的模块、模块级的变量和常量。
局部名称:函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)
在这里插入图片描述

命名空间查找顺序:局部 --> 全局 --> 内置

若找不到,则引发一个NameError异常

命名空间的生命周期:取决于对象的作用域,如果对象执行完毕,则该命名空间的生命周期就结束。因此,我们无法从外部命名空间访问内部命名空间的对象。
# var1 是全局名称
var1 = 5
def some_func():
 
    # var2 是局部名称
    var2 = 6
    def some_inner_func():
 
        # var3 是内嵌的局部名称
        var3 = 7

python的4种作用域

L:local: 最内层包含局部变量,比如一个函数/方法内部
E:Enclosing: 包含非局部非全局的变量,就是闭包函数外的函数,比如两个嵌套函数,函数A里面嵌套函数B,对于函数B中的名称来说,A中的作用域就为nonlocal
G:Global: 当前脚本的最外层,比如当前模块的全局变量
B:Built-in: 包含了内建的变量/关键字等,最后被搜索
规则顺序:L–>E–>G–>B

在这里插入图片描述

g_count = 0  # 全局作用域
def outer():
    o_count = 1  # 闭包函数外的函数中
    def inner():
        i_count = 2  # 局部作用域

python 中只有模块(module)、类(class)、函数(def , lambda)才会引入新的作用域,其他的代码(如 if/elif/else try/except/else/finally for while 等)是不会引入新的作用域的,也就是说在这些语句内部定义的变量,在外部也能访问

a=100
if a==100:
    b=a
else:
    b=0

print(b) #100
a=100
def fun0() :
    if a == 100:
        b = a
    else:
        b = 0
        
print(b)
#NameError: name 'b' is not defined

全局变量和局部变量

定义在函数内部的变量拥有一个局部作用域,定义在函数外部的变量拥有全局作用域。
局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。
调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。

global 和 nonlocal 关键字

当内部作用域想要修改外部作用域的变量时,就要用到global和nonlocal关键字了。

num = 1
def fun1():
    global num  # 需要使用 global 关键字声明
    print(num) 
    num = 123
    print(num)
fun1()
print(num)

'''
1
123
123
'''
def outer():
    num = 10
    def inner():
        nonlocal num   # nonlocal关键字声明
        num = 100
        print(num)
    inner()
    print(num)
outer()

'''
100
100
'''

一种易错情况

a = 10
def test():
    a = a + 1
    print(a)
test()
#UnboundLocalError: local variable 'a' referenced before assignment

报错原因:test()内的a是函数内部新定义的局部变量,因为未赋值,无法修改而报错,而不是全局变量a,这俩同名变量使用不同的地址!
修改1:

a = 10
def test():
	global a #声明global
    a = a + 1
    print(a)
test()
#11
a = 10
def test(a): #传参进来
    a = a + 1
    print(a)
test()
#11

python3 标准库概览

操作系统接口 import os

建议使用 import os 而非 from os import *
因为这样使用os.fun()可以保证随着操作系统不同而有所变化的os.open()不会覆盖内置函数open()

文件通配符 import glob

glob模块提供了一个函数用于从目录通配符搜索中生成文件列表

import glob
f=[]
f=glob.glob("*.py")
print(f)
#['hello.py', 'support.py']
#文件列表

命令行参数 import sys

通用工具脚本经常调用命令行参数
这些 命令行参数(包含文件名)链表的形式存储于sys模块的argv变量中
例如在命令行中执行

>>> import sys
>>>python demo.py one two three
>>> print(sys.argv)
['demo.py', 'one', 'two', 'three']

错误输出重定向和程序终止

sys 还有 stdin,stdout 和 stderr 属性,即使在 stdout 被重定向时,后者也可以用于显示警告和错误信息。

>>> sys.stderr.write('Warning, log file not found starting a new one\n')
Warning, log file not found starting a new one

大多数脚本的定向终止都使用 “sys.exit()”。

字符串替换方法 “str”.replace(“yuan”,“tihuan”)

a="tea for too"
a=a.replace("too","two")
print(a)
#tea for two

数学

import math

math模块为浮点运算提供了对底层c函数库的访问

>>> import math
>>> math.cos(math.pi / 4)
0.70710678118654757
>>> math.log(1024, 2)
10.0
import random

random提供了生成随机数的工具

>>> import random
>>> random.choice(['apple', 'pear', 'banana']) #列表内随机选择
'apple'
>>> random.sample(range(100), 10)   # sampling without replacement : [0,100)随机采样10个
[30, 83, 16, 4, 8, 81, 41, 50, 18, 33]
>>> random.random()    # random float : [0,1)之间的随机浮点数
0.17970987693706186
>>> random.randrange(6)    # random integer chosen from range(6) : [0,6)之间的随机整数
4
import random

a=[]
a=random.sample(range(1000),10)
print(a)
#[793, 846, 177, 803, 269, 377, 63, 804, 687, 652]

日期和时间 from datetime import date

from datetime import date

now = date.today()
print(now)
#2022-09-22

birthday = date(1998,9,26)
print(birthday)
#1998-09-26

age= now -birthday
print(age.days)
#8762
print(age.days/365)
#24.005479452054793

数据压缩 import zlib

import zlib

str0=b"yysjyj"*10
print(str0)
#b'yysjyjyysjyjyysjyjyysjyjyysjyjyysjyjyysjyjyysjyjyysjyjyysjyj'
print(len(str0))
#60
str1=zlib.compress(str0) #压缩
print(str1)
#b'x\x9c\xab\xac,\xce\xaa\xcc\xaa$\x8b\x04\x008\x1f\x1a\xf5'
print(len(str1))
#17
str1=zlib.decompress(str1) #解压缩
print(str1)
#b'yysjyjyysjyjyysjyjyysjyjyysjyjyysjyjyysjyjyysjyjyysjyjyysjyj'
print(len(str1))
#60
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值