crazy-heng
天降大任于斯人也...

导航

 

3.1、三元运算

概念:三元运算又称三目运算,是对简单的条件语句的简写。

1 if  3>1:
2     val = 1
3 else:
4     val =1o
5 
6 改成三元运算后:
7 val = 1 if 3>1 else 10

 

 

3.2、文件操作

一、读文件

 f = open(file=/Users/crazy_heng/PycharmProjects/untitled/exercise/exercise.txt',mode='r',encoding='utf-8')
其中 f= 后面的是固定语法,file= 是文件的绝对路径➕要读取的文件名
mode= 表示模式,r 代表只读模式
encoding= 表示将硬盘上的文件按后面指定的规则去转码
2 3 data = f.read()
f.read()表示将内容转换成字符串后作为参数传给data这个变量。 4 5 f.close
表示关闭文件夹

 二、二进制模式读文件

1  f = open(file=/Users/crazy_heng/PycharmProjects/untitled/exercise/exercise.txt',mode='rb')
2 
3 和读文件一样,只不过是模式变成了rb模式
4 data = f. read()
5 
6 f.close()

在mode=rb的情况下,是以二进制的模式打开文件,数据读到内容里直接是bytes格式,所以不需要指定encoding,如果想看内容还需要decode一下。

三、导入chardet模块判断文件编码

1 import chardet
2 
3 f = open('log',mode='rb')
4 data = f.read()
5 f.close()
6 
7 result = chardet.detect(open('log',mode='rb').read())
8 print(result)

输出:

1 {'encoding': 'GB2312', 'confidence': 0.99, 'language': 'Chinese'}

四、循环文件

1 f = open("兼职白领学生空姐模特护士联系方式.txt",'r',encoding="utf-8")
2 
3 for line in f:
4     print(line)
5 
6 f.close()

输出即将文件内容循环输出

五、写文件

1 f = open('路径+文件名','r',encoding='utf-8')  如果不加文件名则是在默认路径上写文件
2 f.write('文件内容')
3 f.close

六、二进制模式写文件

1 f = open(file='D:/工作日常/兼职白领学生空姐模特护士联系方式.txt',mode='wb') 以2进制模式写
2 f.write('北大本科美国留学一次50,微信号:xxxxx'.encode('utf-8'))
3 f.close()

注意:

在文件以w或wb的模式打开文件的时候是只写模式,读不了文件内容,并且打开文件的同时或默认将原文件内容清空。原本有内容的或以w或者wb模式打开,原内容就会清空,而不是添加内容,相当于写新的文件。

七、追加文件

1 f = open("兼职白领学生空姐模特护士联系方式.txt",'a',encoding="gbk")
2 
3 f.write("\n杜姗姗 北京  167 49 13324523342")
4 f.close()

同样追加有a和ab(2进制模式追加)两种模式,当文件以这两种模式打开时,则只能追加,写入的内容会在原内容尾部追加

八、读写模式

之前的模式都说只读、只写、只追加,这种就是又可以读又可以写的模式

1 f = open("兼职白领学生空姐模特护士联系方式.txt",'r+',encoding="gbk")
2 data = f.read() #可以读内容 
3 print(data)
4 f.write("\nblack girl  河北  167 50  13542342233") #可以写
5 f.close()

这样write后面的内容写到了文件的追后面,也就是相当于追加模式下多了一个读文件。

还有一个和读写模式相对应的是写读模式,同样的道理,写读模式是先写后读,而读的时候会把原文件清空,相当于只写模式,它只是多了一个读的功能,还是读后面写的内容,原先内容还读不出来,并没什么卵用,这里就不介绍了。

九、文件操作的其他功能

1   def flush(self, *args, **kwargs): # real signature unknown
2         把文件从内存buffer里强制刷新到硬盘
文件操作里,因为硬盘比内存慢很多,如果每次写的东西都从内存传到硬盘的话速度会很慢,所以你写的内容都先存到内存buffer里,当buffer慢了会自动写到硬盘里,或者直到你f.close 后就会把buffer里的内容传到硬盘里。
它的作用:可以让你手动强制把内存buffer里内容刷新到硬盘
用法:f.flush()

1 def readline(self, *args, **kwargs): # real signature unknown
2         只读一行,遇到\r or \n为止
f.read()是把文件全部读完,f.readline()则是读到\n也就是换行的时候停止,这个可以结合for循环对文件循环的时候用
用法: f.readline()
1   def tell(self, *args, **kwargs): # real signature unknown
2         返回当前文件操作光标位置 
f.tell() 系统会返回当前文件操作的光标位置
1 def seek(self, *args, **kwargs): # real signature unknown
2         把操作文件的光标移到指定位置
3         *注意seek的长度是按字节算的, 字符编码存每个字符所占的字节长度不一样。
4         如“路飞学城” 用gbk存是2个字节一个字,用utf-8就是3个字节,因此以gbk打开时,seek(4) 就把光标切换到了“飞”和“学”两个字中间。
5         但如果是utf8,seek(4)会导致,拿到了飞这个字的一部分字节,打印的话会报错,因为处理剩下的文本时发现用utf8处理不了了,因为编码对不上了。少了一个字节

注意:f.tell()和f.seek()都说按文件字节来算,所以要注意你的文件的编码格式,gbk中,中文是2个字节一中文,在utf-8中是3个字节一个中文,f.read()是按字符算的,括号里写3那就是读这个文件里第三个字符。

1  def truncate(self, *args, **kwargs): # real signature unknown
2         按指定长度截断文件
3         *指定长度的话,就从文件开头开始截断指定长度,不指定长度的话,就从当前位置到文件尾部的内容全去掉。
f.truncate()里面如果指定长度(也是指定字节)如:f.truncate(3)那就会从开头到字节3,后面的都全部去掉。

十、修改文件

 1 import os
 2 
 3 f_name = "兼职白领学生空姐模特护士联系方式utf8.txt"
 4 f_new_name = "%s.new" % f_name
 5 
 6 old_str = "乔亦菲"
 7 new_str = "[乔亦菲 Yifei Qiao]"
 8 
 9 f = open(f_name,'r',encoding="utf-8")
10 f_new = open(f_new_name,'w',encoding="utf-8")
11 
12 for line in f:
13 
14     if old_str in line:
15         new_line = line.replace(old_str,new_str)
16     else:
17         new_line = line
18 
19     f_new.write(new_line)
20 
21 f.close()
22 f_new.close()
23 
24 os.rename(f_new_name,f_name) #把新文件名字改成原文件 的名字,就把之前的覆盖掉了,windows使用os.replace # 帮助文档说明replace会覆盖原文件

 

 3.3、函数 

一、函数的定义

定义:函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数只需调用其函数名即可。

作用:减少重复的代码

     使程序变的可扩展

   使程序变得易维护

定义:在Python中,定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回。

例子

1 def my_abs(x):
2     if x >= 0:
3         return x
4     else:
5         return -x
my_abs(3) 直接输入函数名带参数来执行函数

 

二、函数参数

函数参数分为

1、形式参数:只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。所以,形参之在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参。

2、实际参数:可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值

这一块等后面学了作用域后再回过头来分析

 

三、默认参数

 1 def stu_register(name,age,country,course):
 2     print("----注册学生信息------")
 3     print("姓名:",name)
 4     print("age:",age)
 5     print("国籍:",country)
 6     print("课程:",course)
 7 
 8 stu_register("王山炮",22,"CN","python_devops")
 9 stu_register("张叫春",21,"CN","linux")
10 stu_register("刘老根",25,"CN","linux")

像coutry这个参数,在调用的时候大多数都是cn,这种情况下,我们可以在定义函数的时候给country设置一个默认参数,这样你在调用参数输入实参的时候,就不需要输入参数了,它会安装形参里定义的调用,当你不想按默认参数时,你按正常输入实参来输入你的参数即可。

1 def stu_register(name,age,course,country="CN"):

把函数的形参改成这样,你以后调用的时候不输入country这个实参,会默认给你传cn作为你的实参。

注意默认参数要写在位置参数后面

 

四、关键参数

调用函数输入实参的时候,必须按形参顺序来,如果不想按形参顺序来调用的话,就可以用关键参数,即指定参数名

还是上面的例子

1 stu_register("王山炮",course='PY', age=22,country='JP' )

可以这样调用,一定要写在位置参数后面。

 

五、非固定参数

 1 def stu_register(name,age,*args): # *args 会把多传入的参数变成一个元组形式
 2     print(name,age,args)
 3 
 4 stu_register("Alex",22)
 5 #输出
 6 #Alex 22 () #后面这个()就是args,只是因为没传值,所以为空
 7 
 8 stu_register("Jack",32,"CN","Python")
 9 #输出
10 # Jack 32 ('CN', 'Python')

当我们不知道实参会传入多少个值的时候,在定义形参的时候就可以使用非固定参数(在不确定的形参前面加个*) 这样子在调用函数输入实参的时候你输入完name,age后剩下对应的就是args,此时你输入多少个值都不会报错,因为他对应的形参时*args,你输入的值会变成一个元祖的形式传入,输出就会像上面是一个('CN','python')。

还有一点需要注意的:当我们传入实参的时候,如果这个实参本身就是一个列表或者元祖的时候,比如lis = ['CN','python'],当我们传参安装 jack,27,lis的话,函数会把lis当成一个整体作为元祖的一个元素输出(输出结果为:jack,27,(['CN','python'],)但是我们像要的是lis里的每一个值为元素,那该怎么办?

这里我们就需要在调用函数传参的时候,在实参里传入lis的前面也加上一个*这样就会把lis里每一个元素作为元祖里每一个元素输出

输出结果:jack,27,('CN'),('python')

还有个**kwargs

 1 def stu_register(name,age,*args,**kwargs): # *kwargs 会把多传入的参数变成一个dict形式
 2     print(name,age,args,kwargs)
 3 
 4 stu_register("Alex",22)
 5 #输出
 6 #Alex 22 () {}#后面这个{}就是kwargs,只是因为没传值,所以为空
 7 
 8 stu_register("Jack",32,"CN","Python",sex="Male",province="ShanDong")
 9 #输出
10 # Jack 32 ('CN', 'Python') {'province': 'ShanDong', 'sex': 'Male'}

**kwargs传参的时候需要安装字典的格式,key=valus 的形式去参数,这样输出的就是字典,道理和👆的一样,同样需要注意如果传参的本来就是个字典的话,在前面加上**即可。

 

六、返回值

函数外部的代码想要获取函数执行的结果,就可以在函数里用return语句把结果返回。

 1 def stu_register(name, age, course='PY' ,country='CN'):
 2     print("----注册学生信息------")
 3     print("姓名:", name)
 4     print("age:", age)
 5     print("国籍:", country)
 6     print("课程:", course)
 7     if age > 22:
 8         return False
 9     else:
10         return True
11 
12 registriation_status = stu_register("王山炮",22,course="PY全栈开发",country='JP')
13 
14 if registriation_status:
15     print("注册成功")
16 
17 else:
18     print("too old to be a student.")

需要我们注意的是:1、函数在执行过程中遇到return语句,就会停止执行过程并返回结果,函数遇到return就代表停止了函数。

           2、如果函数里没有指定return,那这个函数会返回None

           3、return只能返回一个值,如果你定义了返回多个值,它会以元祖的形式返回出来,定义列表也是返回一个列表。

 

七、全局与局部变量

全局变量:定义在函数外部的一级代码(没有缩进)的变量为全局变量,全局变量全局可用。

局部变量:定义在函数内部的变量为局部变量,只能在局部生效,函数一旦执行完毕,局部变量内存会清空,即调用不了,在函数内部可用调用外部即全局变量。

当全局和局部都有一个相同的变量时,函数查找变量的顺序是由内而外(也就是说先在内部找,找不到再去外部找),这里还有一点需要注意,当有多个相同的函数,也就是多个局部变量时,他们之间是不能互相调用的,所以函数查找变量的顺序还是先找自己,自己没有找全局变量。

八、作用域

一个函数就是一个作用域,函数一旦生成,作用域就成立

这里作用域没有细讲,结合上面的全局变量来说,当函数里想改变全局变量的时候需要用到global语法,后面跟需要修改的变量名。

这里需要注意一下,想字符串数字这种不变的全局变量必须global以后才能修改,但是像列表这种可变的(内部元素可用修改,因为其对应的内存地址)修改他其中的元素是不需要global的

九、嵌套函数

 1 name = "Alex"
 2 
 3 def change_name():
 4     name = "Alex2"
 5 
 6     def change_name2():
 7         name = "Alex3"
 8         print("第3层打印", name)
 9 
10     change_name2()  # 调用内层函数
11     print("第2层打印", name)
12 
13 
14 change_name()
15 print("最外层打印", name)

嵌套函数即函数里套着函数

嵌套函数这里需要注意的是,代码从上到下来执行,在遇到嵌套函数的时候只是把函数保存在内存里,没有调用,就不会执行函数。结合这两点,无论变量在哪个位置出现都可以分析出来

 

十、匿名函数

匿名函数就是不需要显示的指定函数名

1 #这段代码
2 def calc(x,y):
3     return x**y
4 
5 print(calc(2,5))
6 
7 #换成匿名函数
8 calc = lambda x,y:x**y
9 print(calc(2,5))

一般来说可以和后面的函数内置方法搭配的使用

1 res = map(lambda x:x**2,[1,5,7,4,8])
2 for i in res:
3     print(i)
4 
5 和map方法搭配使用

匿名函数的作业:节省代码量

 

十一、高阶函数

1 def add(x,y,f):
2     return f(x) + f(y)
3 
4 
5 res = add(3,-6,abs)
6 print(res)

高阶函数:接受一个或多个函数作为参数就是高阶函数

或者 return返回了另外一个函数也叫作高阶函数

 

十二、递归函数

一个函数在内部调用自身这个函数,那这个函数就是递归函数。

特性:

1、递归函数必须有一个限制条件(也就是有结束条件),不然它会无限循环,直到栈溢出。

2、每次进入一层递归是,你需要解决的问题相比上一次递归会有所减少,也就是值你的函数起到了作用,没起一次作用离你的目标就越近。

1 def calc(n):
2     v = int(n/2)
3     print(v)
4     if v > 0:
5         calc(v)
6     print(n)
7 
8 calc(10)

还有一点需要注意的是,每次递归遇到调用自己的函数就进入了一层递归,但是之前的函数还没执行完成,就会卡在那里,等到最后一次递归得到目标后,剩下的函数会继续走完。

 

十三、内置函数

1、abs()  #取绝对值

2、dict() #把数据转为字典

3、min() #取数据里最小值

1 a = [8,2,5,6,9,1]
2 min(a)
3 
4 >>>1   

4、max() #取数据里最大值

1 a = [8,2,5,6,9,1]
2 min(a)
3 
4 >>>9

5、help() #查看函数用法

6、bool() #判断数字是否为True,只有0会返回False,其他的都是返回True

7、all() # 判断数据列表里是否有0,数据里False就不会返回True,只有全部都是True才会返回True。 有0返回False,其他是True,包括空列表


8、any() #列表里只要有一个True,就会返回Ture

9、dir() #打印当前程序的所有变量

1 >>> dir()
2 ['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'goods']
3 
4 前面带__线的是系统变量,后面的是之前定义的变量

10、hex() #把数字转成16进制

1 >>> hex(13)
2 '0xd'
3 >>> hex(14)
4 '0xe'
5 >>> hex(1407)
6 '0x57f'
7 >>> 

11、divmod() #返回整除数和余数

1 >>> divmod(10,3)
2 (3, 1)
3 >>> divmod(16,6)
4 (2, 4)

12、sorted() #按顺序来排序

13、oct() #把10进制转换成8进制

14、bin() #转换成2进制

15、exec() #和eval()效果一样,区别在于eval只能转换单行代码,exec可以转换多行代码,但是exec拿不到返回值

16、ord()  和 chr()是相对于的 根据ascii码对应关系返回

1 >>> ord('a')
2 97
3 >>> chr(97)
4 'a'
5 >>> ord('b')
6 98
7 >>> chr(98)

17、sum() #将列表里所有数字求和

1 >>> a = [1,-5,6,3,8,9]
2 >>> sum(a)
3 22

18、bytearray()字符串是不能被修改的,使用这个函数可以在原内存地址上修改字符串而不是重新赋值

1 >>>s = 'abc路飞'
2 >>> s = s.encode()  #在使用bytearray前要先encode一下,转成bytes类型
3 >>> s
4 b'abc\xe8\xb7\xaf\xe9\xa3\x9e'
5 >>> s[0] =65
6 >>> s
7 bytearray(b'Abc\xe8\xb7\xaf\xe9\xa3\x9e')  #修改后的字符串
8 >>> s.decode()  # 再转换回来
9 'Abc路飞'  #可以看到原字符串的a改变成了A

用于大字符串修改的时候,就不会占内存

19、 map()

1 >>> list(map(lambda x:x*x,[1,2,3,4,5]))
2 [1, 4, 9, 16, 25]
3 >>> 
4 
5 map,让括号后面的按照前面的规则前执行,前面跟一个匿名函数,这个函数定义了x*x所有作用在后面这个列表里,返回一个每个元素相乘的列表

20、  filter()

1 >>> list(filter(lambda x:x>2,[1,2,3,4,5]))
2 [3, 4, 5]
3 
4 filter是过滤的意思,按照前面的匿名函数的规则把符合规则的都返回出来,过滤掉不符合规则的。

21、reduce()  python3中没有这个功能了,需要导入一个模块

1 >>> import functools
2 >>> functools.reduce(lambda x,y:x+y,[1,2,3,4,5])
3 15
4 >>> functools.reduce(lambda x,y:x*y,[1,2,3,4,5])
5 120
6 >>> 
7 
8 他也是按照匿名函数的规则去执行,不但可以两两相加还可以相乘

22、pow() #传入两个数字,返回第一个数字的第二个数字次的幂

1 >>> pow(5,2) #5的2次幂
2 25
3 >>> pow(3,3)  #3的3次幂
4 27
5 >>> 

23、print() 

>>> a = """
... 来试一试
... print
... 的
... """
>>> print(a )
来试一试
print
的
>>> print(a,end="*")

来试一试
print
的
*>>>   
    

# print默认会在最后给你加一个\n 也就是自动换行,打印完后就跳到下一行
#当里面声明end=''后 他最后会按你的指定来加上,而不是自动加上\n,也就不会自动换行


>>> print('crazy_heng','mengmeng')
crazy_heng mengmeng

>>> print('crazy_heng','mengmeng',sep='->')
crazy_heng->mengmeng

在打印多个字符串时,原本print会自动在中间加上空格,当你指定sep= 以后,print会按你指定的加上。

24、callable() #括号里加上数据类型如:函数或者列表。 判断括号里的数据能不能被调用,能调用返回Ture否则返回False

25、vars() #打印所有的变量名和变量值,和dir()的区别在于dir只打印变量名,vars打印变量名和变量值

26、locals()

 1 >>> def func():
 2 ...     n = 3
 3 ...     n1 =4
 4 ...     print(locals())
 5 ... 
 6 >>> 
 7 >>> func()
 8 {'n1': 4, 'n': 3}
 9 
10 locals 函数里的局部变量

27、zip()

1 >>> a = [1,2,3,4,5]
2 >>> b = ['a','b','c']
3 >>> list(zip(a,b))
4 [(1, 'a'), (2, 'b'), (3, 'c')]
5 
6 将两个列表一一对应,没有的丢弃

28、round()

1 >>> round(3.5453452)
2 4
3 >>> round(3.5453452,2)
4 3.55
5 >>> 
6 
7 
8 保留指定的几位小数,没有指定就四舍五入

29、set() 括号里输入列表,返回集合

 

3.4、函数进阶 

一、命名空间

有一个  x = 1 

这两个值都是存在内存里,x 这个变量名和 1的对应关系都存在名词空间里

 

名称空间共3种:

1 locals: 是函数内的名称空间,包括局部变量和形参  #打印当前所以环境的名称空间
2 globals: 全局变量,函数定义所在模块的名字空间
3 builtins: 内置模块的名字空间

 

作用域的查找顺序:LEGB

L:locals 是函数内的名字空间,包括局部变量和形参

E:enclosing 外部嵌套函数的名字空间

G:globals 全局变量,函数定义所在模块的名字空间

B:builtins 内置模块的名字空间

 

二、闭包

 1 def outer():
 2     name = 'alex'
 3 
 4     def inner():
 5         print("在inner里打印外层函数的变量",name)
 6 
 7     return inner
 8 
 9 
10 f = outer() 
11 
12 f()

在上面这种情况下,按正常情况下是函数执行完就会释放内容,里的的作用域就不存在了,但是当函数返回了一个它的内容函数,这个内部函数还使用了它外部函数的参数,相当于使用了外部函数的作用域,那无论何时我们调用函数,他的作用域都有用,没有被释放。这种现象就是闭包。

 

三、装饰器

 1 #_*_coding:utf-8_*_
 2 
 3 user_status = False #用户登录了就把这个改成True
 4 
 5 def login(func): #把要执行的模块从这里传进来
 6 
 7     def inner(*args,**kwargs):#再定义一层函数
 8         _username = "alex" #假装这是DB里存的用户信息
 9         _password = "abc!23" #假装这是DB里存的用户信息
10         global user_status
11 
12         if user_status == False:
13             username = input("user:")
14             password = input("pasword:")
15 
16             if username == _username and password == _password:
17                 print("welcome login....")
18                 user_status = True
19             else:
20                 print("wrong username or password!")
21 
22         if user_status == True:
23             func(*args,**kwargs) # 看这里看这里,只要验证通过了,就调用相应功能
24 
25     return inner #用户调用login时,只会返回inner的内存地址,下次再调用时加上()才会执行inner函数
26 
27 
28 def home():
29     print("---首页----")
30 
31 @login
32 def america():
33     #login() #执行前加上验证
34     print("----欧美专区----")
35 
36 def japan():
37     print("----日韩专区----")
38 
39 # @login
40 def henan(style):
41     '''
42     :param style: 喜欢看什么类型的,就传进来
43     :return:
44     '''
45     #login() #执行前加上验证
46     print("----河南专区----")
47 
48 home()
49 # america = login(america) #你在这里相当于把america这个函数替换了
50 henan = login(henan)
51 
52 # #那用户调用时依然写
53 america()
54 
55 henan("3p")

 

四、生成器&迭代器

函数里有yield  你在外部调用函数只会生出一个生成器,然后next()函数以后  yield会把每一次的执行结果返回给外面。 这样你就能拿到函数里每一步的执行结果

1、通过类时列表生成式的东西来生成(列表生成式 a = [i for i in range(10)]

2、可以通过函数里加上yield来生成

 

yield 

在函数里,遇到yield那这个函数就是生成器,当执行这个函数的时候,就生成了一个生成器,函数内部遇到yield就会停止,并向函数外部返回值,然后等待下一次next()调用。

调用:

执行函数后,next()加上生成器,就可以调用生成器,函数内部执行函数直到遇到yield,并向外面返回值,然后函数等待外部再次调用next()加函数,

send():

函数外部可以向函数发消息,直接用生成器.send(发送的内容) 这样函数内容可以接收信息。

 

迭代去:

可迭代对象(Iterable):可以用来for循环的对象,都是可迭代对象

isinstance()方法:可以利用这个方法判断是不是可迭代对象

迭代器:

可以被next()函数调用并不断返回下一个值的对象称为迭代器Iterator

生成器就是一种迭代器

总结:

凡事可以for循环的,都是Iterable类型;

凡事可以next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列

 

posted on 2018-05-10 22:24  killer-147  阅读(158)  评论(0编辑  收藏  举报