vicky777

python编程 基础入门学习笔记三

本节内容:

1.编解码

2.集合

3.文件

4.函数

5.局部变量\全局变量

6.练习

 

1.编解码                                                                                                                                                                    

  计算机只认识二进制编码,对于其他编码它并不认识。为了让计算机能够处理汉字、字母、数字等等字符,我们需要将字符转换成二进制表达(这个就是编码),交给计算机处理。再将计算机处理输出的二进制信息转换成字符(这就是解码)。所以,需要一种”字符与二进制的一对一映射关系“~

  在计算机发展早期,用英文字符基本可以搞定一切,所以产生了ASCII码:

  ASCII码,用32-127数值可以表示所有的字母和符号,小于32的数值表示非打印的控制字符。

  后来,随着计算机的普及,全世界都在使用,各国的字符都需要用计算机来存储和表示,中文也一样,从而产生了Unicode,也就是所谓的”万国码“:

  Unicode码,涵盖世界上所有字符到代码值的映射,如“A”的映射为U+0041,“中”的映射为U+2D2E。

  随着Unicode”万国码“的诞生,计算机如何来存储这个代码值的问题就出来了,于是就有了UTF-16的产生:

  UTF-16,直接将代码值中数值作为字符的二进制表示,这样每个字符基本都占用两个字节,如“中”,用“\x2D\x4E”表示了。

这么一弄,原本一个英文字符只要一个字节表示就可以,现在需要两个字节,所需存储资源无故多了一倍。所以有些国家还是继续使用ASCII,UTF-16就很尴尬了。为了解决这个问题,UTF-8产生了:

  UTF-8码,它能够使英文字符的编码与ASCII保持一致,而其它的字符则可能用更多字节表示。但是,以中文为例,中文的每个字符也无故多用了一个字节。所以我们也有了自己的编码格式,如GBK:

  GBK码,英文字母的编码格式与ASCII保持一致,中文字符采用两字节表示,正常情况下,我们的window系统默认存储格式都是按GBK。

   好了,介绍了这么多,还是来捋一捋他们之间的联系与区别吧:

  ASCII码:英文字符+特殊字符 ,每个字符只占一个字节(即8位)

  Unicode码:英文字符+中文字符,每个字符都占两个字节(即16位)

  UTF-8码:英文字符(按ASCII码,只占一个字节)+中文字符(占三个字节)

  GBK码:英文字符(按ASCII码,只占一个字节)+中文字符(占两个字节)

  他们之间又是如何相互转码的呢?

 

举个例子,

>>> s="a你好" 
>>> len(s)
3

>>> s_gbk=s.encode("gbk")#str转gbk码
>>> len(s_gbk)#gbk:中文占2个字符,英文占1个字符
5
>>> print(s_gbk)
b\'a\xc4\xe3\xba\xc3\'


>>> s_utf8=s.encode()#str转utf8码,encode()默认是转成utf8,但是实际使用建议都写成encode("utf-8")
>>> len(s_utf8)#utf-8:中文占3个字符,英文占1个字符
7
>>> print(s_utf8)
b\'a\xe4\xbd\xa0\xe5\xa5\xbd\'

>>> gbk_to_utf8=s_gbk.decode("gbk").encode("utf8")#gbk码转成utf8码,gbk先解码转成Unicode再编码转成utf8
>>> len(gbk_to_utf8)
7
>>> print(gbk_to_utf8)
b\'a\xe4\xbd\xa0\xe5\xa5\xbd\'


>>> type(s)#python3默认使用的是str类型对字符编码
<class \'str\'>
>>> type(s_utf8)
<class \'bytes\'>
>>> type(s_utf8)
<class \'bytes\'>
>>> type(gbk_to_utf8)
<class \'bytes\'>
View Code

Python3有两种表示字符序列的类型:bytes和str。

python3默认使用的是str类型对字符串编码,默认使用bytes操作二进制数据流,两者不能混淆!! !

python3中bytes用b’xxx’表示,其中的x可以用字符,也可以用ascii表示。

>>> s="世界,你好"
>>> print(s.encode("utf-8").decode("utf-8"))#编码utf-8,再解码utf-8,输出不变
世界,你好
>>> print(s.encode("utf-8").decode("utf-8").encode("gb2312"))#编码utf-8,再解码utf-8,最后编码转gb2312,最后输出gb2312编码
b\'\xca\xc0\xbd\xe7\xa3\xac\xc4\xe3\xba\xc3\'
>>> print(s.encode("utf-8").decode("utf-8").encode("gb2312").decode("gb2312"))#编码utf-8,再解码utf-8,然后编码转gb2312,最后解码gb2312,输出不变
世界,你好

至此,大家清楚了吗?现在思考一下,如果现在有一款日文的程序要在中国计算机上显示成中文,如何处理?

答案:日文编码先转Unicode再转GBK。

2.集合                                                                                                                                                                      

 集合就是我们数学学的集合,没有什么特殊的定义。集合最好的应用是去重。集合没有特殊的表示方法,而是通过一个set函数转换成集合。

>>> list_test=[1,4,5,7,\'c\',\'d\',\'b\',\'a\',\'d\']#这是一个列表
>>> set_test=set(list_test)#这是一个集合,集合是无序的,而列表是有序的
>>> print(list_test,set_test)
[1, 4, 5, 7, \'c\', \'d\', \'b\', \'a\', \'d\'] {1, 4, 5, \'b\', 7, \'d\', \'c\', \'a\'}

看到后面的集合打印出来,去除了重复的\'d\'字符,并且它的输出顺序也是与列表的输出不一样的。

下面主要做一些集合的关系测试:

1).交集

>>> set_one=set([1,4,5,7,\'c\',\'d\',\'b\',\'a\',\'d\'])
>>> set_two=set([4,3,1,2,\'f\',\'e\',\'a\',\'b\',\'c\'])
>>> set_one.intersection(set_two)
{1, \'c\', \'a\', 4, \'b\'}

intersection方法用来求两个集合的交集

>>> set_one&set_two
{1, \'c\', \'a\', 4, \'b\'}

也可以用符号&代替intersection

2).并集

>>> set_one.union(set_two)
{1, 2, 3, 4, 5, \'b\', 7, \'d\', \'e\', \'c\', \'a\', \'f\'}

union方法用来求两个集合的并集

>>> set_one|set_two
{1, 2, 3, 4, 5, \'b\', 7, \'d\', \'e\', \'c\', \'a\', \'f\'}

也可以用符号|代替union

3).差集

>>> set_one=set([1,4,5,7,\'c\',\'d\',\'b\',\'a\',\'d\'])
>>> set_two=set([4,3,1,2,\'f\',\'e\',\'a\',\'b\',\'c\'])
>>> set_one.difference(set_two)#in set_one but not in set_two
{\'d\', 5, 7}
>>> set_two.difference(set_one)#in set_two but not in set_one
{2, 3, \'e\', \'f\'}

difference方法求两个集合的差集

>>> set_one-set_two
{\'d\', 5, 7}
>>> set_two-set_one
{2, 3, \'e\', \'f\'}

也可以用符号-代替difference

4).子集

>>> set_one.issubset(set_two)
False
>>> set_one.issubset(set([4,5]))
False
>>> set([4,5]).issubset(set_one)
True

issubset方法是判断前面的集合是否被后面的集合包含,是则返回True,否则返回False

5).父集

>>> set_one.issuperset(set_two)
False
>>> set_one.issuperset(set([4,5]))
True

issuperset方法是判断前面的集合是否包含了后面的集合,是则返回True,否则返回False

6).对称差集

>>> set_one=set([1,4,5,7,\'c\',\'d\',\'b\',\'a\',\'d\'])
>>> set_two=set([4,3,1,2,\'f\',\'e\',\'a\',\'b\',\'c\'])
>>> set_two.symmetric_difference(set_one)
{2, 3, 5, 7, \'d\', \'e\', \'f\'}

等价于

>>> u=set_one.union(set_two)
>>> i=set_one.intersection(set_two)
>>> u-i
{2, 3, 5, 7, \'d\', \'e\', \'f\'}

7).判断是否有交集

>>> set_one.isdisjoint(set_two)
False
>>> set_one.isdisjoint(set([8]))
True

isdisjoint是判断两个集合是否有交集,没有交集返回True,有交集则返回False

8).集合的增删改

>>> set_one.add(999)#增加新的元素
>>> set_one
{1, 4, 5, \'b\', 7, 999, \'d\', \'c\', \'a\'}
>>> set_one.update([1,37,42])#更新集合元素,有则不更新,无则添加
>>> set_one
{1, 4, 5, \'b\', 7, 999, 37, \'d\', 42, \'c\', \'a\'}
>>> set_one.remove(37)#删除集合中的元素37
>>> set_one
{1, 4, 5, \'b\', 7, 999, \'d\', 42, \'c\', \'a\'}
>>> set_one.pop()#随机删
1
>>> set_one
{4, 5, \'b\', 7, 999, \'d\', 42, \'c\', \'a\'}
>>> print(set_one.discard(666))#删除时不管集合元素是否存在,都不会报错,而是返回None
None
>>> print(set_one.discard(999))
None
>>> set_one
{4, 5, \'b\', 7, \'d\', 42, \'c\', \'a\'}

3.文件                                                                                                                                                                       

 文件操作流程:

  打开文件,获得文件句柄并赋值给一个变量

  通过句柄对文件进行操作

  关闭文件

1).文件的读

>>> data=open("test.txt").read()
>>> print(data)
Hello World!
>>> f=open("test.txt",\'r\')#规范的写法是加上文件打开的模式,r是读模式,默认也是读模式
>>> print(f.read())
Hello World!

’r‘读模式只能读,不能写

2).文件的写

>>> f=open("test.txt",\'w\')#文件句柄
>>> f.write("你好,世界!")
6
>>> print(f.read())
Traceback (most recent call last):
  File "<pyshell#377>", line 1, in <module>
    print(f.read())
io.UnsupportedOperation: not readable

’w‘写模式只能写,不能读;并且’w‘写模式会覆盖之前已有内容。

>>> f=open("test.txt",\'r\')
>>> print(f.read())
你好,世界!

”Hello World!“ 被 ”你好,世界!“覆盖了

3).文件的追加

>>> f=open("test.txt",\'a\')
>>> f.write("Hello,world!")
12
>>> print(f.read())
Traceback (most recent call last):
  File "<pyshell#382>", line 1, in <module>
    print(f.read())
io.UnsupportedOperation: not readable
>>> f=open("test.txt",\'r\')
>>> print(f.read())
你好,世界!Hello,world!

’a‘追加模式,只能追加写,不能读;”Hello World!“ 直接追加写在 ”你好,世界!“后面

4).循环取行数据

1    3564547    西部数据(WD)New My Passport 4TB 2.5英寸 经典黑 移动硬盘 
2    3564513    西部数据(WD)New My Passport 4TB 2.5英寸 闪耀白 移动硬盘 
3    3564527    西部数据(WD)New My Passport 4TB 2.5英寸 中国红 移动硬盘
4    3995534    西部数据(WD)New My Passport 4TB 2.5英寸 贵族蓝 移动硬盘 
5    3564429    西部数据(WD)New My Passport 4TB 2.5英寸 清新黄 移动硬盘 
6    3564471    西部数据(WD)New My Passport 4TB 2.5英寸 活力橙 移动硬盘 
7    4068030    希捷(Seagate)2.5英寸 Backup Plus 新睿品 5T USB3.0 便携式移动硬盘 黑色版
8    2344160    希捷(Seagate)2.5英寸 Backup Plus 新睿品 4T USB3.0 便携式移动硬盘 银色版
9    1788793    希捷(Seagate)2.5英寸 Backup Plus新睿品2TB USB3.0便携式移动硬盘 金色版
10    1429774    希捷(seagate)Expansion 新睿翼1TB 2.5英寸 USB3.0 移动硬盘
11    1000431    希捷(Seagate) Backup Plus睿品(升级版)1T 2.5英寸 USB3.0移动硬盘 丝绸红
filelist.txt
>>> f=open("filelist.txt",\'r\')
>>> print(f.readlines())
[\'1\t3564547\t西部数据(WD)New My Passport 4TB 2.5英寸 经典黑 移动硬盘 \n\', \'2\t3564513\t西部数据(WD)New My Passport 4TB 2.5英寸 闪耀白 移动硬盘 \n\', \'3\t3564527\t西部数据(WD)New My Passport 4TB 2.5英寸 中国红 移动硬盘\n\', \'4\t3995534\t西部数据(WD)New My Passport 4TB 2.5英寸 贵族蓝 移动硬盘 \n\', \'5\t3564429\t西部数据(WD)New My Passport 4TB 2.5英寸 清新黄 移动硬盘 \n\', \'6\t3564471\t西部数据(WD)New My Passport 4TB 2.5英寸 活力橙 移动硬盘 \n\', \'7\t4068030\t希捷(Seagate)2.5英寸 Backup Plus 新睿品 5T USB3.0 便携式移动硬盘 黑色版\n\', \'8\t2344160\t希捷(Seagate)2.5英寸 Backup Plus 新睿品 4T USB3.0 便携式移动硬盘 银色版\n\', \'9\t1788793\t希捷(Seagate)2.5英寸 Backup Plus新睿品2TB USB3.0便携式移动硬盘 金色版\n\', \'10\t1429774\t希捷(seagate)Expansion 新睿翼1TB 2.5英寸 USB3.0 移动硬盘\n\', \'11\t1000431\t希捷(Seagate) Backup Plus睿品(升级版)1T 2.5英寸 USB3.0移动硬盘 丝绸红\n\']

readlines()是将文件内容以换行符作为分割符,将内容存成列表的形式

现在有个需求:读filelist.txt,但是要跳过第5行,输出其他行,具体代码如下:

>>> f=open("filelist.txt",\'r\')
>>> for index,line in enumerate(f.readlines()):
    if index==4:
        print("---跳过第5行---\n")
        continue
    print(line)

    
1    3564547    西部数据(WD)New My Passport 4TB 2.5英寸 经典黑 移动硬盘 

2    3564513    西部数据(WD)New My Passport 4TB 2.5英寸 闪耀白 移动硬盘 

3    3564527    西部数据(WD)New My Passport 4TB 2.5英寸 中国红 移动硬盘

4    3995534    西部数据(WD)New My Passport 4TB 2.5英寸 贵族蓝 移动硬盘 

---跳过第5行---

6    3564471    西部数据(WD)New My Passport 4TB 2.5英寸 活力橙 移动硬盘 

7    4068030    希捷(Seagate)2.5英寸 Backup Plus 新睿品 5T USB3.0 便携式移动硬盘 黑色版

8    2344160    希捷(Seagate)2.5英寸 Backup Plus 新睿品 4T USB3.0 便携式移动硬盘 银色版

9    1788793    希捷(Seagate)2.5英寸 Backup Plus新睿品2TB USB3.0便携式移动硬盘 金色版

10    1429774    希捷(seagate)Expansion 新睿翼1TB 2.5英寸 USB3.0 移动硬盘

11    1000431    希捷(Seagate) Backup Plus睿品(升级版)1T 2.5英寸 USB3.0移动硬盘 丝绸红
View Code

这段代码虽然可以实现”跳过第5行,输出其他行“的需求,但是前提条件是先要把整个文件内容存入列表,非常占用内存,是一种低效的循环

下面介绍一种高效的方法:

>>> f=open("filelist.txt",\'r\')
>>> count=0
>>> for line in f:
    if count==4:
        print("---跳过第5行---\n")
        count+=1
        continue
    print(line)
    count+=1

    
1    3564547    西部数据(WD)New My Passport 4TB 2.5英寸 经典黑 移动硬盘 

2    3564513    西部数据(WD)New My Passport 4TB 2.5英寸 闪耀白 移动硬盘 

3    3564527    西部数据(WD)New My Passport 4TB 2.5英寸 中国红 移动硬盘

4    3995534    西部数据(WD)New My Passport 4TB 2.5英寸 贵族蓝 移动硬盘 

---跳过第5行---

6    3564471    西部数据(WD)New My Passport 4TB 2.5英寸 活力橙 移动硬盘 

7    4068030    希捷(Seagate)2.5英寸 Backup Plus 新睿品 5T USB3.0 便携式移动硬盘 黑色版

8    2344160    希捷(Seagate)2.5英寸 Backup Plus 新睿品 4T USB3.0 便携式移动硬盘 银色版

9    1788793    希捷(Seagate)2.5英寸 Backup Plus新睿品2TB USB3.0便携式移动硬盘 金色版

10    1429774    希捷(seagate)Expansion 新睿翼1TB 2.5英寸 USB3.0 移动硬盘

11    1000431    希捷(Seagate) Backup Plus睿品(升级版)1T 2.5英寸 USB3.0移动硬盘 丝绸红
View Code

这种方法,是利用迭代器(在后面会详细介绍)的方法,一行一行的读,需要哪一行及读一行,始终是占用一行的内存

5).文件的修改

f=open("filelist.txt",\'r\')
>>> f_new=open("filelist_bak.txt",\'w\')
>>> for line in f:
    if "3564527" in line:
        line=line.replace("3564527","3564527+")
    f_new.write(line)
>>> f.close()
>>> f_new.close()
>>> f_new=open("filelist_bak.txt",\'r\')
>>> print(f_new.read())
1    3564547    西部数据(WD)New My Passport 4TB 2.5英寸 经典黑 移动硬盘 
2    3564513    西部数据(WD)New My Passport 4TB 2.5英寸 闪耀白 移动硬盘 
3    3564527+    西部数据(WD)New My Passport 4TB 2.5英寸 中国红 移动硬盘
4    3995534    西部数据(WD)New My Passport 4TB 2.5英寸 贵族蓝 移动硬盘 
5    3564429    西部数据(WD)New My Passport 4TB 2.5英寸 清新黄 移动硬盘 
6    3564471    西部数据(WD)New My Passport 4TB 2.5英寸 活力橙 移动硬盘 
7    4068030    希捷(Seagate)2.5英寸 Backup Plus 新睿品 5T USB3.0 便携式移动硬盘 黑色版
8    2344160    希捷(Seagate)2.5英寸 Backup Plus 新睿品 4T USB3.0 便携式移动硬盘 银色版
9    1788793    希捷(Seagate)2.5英寸 Backup Plus新睿品2TB USB3.0便携式移动硬盘 金色版
10    1429774    希捷(seagate)Expansion 新睿翼1TB 2.5英寸 USB3.0 移动硬盘
11    1000431    希捷(Seagate) Backup Plus睿品(升级版)1T 2.5英寸 USB3.0移动硬盘 丝绸红
View Code

6).文件操作的其他方法

>>> f.tell()#查看光标的当前位置
829
>>> f.seek(0)#光标回到起点
0
>>> f.readline()
\'1\t3564547\t西部数据(WD)New My Passport 4TB 2.5英寸 经典黑 移动硬盘 \n\'
>>> f.tell()#查看光标的当前位置,70是指光标所在位置为第70个字符处
70
f=open("filelist.txt",\'a\')
print(f.flush())#强制刷新,写一行刷一行
f.truncate(10)#从头开始截断10个字符

f=open("filelist.txt",\'r+\')#文件句柄,读写
f=open("filelist.txt",\'w+\')#文件句柄,写读,不常用
f=open("filelist.txt",\'a+\')#文件句柄,追加读写
f=open("filelist.txt",\'wb\')#文件句柄,二进制文件rb,wb,ab网络传输时会用到二进制
f.write("hello binary\n".encode())#以二进制形式写入
f.close()#文件句柄关闭
import sys,time

for i in range(50):
    sys.stdout.write("#")
    sys.stdout.flush()#强制刷新,写一行刷一行
    time.sleep(0.1)
动态进度条

体验一下吧!

4.函数                                                                                                                                                                       

 函数分为:内置函数和自定义函数。

内置函数,是系统自带的函数可以直接调用;自定义函数是用户自己定义的函数,是这里重点讲解的内容。

>>> def func1():
    \'\'\'第一个函数\'\'\'
    print("in the func1")
    return 0
>>> def func2():
    \'\'\'这是一个过程\'\'\'
    print("in the func2")
>>> x=func1()
in the func1
>>> y=func2()
in the func2

#过程就是没有返回值的函数
#在python中过程也隐式的给了返回值"None"
#即python中过程和函数的区别没有严格的界限

为什么要自定义函数?

举个例子,已知有三个函数

def test1():
    print(\'in the test1\')

def test2():
    print(\'in the test2\')

def test3():
    print(\'in the test3\')

test1()
test2()
test3()
View Code

现在需要添加代码获取每个函数运行的当前时间,在不使用函数的情况下:

import time

def test1():
    print(\'in the test1\')
    time_format=\'%Y-%m-%d %X\'
    time_current=time.strftime(time_format)
    print(\'%s end action\n\' %time_current)

def test2():
    print(\'in the test2\')
    time_format=\'%Y-%m-%d %X\'
    time_current=time.strftime(time_format)
    print(\'%s end action\n\' %time_current)

def test3():
    print(\'in the test3\')
    time_format=\'%Y-%m-%d %X\'
    time_current=time.strftime(time_format)
    print(\'%s end action\n\' %time_current)

test1()
test2()
test3()
View Code

加入自定义函数logger()的情况下:

import time
def logger():
    time_format=\'%Y-%m-%d %X\'
    time_current=time.strftime(time_format)
    print(\'%s end action\n\' %time_current)
    with open(\'a.txt\',\'a+\') as f:
        f.write(\'%s end action\n\' %time_current)

def test1():
    print(\'in the test1\')
    logger()

def test2():
    print(\'in the test2\')
    logger()

def test3():
    print(\'in the test3\')
    logger()

test1()
test2()
test3()
View Code

可见,函数的作用:1.代码重用 2.保持数据的一致性 3.可扩展

1).函数的返回值

def test1():
    print("in the test1")

def test2():
    print("in the test2")
    return 1

def test3():
    print("in the test3")
    return 1,\'hello\',[\'Rose\',\'Jack\'],{\'name\':\'Rose\'}

x=test1()
print(x)
y=test2()
print(y)
z=test3()
print(z)
View Code

代码执行结果:

in the test1
None
in the test2
1
in the test3
(1, \'hello\', [\'Rose\', \'Jack\'], {\'name\': \'Rose\'})

函数的返回值按照数目可以分为:

  返回值的数目=0:None(当没有定义返回值时,默然返回None)
  返回值的数目=1:object
  返回值的数目>1:tuple(当定义返回值大于1个时,返回值以元组的形式返回)

2).函数的参数

首先需要了解形参实参

#x,y为形参,1,2为实参
def test(x,y):
    print(x)
    print(y)

test(1,2)

了解了实参和形参后,我们来看看位置参数关键字参数

以test函数为例,test(1,2)就属于位置参数调用,位置参数调用顺序必须与形参位置一一对应

a=1#定义了一个内存对象
b=2#定义了一个内存对象
test(x=a,y=b)
test(x=1,y=2)
test(y=2,x=1)

test(x=a,y=b),test(x=1,y=2),test(y=2,x=1)均属于关键字调用,关键字调用与形参数据顺序无关

test(1,y=2)

还有一种情况,既有位置参数调用又有关键字参数调用,既有关键字调用,又有位置参数调用,会按照位置参数调用规则执行

注意:关键字调用是不能写在位置参数前面的如test(x=1,2)是会出错的,另外test(2,x=1)也是会出错的,请自行思考原因

下面来认识下什么是默认参数,默认参数的特点是:调用函数时,默认参数非必须传递

def test(x,y,z=2):
    print(x,y,z)
    
test(1,2) #z不传参数时,默认值就是2
test(1,2,3)#如果不想使用默认参数z的值,也可以自行赋值

代码执行结果:
1 2 2
1 2 3
View Code

那么如果现在不确定具体使用时需要定义几个参数,该怎么办呢?那就使用参数组吧!

def test1(*args):
    print(args)

test1(1,2,3,4,5,6)
test1(*[1,2,3,4,5])# args=tuple([1,2,3,4,5]),元组的形式

def test2(x,*args):
    print(x,args)

test2(1,2,3,4,5,6,7)

代码执行结果:
(1, 2, 3, 4, 5, 6)
(1, 2, 3, 4, 5)
1 (2, 3, 4, 5, 6, 7)
View Code

参数组,在不确定参数数目时使用,*args:接受N个位置参数,转换成元组的方式

def test3(**kwargs):
    print(kwargs)

test3(name=\'rose\',age=8,sex=\'M\')
test3(**{\'name\':\'rose\',\'age\':8})

代码执行结果:
{\'sex\': \'M\', \'age\': 8, \'name\': \'rose\'}
{\'name\': \'rose\', \'age\': 8}
View Code

**kwargs:把N个关键字参数,转换成字典的方式

def test4(name,**kwargs):
    print(name)
    print(kwargs)

test4(\'Jack\',age=18,sex=\'M\')

代码执行结果:
Jack
{\'sex\': \'M\', \'age\': 18}
View Code

加入位置参数,位置参数必须放在参数组前面

def test5(name,age=18,**kwargs):
    print(name)
    print(age)
    print(kwargs)

test5(\'Jack\',sex=\'M\',hobby=\'tesla\')

代码执行结果:
Jack
18
{\'sex\': \'M\', \'hobby\': \'tesla\'}
View Code

加入默认参数,必须将参数组放在最后

 1 def test6(name,age=18,*args,**kwargs):
 2     print(\'name:\',name)
 3     print(\'age:\',age)
 4     print("args:",args)
 5     print("kwargs:",kwargs)
 6 
 7 test6(\'Tom\',age=34,sex=\'M\',hobby=\'tesla\')
 8 print("分割线".center(50,\'-\'))
 9 myList=[1,2,3]
10 myDict={"name":"Lucy","age":19}
11 test6("Jack",myList,myDict)
12 print("分割线".center(50,\'-\'))
13 test6("Rose",19,1,2,3,a=100)
14 #print("分割线".center(50,\'-\'))
15 #test6(name="David",age=25,*myList,**myDict)#在python3.x中会出错,原因需要再查证
16 
17 def test7(*args,**kwargs):
18     print("args:",args)
19     print("kwargs:",kwargs)
20 
21 print("分割线".center(50,\'-\'))
22 myList=[1,2,3]
23 myDict={"name":"Lucy","age":19}
24 
25 test7(*myList,**myDict)
26 
27 代码执行结果:
28 name: Tom
29 age: 34
30 args: ()
31 kwargs: {\'hobby\': \'tesla\', \'sex\': \'M\'}
32 -----------------------分割线------------------------
33 name: Jack
34 age: [1, 2, 3]
35 args: ({\'name\': \'Lucy\', \'age\': 19},)
36 kwargs: {}
37 -----------------------分割线------------------------
38 name: Rose
39 age: 19
40 args: (1, 2, 3)
41 kwargs: {\'a\': 100}
42 -----------------------分割线------------------------
43 args: (1, 2, 3)
44 kwargs: {\'name\': \'Lucy\', \'age\': 19}
View Code

第7行,关键字参数sex=\'M\',hobby=\'tesla\',因为函数test6(name,age=18,*args,**kwargs)中没有rt参数,所以最后归到字典参数中。

第11行,元组对象前面如果不带“*”、字典对象如果前面不带“**”,则作为普通的对象传递参数。多余的普通参数,在test6("Jack",myList,myDict)中,"Jack"赋给参数name,myList赋给参数age,多余的参数myDict默认为元组赋给myList。

第13行,"Rose"是位置参数赋值给name,19也是位置参数赋值给age,1,2,3作为元组赋值给args,a=100是关键字参数,但是函数test6(name,age=18,*args,**kwargs)中没有rt参数,所以最后归到字典参数中。

第15行,在python3.x中会出错,原因需要再查证

第25行,参数中如果使用“*”元组参数或者“**”字典参数,这两种参数应该放在参数列表最后。并且“*”元组参数位于“**”字典参数之前。

3).递归函数

递归函数:自己调用自己,最大可调用999次

使用递归函数的条件:
 明确的结束条件
 问题规模每递归一次都应该比上一次的问题规模有所减少
 效率低

\'\'\'定义一个函数,判断一个数是否能被2除完,能返回True\'\'\'
def calc(n):
    h=int(n/2)
    if h>=2:
        calc(h)
        print("%d是大于2的整数" %h)

calc(9)
View Code

先简单认识下,在具体应用中请自行思考

4).高阶函数

参数是函数,返回值也是函数

易于可读性,方便代码维护,隔离作用域;函数是一等对象

在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数:
接受一个或多个函数作为输入
输出一个函数

def add(a,b,f):
    return f(a)+f(b)

res=add(3,-6,abs)#函数名也是变量,变量f现在已经指向abs函数本身
print(res)

代码执行结果:
9

讲两个经典的函数:map和reduce

>>> def foo(x):
    return x*x

>>> map(foo,[1,2,3,4,5])
>>> for i in iter:
    print(i)

    
1
4
9
16
25
View Code

map()函数接收两个参数,一个是函数,一个是序列,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回。

reduce()把一个函数作用在一个序列[x1, x2, x3…]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算(在Python 3里,reduce()函数已经被从全局名字空间里移除了,它现在被放置在functools模块里,用的话要先引入from functools import reduce),其效果就是:

>>> from functools import reduce
>>> def add(x,y):
    return x+y

>>> reduce(add,[1,2,3,4,5])
15
View Code

5.局部变量\全局变量                                                                                                                                                

#-*- coding:utf-8 -*-
#Author:\'Yang\'

school="Oxford.edu" #全局变量

def change(name):
    school="Music"
    print("before change:",name)
    name=\'露丝\' #局部变量,该函数就是这个变量的作用域
    print("after change:",name)

print(\'调用change前,全局变量school:\',school)
name=\'Lucy\'
change(name)
print(\'局部变量:\',name)
print(\'调用change后,全局变量school:\',school)

代码执行结果:
调用change前,全局变量school: Oxford.edu
before change: Lucy
after change: 露丝
局部变量: Lucy
调用change后,全局变量school: Oxford.edu
View Code

局部变量的作用域只在函数体内,在函数外失效,所以局部变量的值在函数为无法被修改,这就是为什么change(name)函数执行后,局部变量name的值仍然是"Lucy"

全局变量的作用域是整个程序,在整个程序内,全局变量值均有效,当school变量出现在函数内时是属于局部变量,所以在change(name)函数执行后,局部变量school的值仍然是"Oxford.edu"

还有一种方法必须提一下,就是在函数内如何定义一个全局变量,用关键字global,虽然不提倡这么使用,但还是有必要了解一下:

#-*- coding:utf-8 -*-
#Author:\'Yang\'

school="Oxford.edu"#全局变量

def change(name):
    global school#用global指定为全局变量
    school="Music"
    print("before change:",name)
    name=\'露丝\' #局部变量,该函数就是这个变量的作用域
    print("after change:",name)

print(\'调用change前,全局变量school:\',school)
name=\'Lucy\'
change(name)
print(\'局部变量:\',name)
print(\'定义global,调用change后,全局变量school:\',school)

代码执行结果:
调用change前,全局变量school: Oxford.edu
before change: Lucy
after change: 露丝
局部变量: Lucy
定义global,调用change后,全局变量school: Music
View Code

当在change(name)函数内的school变量赋值前,加一句"global school",那么函数内的school变量即变为全局变量,所以在change(name)函数执行后,全局变量school的值变成是"Music"

6.练习                                                                                                                                                                      

程序1: 实现简单的shell sed替换功能

程序2:修改haproxy配置文件 

1、查
    输入:www.oldboy.org
    获取当前backend下的所有记录

2、新建
    输入:
        arg = {
            \'backend\': \'www.oldboy.org\',
            \'record\':{
                \'server\': \'100.1.7.9\',
                \'weight\': 20,
                \'maxconn\': 3000
            }
        }

3、删除
    输入:
        arg = {
            \'backend\': \'www.oldboy.org\',
            \'record\':{
                \'server\': \'100.1.7.9\',
                \'weight\': 20,
                \'maxconn\': 3000
            }
        }
需求
global       
        log 127.0.0.1 local2
        daemon
        maxconn 256
        log 127.0.0.1 local2 info
defaults
        log global
        mode http
        timeout connect 5000ms
        timeout client 50000ms
        timeout server 50000ms
        option  dontlognull

listen stats :8888
        stats enable
        stats uri       /admin
        stats auth      admin:1234

frontend oldboy.org
        bind 0.0.0.0:80
        option httplog
        option httpclose
        option  forwardfor
        log global
        acl www hdr_reg(host) -i www.oldboy.org
        use_backend www.oldboy.org if www

backend www.oldboy.org
        server 100.1.7.9 100.1.7.9 weight 20 maxconn 3000
原配置文件

分类:

技术点:

相关文章: