什么是函数?

把一堆代码放一起就叫函数

函数用来干什么?

不复写代码,提高代码重复利用程度

怎么定义以及调用函数:

def fun1():    #定义函数
print('这是一个函数') #函数体,里面什么都不想实现就写个 pass
fun1() #调用:函数名加括号,如果里面有参数必填的就得填

参数

参数分两种,形参和实参

形参:形式参数,函数内使用的参数

实参:实际参数,传到函数内的参数值

def calc(a,b):#形参,形式参数
print(a,b)
return a+b #返回值 result = calc(1,2) #实参,实际参数

返回值

返回值的作用是返回函数处理的结果,并且,函数遇见 return 则立即结束,也就是 return 后的下一行代码,是不会执行的

def calc(a,b):#形参,形式参数
print(a,b)
return a+b #返回值 result = calc(1,2) #实参,实际参数

小练习1:判断输入的值,是否为小数:

思路:

  1. 判断是否只有一个小数点
  2. 小数点左边的是一个整数,小数点右边的也是一个整数
  3. 小数点右边的也是一个整数,左边要以负号开头,只有一个负号,负号后面是整数
num = input('请输入价格:')
def check_float(num):
num = str(num)
if num.count('.')==1:
left,right = num.split('.')
if left.isdigit() and right.isdigit():
return True
elif left.startswith('-') and left[1:].isdigit() and right.isdigit():
return True
return False
check_float(num)

小练习2:函数定义文件读写,格式为 json 格式

import json
def write_file(d,file):
with open(file,'w',encoding='utf-8') as fw:
json.dump(d,fw,indent=4,ensure_ascii=False) def read_file(file):
with open(file,encoding='utf-8') as fw:
return json.load(fw)

返回值有多个

有种情况是,我们函数处理完,需要返回多个值,怎么办呢?

def get_file(age,name,addr):
age+=5
name = 'szz_'+name
addr = 'bejing_'+addr
return age,name,addr

直接 return 就好了,用逗号隔开就成,返回的结果是一个元组的形式

(24, 'szz_小黑', 'bejing_天通苑')

那么这几个返回值如何取用呢?

age,name,addr = get_file(19,'小黑','天通苑')

这样的话,我们的 age 就等于函数返回的 age,name 就是函数返回的 name ,addr 就是函数返回的 addr。

如果拿 1 个变量来接收,那么该变量当然就会是这个元组

变量

变量分为局部变量和全局变量,那么这两者有什么区别呢?

简单理解为全局变量是所有的函数都能用,局部变量只能给自己本身函数内部使用,假设函数内用的变量在函数体内找不到,那么它就会去全局变量内找,找不到就会报语法错误。

全局变量不在函数体内定义,局部变量在函数体内定义。

一般来讲,全局变量放在最上边

name = 'abc'
def fun1():
name = 'abc2'
return name
print('全局变量:%s'%name)
print('局部变量:%s'%fun1()) 结果:
全局变量:abc
局部变量:abc2

那么,假设我在函数内不单单是想取用这个全局变量值,而且想对其进行修改,要怎么办呢?那就要在函数体内声明一个全局变量,具体如下:

money = 0

def dsk():
global money
money+=500 def ldd():
global money
money -= 1000 print('money之前的',money)
dsk()
print('挣钱之后的',money)
ldd()
print('花钱之后的',money) 结果:
money之前的 0
挣钱之后的 500
花钱之后的 -500

但是这种方式尽量少用,为什么呢?因为假设外面定义了一个全局变量,在程序内部修改了我这个全局变量的值,很难找到出错的根源

那么我们用几个例子来理解一下,全局变量以及局部变量

money = 500

def test(consume):
return money - consume def test1(money):
return test(money) + money money = test1(money) print(money)

结果是怎样呢?应该为 500

过程:最后 print(money) money 来自于 test1(money) ,看 test1 内,返回的是 test(money)+money ,money 在这个函数内找不到,那么用全局变量 500 ,所以 test(500)+500;再去看 test(500),test(500) 返回的是money - consume = 500 - 500 = 0;所以最终值为 0+500 = 500

2、

def test():
global a
a = 5 def test1():
c = a + 5
return c #test()
res = test1()
print(res) 

结果:NameError: name 'a' is not defined

为什么呢?因为 res = test1(),调用 test1 函数, c = a+5 ,a 在函数未定义,且全局变量内找不到,因为 test() 函数未调用。global a a=5 并未生效,所以一定会报错。

那么假设在 print 之前,调用下 test(),就有结果了,结果为:10

那么是不是所有的变量,我们在函数内要修改,都要进行全局变量声明呢?答案是 no!可以根据下标啥的修改的,就可以在函数内修改,其他的不行

可变类型:dict、list、set :字典,列表,集合可以直接修改的就不需要全局变量声明,直接在函数内修改就行

不可类型:int、str、tuple:数字,字符串,元组就必须要全局变量声明,才能够修改

例如:

stus = ['xiaojun','xiaohei','xiaobai']
stu_info = {
'name':'xiaojun',
'age':19
} stus2 = {'xiaohei','xiaobai'}
def add_stu():
name = input('name:')
age = input('age:')
# stus.append(name)
stu_info[name]=age def select_stu():
name = input('name:')
print('你的学号是%s'%stus.index(name))

默认参数&参数组

上面我们讲过,函数的参数。函数的参数可以有,也可以没有:

def say_hello():
print(word)

1、必填参数/位置参数

那么有参数的情况是怎样的呢?我们假定有个函数,参数传入什么,就打印什么

def say_hello(word='hello'):
print(word)
say_hello(123)

结果:

123

2、默认值参数

参数有个默认值就叫做默认值参数,看下面 word 在函数定义括号内,传入了一个默认值 'hello'

def say_hello(word='hello'):
print(word)
say_hello(123)
say_hello()

结果:

123
hello

上面,我们看到,在函数定义的括号内,加入了 word='hello' ,那么这个参数就叫做默认参数,假设调用函数内,不传值,就会使用默认值,但是传新值该参数就是用新值进行使用

那么默认值参数有什么用呢?定义了两个参数,一个叫 file ,是文件名,content 是默认值参数,也就是输入的内容,实现一个函数内进行文件读写操作,假设 content 不传内容,就执行读文件操作;传新值的话就写入到文件内:

def op_file(file,content=None):
import json
if content:
with open(file,'w',encoding='utf-8') as f:
json.dump(content, f)
else:
with open(file,encoding='utf-8') as f:
return json.load(f)

不明显的话,看下面的更直观:

def op_file2(file,content='没有传文件内容'):
if content=='没有传文件内容':
with open(file,encoding='utf-8') as f:
result = f.read()
return result
else:
with open(file,'w',encoding='utf-8') as f:
f.write(content)

但是,这个还是需要完善的,因为可以校验文件名为不为空的情况,想写的可以继续写

3、参数组

假设我们自动化程序,写了一个函数,实现了发邮件功能,一开始的测试只有我们一个,那么我们就传一个人进去,name1,但是随着测试团队的壮大,这个邮件要发的人越来越多,那么就得加 name,而且如果有 100 人,就得在函数定义内加 100 个参数,未免有点太笨拙,咋办呢?

def send_mail(name1,name2,name3):
print('给%s'%name1,name2,name3) send_mail('abc','def','igh')

这时候就是我们参数组大显身手的时候了,我们可以将 name 这个参数定义为一个参数组,里面的具体 name 数目不详,这样就不用每次都去手动添加这个 name 参数你,那么怎么实现呢?

用 *args 表示(*args 并不是固定写法,只是约定如此,也可以定义为其他的,比如 *names)

def send_mail(*args):
print(args) send_mail()
send_mail('abc')
send_mail([1,2,3],'bcd','efg')

结果:

()
('abc',)
([1, 2, 3], 'bcd', 'efg')

从上述结果我们不难看出,参数组为 *args 的写法,是传入了一个元组。而且 *args 可以为空,不会报错。

那么,上面的函数没写规范,既然传进来的是个元组,循环取值发送就 ok:

def send_mail(*args):
for name in args:
print('给 %s 发邮件'%name)

4、关键字参数

这里先插一嘴,假设处理测试人员信息的函数,用位置参数:

def info(name,age,sex,addr,phone,qq,mail):
print(name,age,sex,addr,phone,qq,mail)
info('xiaohei',18,'man','guanzhou',110,139,'123@163.com')

这样的话很容易出问题的是,假设 age 我们传了一个 'women' ,那就完全错误了,很难对应起来。

那么我们可以怎么避免这种不对应的情况呢?

可以在调用的时候,指定关键字传什么,比如 addr = '北京',这样的话,就不需要一一对应,这就叫关键字传参

def szz(name,age,sex,addr,phone,qq,mail):
print(name,age,sex) szz(addr='北京',qq=1110,mail='abcc@163.com',name='abc',phone=11111,sex='dsdfs',age=11)

但是也可以位置参数和关键字参数混用:

def szz(name,age,sex,addr,phone,qq,mail):
print(name,age,sex) info('xiaohei',18,addr='beijing',phone=186,mail='aaa@163.com',sex='男',qq='')

可以看到,前两个我们用的是位置参数,传的是 'xiaohei'  和 18,后面所有的用的都是关键字参数,但是要注意:关键字参数和位置参数不能交叉使用,因为很难对应:

info('xiaohei',addr='beijing',18,phone=186,mail='aaa@163.com',sex='男',qq='')

看一下,第一个我们使用关键字参数,给了 name ,然而第二个是关键字参数,我们是能对应上,后面又来了了个未知参数 18 ,没法对应上,所以混用的方式只能是:位置参数+关键字参数,用了一个关键字参数,后面的全部都得用关键字参数,否则会报语法错误:SyntaxError: positional argument follows keyword argument

所以:

  1. 调用的函数的时候,可以全部都用位置参数,位置是一一对应的,必须按照位置来传参
  2. 也可以全部都用关键字参数,指定关键字,不需要按照顺序来
  3. 也可以一起用,但是要先写位置参数,再写关键字参数,关键字参数后面不能再出现位置参数

关键字参数有种更牛批的方式,还是上面的例子:

def xiaohei(**info):
print(info)
xiaohei()
xiaohei(1,2,3)
xiaohei(name='小黑',addr='北京')
xiaohei(file_name='a.json',mode='w',conent='abcc',time='')

结果:

接收到的数据形式是字典形式,可以传空值,个数不限制

{}
{'name': '小黑', 'addr': '北京'}
{'file_name': 'a.json', 'mode': 'w', 'conent': 'abcc', 'time': ''}

但是,有个问题,当传入的为位置参数,不能传关键字参数!!!

xiaohei(1,2,3)

会报错:TypeError: xiaohei() takes 0 positional arguments but 3 were given

所以:**是关键字传参,会把多余的参数放进字典内

归纳一下:

def xiaobai(name,age=None,*args,**kwargs):
print(name)
print(age)
print(args)
print(kwargs) xiaobai('xiaobai',18,'beijing','shanghai',money=500,
func='xiaobai')

结果:

xiaobai
18
('beijing', 'shanghai')
{'money': 500, 'func': 'xiaobai'}

参数传递,位置参数和默认值参数优先,再多余的位置参数会进入参数组内(*arg),再多余的"默认值参数"会进入关键字参数(**kwargs)内

5、解包

再着重说一下 * 和 ** 的作用

假设我们连接数据库,原来我们只能这么传,一个一个对应:

def op_mysql(host,port,user,passwd,db):
print(host)
print(port)
print(user)
print(passwd)
print(db)
op_mysql('127.0.0.1',3306,'root','123456','szz')

1、那么我们用 *args 的方式:

db_info = ['127.0.0.1',3306,'szz','','szz']
#db_info = ('127.0.0.1',3306,'szz','','szz')
op_mysql(*db_info)

注意这里是调用的时候写 *db_info ,意思是将 db_info 解包传入函数体内,但是参数个数要一致(可以传元组,list,甚至是字符串,但是个数要一致,只要有下标的就成),而且进入的值要跟函数定义内的对应

结果:

127.0.0.1
3306
szz
123456
szz

2、那么我们用 **kwargs 的方式:

db_info2 = {
'host':'127.0.0.1',
'port':3306,
'user':'szz',
'passwd':'',
'db':'szz'
} op_mysql(**db_info2)

把字典解开host=127.0.0.1,port=3306,user=szz……传入到函数内,这里要注意字典内的 key 值要跟函数定义的参数名字对应,个数要一致,顺序可以不一致

结果:

127.0.0.1
3306
szz
123456
szz

6、定义入参形式

假设我们要定义输入参数的数据类型怎么定义呢?

def add_user(username:str,password:list):
print('username',username)
print('password',password)

如上面例子所示,username 定义为 str 类型,password 是数组类型;但是这个入参类型仅仅可以认为是个提示信息,即使不传入规定的参数类型,也不会报错

递归

递归简单而言就是函数内部调用函数本身(最多调用 999 次)

比如我们用一个函数判定输入的数字是否为偶数,不是的话就继续输入

def say():
num = input('请输入一个数字:').strip()
if int(num)%2!=0:
print('请重新输入')
say()
return True
say()

递归的 return 坑,得到 none

return的作用是将函数结果返回,即退出def函数模块。大量的教材和网上教程都有说明函数执行遇到return就会结束,返回一个值给调用函数处。常规用法确实是这样,但在递归调用中却存在一个坑,今天就遇到了,举个例子:

一个简单的不断相加的递归小程序:

def add(sum,x,y):
if sum<10:
x +=2
y +=2
sum=x+y
add(sum,x,y)
else:
sum=x+y
print(sum)
return sum
print (add(0,0,0))

结果:

12
None

这就有点奇怪了,结果为什么是 None?

经过计算,结果确实应该是12,明明已经计算出了正确的值,为什么函数返回值是 None 呢。经过多方查阅,发现自己采坑里去了,惯性思维让我认为 return 必然会使得 def 函数模块结束返回一个值,可实际上在递归中并不是,如果改变约束条件在 return 之后函数还会继续递归计算。

真正的原因是此处的 return 仅仅是上一次递归调用函数本身时候的返回值,而 def 函数块并没有返回任何值。也就是说这个 return 仅属于上一次递归调用,并不属于 def 函数块。也就是说整个 def 函数块没有 return,也就没有出口,自然不会有数据出去,所以得到 None,将程序改变一下:

def add(sum,x,y):
if sum<10:
x +=2
y +=2
sum=x+y
sum = add(sum,x,y)
return sum
else:
sum=x+y
print(sum)
return sum
print (add(0,0,0))

结果:

12
12

这次就正确了,程序多次递归后,运行到 else,此时返回一个值到达 sum=add(sum,x,y) 的 sum,再 return sum,此时为 def 函数块的返回值。而之前程序运行到 sum=add(sum,x,y) 时由于等号右边的递归使得程序一直在计算,sum 并未被幅值,进而下面的 return sum 并未执行,所以只有一个返回值。

 

深拷贝/浅拷贝

用一个例子来看一下,循环删除 list 内容会出现什么问题

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

for i in li:
if i%2!=0:
li.remove(i)

很明显,这个函数的作用是,删除数组内的奇数,只留下偶数,但是结果真的如此么?

[1, 2, 4, 6, 8]

咦,为啥会出现这个问题?多出来一个 1?

解答:我们理解一下,循环 list ,第一个取到的是 li[0] = 1,是奇数,所以删除,此时 li = [1,2,3,4,5,6,7,8,9] ;再删除下标为 1 的 li[1]  = 2,为偶数,不删除,所以留下了一个 1 ……

所以,循环 list 删除元素,都会出现这个问题,怎么解决?

方式1——深拷贝一个一样的 list

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

l2 = [1,1,2,3,4,5,6,7,8,9]
for i in l2:
if i%2!=0:
li.remove(i)
print(li)

重新拷贝一个一模一样的 l2,循环 list ,第一个取到的是 l2[0] = 1,是奇数,所以删除,此时 li = [1,2,3,4,5,6,7,8,9] ;再看 li2[1] 是奇数,删除 li 的 1 ,所以 li 变成了 [2,4,6,8]

那么可能会说,既然 l2 和 li 是一模一样,为啥不直接 l2 = li 进行复制呢?这就涉及到一个概念叫:深拷贝,浅拷贝。区别:深拷贝会开辟新的内存空间;浅拷贝:不会开辟新的内存空间。

我们定义的 li = [1,1,2,3,4,5,6,7,8,9] 其实是在内存里面开辟了一块内存存这个 list 的内容 [1,1,2,3,4,5,6,7,8,9] ,那 li 这个变量也是开辟了一块内存空间,里面存的是什么?是这个 list 的内存地址,比如说是 1234;

假设要对 li 元素删除,会用 li 的地址 1234 对应的 list 内的 [1,1,2,3,4,5,6,7,8,9] 去删除。那么假设我们定义 l2 = li ,那么只是将 l2 的地址也是 1234 ,这样操作的话,操作的是同一个内存空间的 list ,其实跟没有拷贝是一样的……

所以我们要重新开辟一块内存空间存一样的 list ,将内存独立出来就不会出现 list 修改的问题

方式2——切片深拷贝

li = [1,1,2,3,4,5,6,7,8,9]
l2 = li[:] for i in l2:
if i%2!=0:
li.remove(i)
print(li)

地址空间怎么查看

li = [1,1,2,3,4,5,6,7,8,9]
l2 = li
l3 = li[:]
print(id(li))
print(id(l2))
print(id(l3))

地址结果:说明 l2 = li 这种方式不会开辟新的内存空间

39139336
39139336
34693832

当然深拷贝,对于字典元组什么的也是一样适用。深拷贝会开辟新的内存空间;浅拷贝:不会开辟新的内存空间。

深拷贝/浅拷贝

import copy
d = {'name':'xiaohei','l':[4,5,6]}
d1 = d #浅拷贝
d2 = copy.copy(d)#浅拷贝
d3 = copy.deepcopy(d) #深拷贝 d1['age']=18
d1['l'].append(8) print(id(d))
print(id(d1))
print(id(d2))
print(id(d3)) print('d',d)
print('d1',d1)
print('d2',d2)
print('d3',d3)

结果:

38911072
38911072
38911720
42963664
d {'name': 'xiaohei', 'l': [4, 5, 6, 8], 'age': 18}
d1 {'name': 'xiaohei', 'l': [4, 5, 6, 8], 'age': 18}
d2 {'name': 'xiaohei', 'l': [4, 5, 6, 8]}
d3 {'name': 'xiaohei', 'l': [4, 5, 6]}

这里有个疑问,为什么 copy.copy 打印出来的内存地址也是不一样的呢,但是打印出来的结果是一致的,记住 copy.copy() 是浅拷贝,虽然也开辟了新空间,但是里面嵌套一层数组啥的,也不会拷贝出来,所以是浅拷贝。

内置函数

有文档可参考:https://docs.python.org/zh-cn/3.7/library/functions.html

python 自带的函数,比如说:input(),print()

1、类型转换

函数名 功能
int() 转成整数
float() 转成浮点数
dict(a=1,b=2) 转成字典
list('123') 转成列表
set() 转成集合
tuple() 转成元组
bool(None) 转成布尔类型

2、常用函数

enumerate  #枚举

假设想实现,打印出 a==>1 b==>2 c==>3……a对应1,b对应2,c对应3这种的,要怎么实现?

方法1:

l = ['a','b','c','d','e','f']
id = 1
for i in l:
print('%s==>%s'%(i,id))
id+=1

方法2:

l = ['a','b','c','d','e','f']
for id,i in enumerate(l,1):  #后面的 1 代表从 1 开始,写 0 代表从 0 开始,就是 a==>0……
print('%s => %s'%(id,i))

结果:

1 => a
2 => b
3 => c
4 => d
5 => e
6 => f

zip  #合并

l1 = ['xiaoming','xiaobai','xiaohei']
l2 = [110,120,119]
l3 = [1,2,3]
res = list(zip(l1,l2,l3))
print(res)

结果:

[('xiaoming', 110, 1), ('xiaobai', 120, 2), ('xiaohei', 119, 3)]

要注意的是,假设 l3 只有 2 个元素,那么 zip 之后整个 list 内元素只有两个:

l1 = ['xiaoming','xiaobai','xiaohei']
l2 = [110,120,119]
l3 = [1,2]
res = list(zip(l1,l2,l3))
print(res) 结果:
[('xiaoming', 110, 1), ('xiaobai', 120, 2)]

这个一般用在于合并两个 list 转成 字典形式:

l1 = ['xiaoming','xiaobai','xiaohei']
l2 = [110,120,119]
res = list(zip(l1,l2))
print(res)
print(dict(res)) 结果:
[('xiaoming', 110), ('xiaobai', 120), ('xiaohei', 119)]
{'xiaoming': 110, 'xiaobai': 120, 'xiaohei': 119}

map —— 循环调用函数,保存返回结果

例如讲,我们对数字补零的方式:'1'.zfill(2),就是对数字补零为 2 位,但是假设我们并不知道有这个方式怎么办?就要自己写函数补零

def zfill(num):
num = str(num)
if len(num)==1:
num = ''+num
return num

定义好之后,假设要生成一个 01-33 的二位数 list 那么就得对 range 进行循环补零:

1、直接循环写

l = []
for i in range(1,34):
result = zfill(i)
l.append(result)
print(l)

2、列表生成式写

l = [ zfill(i) for i in range(1,34) ]

3、利用 map :要用的时候,前面一定要加 list 转换,否则不会调用

map(函数名,list),里面可以理解为 map 会帮我们循环调用这个 list ,将 list 的每个值传到函数名内循环调用

res = list(map(zfill,range(1,34)))
print('map 的结果:',res) 结果:
map 的结果: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']

这里要注意,要查看 map 函数的结果,需要在前面加 list ,这是 Python3 内需要注意的否则会打印出来一串 <map at 0xc8c9320> 之类的。

map 函数也可以用来创建文件夹:同样的,前面要加 list ,否则不会创建

import os
list(map(os.mkdir,['dsk','ldd','brf']))

filter —— 循环调用函数

假设我们有一个显示分数是否及格的程序,我们用 list 的每个传入该函数内判断

score = [89, 43, 60, 52, 45, 37, 66, 100, 21, 24]

def is_jg(s):
if s>59:
return True

如果我们只想把及格的分数保留,不及格的剔除,原来的方法:

jg = []
for i in score:
if is_jg(i):
jg.append(i)
print(jg)

利用 filter 方法:这里要注意,filter 要生效也要加 list 转换

result = list(filter(is_jg,score))
print('filter的结果',result) filter的结果 [89, 60, 66, 100]

那么你可能会问,map 的结果是啥呢?map 其实是保存返回结果,那么上面的 is_jg 的返回结果是啥呢?是 True 和 None

result2 = list(map(is_jg,score))
print('map的结果',result2) map的结果 [True, None, True, None, None, None, True, True, None, None]

map:我帮你循环调用函数,你返回什么,我就保存什么;filter:你只要返回 True ,我就给你保存这个 list 的元素,返回结果不为 True 的元素就给你过滤掉

函数名 功能
type() 查看数据类型
id() 查看地址
len() 查看 list 等长度
sum(list) 求数组的和
round(1.9911,2) 四舍五入保留两位小数
divmod(10,3) 取商和余,返回(3,1)
locals() 取当前函数的所有局部变量,返回 list
globals() 取当前整个Python文件的所有变量,返回 list
chr(64) 取 Ascii 码为 64 对应的字符:@
ord('A')  取字符 A 对应的 Aciii 码
dir(d) 看 d 这个数据支持哪些方法可用
sorted(l) 对l(l可以为list也可为字符串等)从小到大排序
reversed(sorted(l)) 对 l 从大到小排序(reversed就是翻转) 
sorted(l,reversed=True) 效果同上,从大到小排序
enumerate 枚举
zip 合并
list(map(funname,list)) 将 list 的每个值循环传入 funname 调用,保存返回结果
list(filter(funname,list)) 将 list 的每个值循环传入 fucname 调用,保存返回为 True 的元素

字符集编码

让计算机认识各种字符:数字,特殊字符,汉字……计算机只认识 0 和 1。

那么计算机怎么认识其他的呢?一开始,计算机是外国人造的,外国人弄了一张表,就是 Ascii 码,每一个英文字母以及 0-9 数字以及特殊字符都有个对应的编码,计算机就按照这张表进行翻译。比如说 @ 字符的编码为 64,先将 @ 转化为 64,再将 64 转化为二进制数这样计算机就能认识这个 @ 。

再后来,计算机传入到中国,那么中国不能也只用简单的英文字符以及特殊字符啊,那么咋办呢?而且别的比如说韩国,日本等也要用。后来就来了一张表:gb2312,里面有六千多个汉字,计算机就认识中文了,后来又扩展了下:GBK,基本就包含了汉字,比如说我们的 Windows 系统现在默认的字符集编码就是 GBK。但是中文用的是 GBK 拿到日本啥的能用么?用不了,会出现乱码,相当于鸡同鸭讲,所以这就是为什么出现乱码。

为了解决这个问题,发明了新编码:Unicode,就把很多国家的字符集集成起来,表很大有很多数字,不管是英文,什么鬼文,在全世界都通用的,这个就是万国码。又产生了个问题:一开始英文只占了一个字节大小,Unicode规定每个字符都占两个字节,这样就导致了很多明明可以一个字节表示的字符,却强制性变成了两个字节,占用的内存也有很多不必要的浪费。

最后出来了 utf-8 ,也就是解决了这个问题,什么英文字符啥的也就是占一个字节,中文啥的占两个字节,这样算是最优解了,所以现在用中文的话,一般指定 utf-8。所以 utf-8 是属于 Unicode,只是做了小优化。Python 3 里面默认的编码是 Unicode,所以 Python 3 里面对中文比较友好;Python 2 默认的是Ascii 码,所以要在最前面写 #coding=utf-8

有时候会有个问题,函数能不能作为字典的 value 存在?这样多个 if 的情况下就直接用 key - value 调用函数,不用多个 什么 if 去写:

func_map = {
"":func,
"":fun2
"":fun3
} if choice in fun_map:
fun_map.get(choice)()

作业

要求:写一个生成双色球的程序,输入几就产生多少注双色球

  1. 每次产生的双色球不能重复
  2. 存到文件里面
  3. 文件里面的也不能重复
规则
  1. 红色球号码从1 - -33中选择;蓝色球号码从1 - -16中选择
  2. 红色的球有6个
  3. 蓝色的球有1个
思路:
  • 红色球6个,1,33,蓝色球1个,1-16
  1. 先从1,33之间取6个 random.sample([1,33],6)
  2. 再从1-16之间取1个 random.choice([1,16])
  • 把双色球号码改成 红色球 01 02 03 04 05 06 蓝色球 07 的格式
  • 读到文件的内容, 判断刚才产生的双色球是否在文件中
  • 不在就写入
import random
FILE_NAME = 'seq.txt'
def op_file(content=None):
with open(FILE_NAME,'a+',encoding='utf-8') as fw:
if content:
fw.write(content)
else:
fw.seek(0)
res = fw.read()
return res
def seq(num):
count = 0
while count<num:
b1 = [ str(i).zfill(2) for i in range(1,34) ]#产生一个01,02- 33的list
b2 = [ str(i).zfill(2) for i in range(1,17) ]#产生一个01,02- 33的list
red = random.sample(b1,6)#返回是一个list
red.sort()#排序
blue = random.choice(b2)
red_str = ' '.join(red) # '01 02 03 04 05 06'
result = "红色球:%s 蓝色球:%s\n"%(red_str,blue)
all_ball = op_file()#获取文件内容
if result not in all_ball:
op_file(result)#写入
count+=1 def seq2(num):
count = 0
while count<num:
red_str = ' '.join(sorted(random.sample([ str(i).zfill(2) for i in range(1,34) ],6))) #返回是一个list
blue = random.choice([ str(i).zfill(2) for i in range(1,17) ])
result = "红色球:%s 蓝色球:%s\n"%(red_str,blue)
if result not in op_file():
op_file(result)#写入
count+=1 seq2(20)

Python(四) —— 函数的更多相关文章

  1. python(四)函数

    一.背景 在学习函数之前,一直遵循:面向过程编程,即:根据业务逻辑从上到下实现功能,其往往用一长段代码来实现指定功能,开发过程中最常见的操作就是粘贴复制,也就是将之前实现的代码块复制到现需功能处,如下 ...

  2. Python 全栈开发四 python基础 函数

    一.函数的基本语法和特性 函数的定义 函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的.函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数 ...

  3. python学习笔记(四):函数

    一.函数是什么? 函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的,编程中的函数在英文中也有很多不同的叫法.在BASIC中叫做subroutine(子过程或子程序),在Pasc ...

  4. Python中函数传递参数有四种形式

    Python中函数传递参数有四种形式 fun1(a,b,c) fun2(a=1,b=2,c=3) fun3(*args) fun4(**kargs) 四种中最常见是前两种,基本上一般点的教程都会涉及, ...

  5. Python虚拟机函数机制之位置参数(四)

    位置参数的传递 前面我们已经分析了无参函数的调用过程,我们来看看Python是如何来实现带参函数的调用的.其实,基本的调用流程与无参函数一样,而不同的是,在调用带参函数时,Python虚拟机必须传递参 ...

  6. Python之函数与变量

    本节内容 函数介绍及其作用 函数的定义与调用 函数的参数说明 全局变量与局部变量 值传递和引用传递 一.函数的介绍及其作用 编程语言中的函数与数学中的函数是有区别的:数学中的函数有参数(输入),就会有 ...

  7. Python之函数进阶

    本节内容 上一篇中介绍了Python中函数的定义.函数的调用.函数的参数以及变量的作用域等内容,现在来说下函数的一些高级特性: 递归函数 嵌套函数与闭包 匿名函数 高阶函数 内置函数 总结 一.递归函 ...

  8. python 中函数的参数

    一.python中的函数参数形式 python中函数一般有四种表现形式: 1.def function(arg1, arg2, arg3...) 这种是python中最常见的一中函数参数定义形式,函数 ...

  9. python 中函数参数传递形式

    python中函数参数的传递是通过赋值来传递的.函数参数的使用又有俩个方面值得注意:1.函数参数是如何定义的 2.在调用函数的过程中参数是如何被解析 先看第一个问题,在python中函数参数的定义主要 ...

  10. 第三章:Python基础の函数和文件操作实战

    本課主題 Set 集合和操作实战 函数介紹和操作实战 参数的深入介绍和操作实战 format 函数操作实战 lambda 表达式介绍 文件操作函数介紹和操作实战 本周作业 Set 集合和操作实战 Se ...

随机推荐

  1. Input标签_实现限制输入字符类型(只能输入特定类型字符)

    ... <input type="text" placeholder="密码" maxlength="20" onKeyPress=& ...

  2. CSS3简单画出3d图形

    1.气球 2.泳圈 1.2两图实现代码分别如下: <html> <head> <meta charset="utf-8"> <meta h ...

  3. PTA-栈(括弧匹配)

    #include<bits/stdc++.h> using namespace std; #define STACK_INIT_SIZE 10000 #define STACKINCREM ...

  4. L343 中译英

    爱显摆的人遇事总喜欢标新立异.Showoffs never miss an opportunity to draw attention to themselves by some outrageous ...

  5. 学号 20175223 《Java程序设计》第9周学习总结

    目录 教材学习内容总结 教材学习中的问题和解决过程 1. 输出文件时过多输出. 代码调试中的问题和解决过程 1. 问题:费马素性检验程序. [代码托管] 学习进度条 参考资料 目录 教材学习内容总结 ...

  6. GoGland 快捷键说明

    关于Gogland一些常用快捷键的说明,我在网上没有搜索到,于是乎,我找到了官网中的视频介绍,然后将其中的一部分摘录了出来,希望能帮住大家... Gogland——使用说明前面是苹果|后面是linux ...

  7. jar包是干什么用的

    1.JAR(Java ARchive)是将一系列文件到单个压缩文件里,就象Zip那样.但是,同Java中其他任何东西一样,JAR文件是跨平台的,所以不必关心涉及具体平台的问题.2.jar包就是别人已经 ...

  8. 第一次scrum冲刺

     一.第一次冲刺任务          首先分工做好全局规划,然后基于规划实现全部功能,当然现在只是部分.   二.用户故事        用户进入界面    用户输入账号密码        不记得密 ...

  9. 玩转BLE(3)_使用微信蓝牙精简协议伪造记步数据

    1. 前言 在物联网时代,有一个问题肯定会让人头疼(现在已经初露端倪了): 物联网中的IOT设备有两个主要特点: 1)简单小巧(不具备复杂的人机交互接口,需要手机等终端设备辅助完成配置.控制等功能). ...

  10. 深度学习(PYTORCH)-3.sphereface-pytorch.lfw_eval.py详解

    pytorch版本sphereface的原作者地址:https://github.com/clcarwin/sphereface_pytorch 由于接触深度学习不久,所以花了较长时间来阅读源码,以下 ...