python - day10
参数:
默认参数:
在定义函数的时候,可以先给位置参数赋一个默认值,如果后面调用该函数时,没有对该位置参数传值,则该位置参数使用设置的默认值。
eg:
def  function1(name,age=18):#这里对age参数进行了默认值设定。#打印名字和年龄。print("name:",name,"age:",age);function1("guo");#这里没有传送age的值,所以默认age=18
function1("gao",20);#这里传送了age的值,所以输出的年龄是20
运行结果:

不定长参数
不定长参数是不确定别人在调用该函数时,会传多少参数,如果比函数声明的要更多,多出来的这些参数就是不定长参数。
加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。
加了两个星号 ** 的参数会以字典的形式导入。
eg:
def   function(a,*b):#这里定义了一个函数,参数a是必选参数,参数b是可变参数/关键字参数,*表示b是一个元组,用来存放多出来的参数。print(a);print(b);def   function1(c,**d):#这里定义了一个函数,参数c是必选参数,参数d是关键字参数,**表示d是一个字典,用来存放多出来的参数。print(c);print(d);function(1);#这里只传了a的参数,b参数没有传送,是一个空元组。
function(1,2,3,4,5,6,7,8,9,10);#这里传送了a和b两个参数,b是一个元组,里面存放了8个参数。function1("hh");
function1("hh",name="guo",age=20,sex="male")#这里传送了c和d两个参数,d是一个字典,里面存放了name,age,sex三个参数。运行结果:

匿名函数
Python 使用 lambda 来创建匿名函数。
它可以具有任意数量的参数,但只能有一个表达式。
所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数,没有函数名称,只能通过赋值给变量或作为参数传递给其他函数来使用。
- lambda 只是一个表达式,函数体比 def 简单很多。
- lambda 的主体是一个表达式,而不是一个代码块。仅仅能在 lambda 表达式中封装有限的逻辑进去。
- lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
语句格式:
lambda [arg1 [,arg2,.....argn]]:expression
arfg1,arg2....都是参数,可以包含零个或多个参数,但必须在冒号(:)前指定,expression是逻辑表达式。
eg:
x1= lambda x:x*2;
#定义了一个匿名函数,输入一个参数x,返回x*2。
#x1是函数对象,可以像其他函数一样调用。a=x1(3);
print(a);#输出: 6运行结果:

可以将匿名函数封装在一个函数内,这样可以使用同样的代码来创建多个匿名函数。
eg:
def myfunc(n):return lambda a : a * nmydoubler = myfunc(2)#这里在定义一个匿名函数,输入一个参数n,返回一个匿名函数对象。
#运行的结果相当于 mydoubler = lambda a : a * 2;
mytripler = myfunc(3)print(mydoubler(11))
print(mytripler(11))运行结果:

lambda 函数通常用于编写简单的、单行的函数,通常在需要函数作为参数传递的情况下使用,例如在 map()、filter()、reduce() 等函数中。
map函数
语句格式:
map(function, iterable)map函数,就是把iterable序列里面的每个元素都用到前面的function函数中,然后将function函数的运行结果逐一返回,感觉用于值转换,列表里的是自变量,然后function是函数,map返回自变量带入函数之后的因变量。
eg:
number=[1,2,3,4,5,6,7,8,9,10];
hh=tuple(map(lambda x:x*2,number));#map函数将number中的元素全部乘以2,并将结果存入一个新的元组hh中。
print(hh);
print(type(hh));运行结果:

filter函数
语句格式:
filter(function, iterable)filter用来过滤元素,元素来自于iterable,条件是function函数,满足条件的会被返回保留。
eg:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
filter2 = list(filter(lambda x : x%2==0,numbers));
#filter函数将numbers中的偶数元素存入一个新的列表filter2中。
#元素来自numbers,条件来自lambda函数,即x%2==0。满足条件的元素会被存入filter2。
print(filter2);运行结果:

eg:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
filter2 = filter(lambda x : x%2==0,numbers);#我在这里没有指明返回值的类型print(filter2);运行结果

这好像是个什么的地址,倒没有报错。
reduce函数
语法格式:
reduce(function, iterable)通过对序列中的元素重复应用某个函数,将序列元素累积成单一的值。

eg:
from functools import reduce
numbers = [1, 2, 3, 4, 5];
reduce1=(reduce(lambda x,y:x*y,numbers));
#reduce函数将numbers中的元素全部相乘,并将结果存入一个新的列表reduce1中。
print(reduce1);运行结果:

通过类创造栈(这里类还没有开始学,看着写了一遍)
类似乎就是一群变量/属性和函数/方法的集合,不过类内部的函数要比正常的函数定义多一个变量,放在第一个,表示的是这个类本身,在下面的代码中就是self,后面的就是函数正常运行所需要用到的变量,比如push函数中的x,感觉之所以要有self是为了指明这个变量,或者这个函数来自于self这个类,防止混乱,在调用类内部的变量和函数是,要先用self.指明是这个类的属性和方法,其他的都是正常的,比如在给列表增添值时,(比如这个列表是stack)正常的就是stack.append(x),然后类内部的就是self.stack.append(x),这样说明是self这个类里面的列表,函数也是同理,区分调用和定义,调用时不用再第一个参数是self,定义的时候需要将第一个参数写为self,然后后面才是正常需要的参数)比如我们调用类的内部函数时也是加上self.用来说明是类内部的函数,比如下面的self.is_empty(),也是多了一个self用以指明是类的内部函数。
对于def __init__(self):这部分在定义实例类时,会自动运行,比如下面的那个stack1=stack(),这里的stack1就是实例类(好像这么叫的),因为我们只是定义了一个类,然后现在我们用我们定义的这个类去真正的创造一个变量(一个类的变量,也就是下面的stack1)(注意那个横线是双横线,不是单)。
而在创造一个类的实例变量之后,使用也是一样的 类的名字(这里就是真正所定义出的那个类了,就是下面的那个stack1) + . + 想要调用的函数名,比如下面的stack1.push(),(不要忘了带小括号,因为本质上,stack1.pop()也是一个函数,不过是多了一个self用以指明是类内部的函数,正常的函数就是pop())。
eg:
class stack:#初始化栈def __init__(self):self.stack=[];#判断栈是否为空def is_empty(self):if len(self.stack)==0:return True;else:return False;#入栈def push(self,x):self.stack.append(x);#出栈def pop(self):if self.is_empty():#调用方法/函数的时候,需要加self,指明调用的是哪个类的实例。变量/属性也是raise IndexError("pop from empty stack");else:return self.stack.pop();#查看栈顶元素def peek(self):if self.is_empty():raise IndexError("The stack is empty");else:return self.stack[-1];#获取栈的大小def size(self):return len(self.stack);#测试
stack1=stack();#创建栈对象
stack1.push(1);#入栈
stack1.push(2);
stack1.push(3);
stack1.push(4);
print("size:",stack1.size());
print("peek:",stack1.peek());
x=stack1.pop();
print("栈顶元素为:",x);
print("栈元素为:",stack1.peek());
print("判断栈是否为空:",stack1.is_empty());运行结果:

列表推导式
我们之前前面学过一点,形如下面这种;
list = [ x*2 for x in range (1,10) if x%2==0];
#列表推导式,x*2是一会列表的元素,for x in range (1,10)是循环,if x%2==0是条件,生成一个新的列表。
#列表推导式的格式是[表达式 for 变量 in 可迭代对象 if 条件],if 条件是可选的,可迭代对象可以是列表、元组、字符串等。
#生成的列表中元素的类型是表达式的类型。
print(list);
print(list.pop(0));
print(list.pop(0));#这说明再删除第一个元素之后,后面的元素会自动向前,索引0的元素变成了索引1的元素。运行结果:

这里有一些更复杂的形式:
eg:
list1 = [ [x,x*2] for x in range(2,9) ];
# 嵌套列表推导式,生成一个二维列表,外层列表的元素是[x,x*2],x是内层列表的第一个元素,x*2是内层列表的第二个元素。
print("list1:",list1);list2 = [x*y for x in range(2,5) for y in range(1,5)];
# 多重循环,生成一个列表,元素是x*y,x是2-4,y是1-4。x,y的循环顺序是先x,再y。x和y的范围可以是不同的。
print("list2:",list2);#这个感觉很牛
matrix = [ [1, 2, 3, 4],[5,6,7,8],[9,10,11,12]];
# 定义一个矩阵,每行4个元素,每列3个元素。list3 = [row for row in matrix];
# 列表推导式,生成一个列表,元素是矩阵的每行。
print("list3:",list3);list4 =[ [row[i] for row in matrix] for i in range(4)];
# 嵌套列表推导式,生成一个二维列表,外层列表的元素是矩阵的每行,内层列表的元素是每行的第i个元素。
print("list4:",list4);运行结果;

这里list2可以看一下,x,y不是一 一对应,而是每个x对应所有y;
然后对比一下list3和list4,从list3的运行结果可以看出,通过for循环提取出的row ,是矩阵的每一行,也就是说它是外层copy(相当于它把matrix内部的元素看三个元素,每个元素是一个列表,就是那三行),这样就可以比较好的解释list4的生成,首先通过外层的for循环,提取出一个i的值,然后赋值到内层循环(假如这里的i是1),这样内层就变成了row[1] for row in matrix ,而我们刚刚说了row 提取的矩阵的外层元素,也就是一个列表,这样的话,我们相当于提取了每个列表的第一个元素(row变成了一个列表,然后row[1]提取的是row列表的第一个元素)。
再补一点;下面的代码是在上面的基础上补充在最后的
del list1[:];
print("list1:",list1);
del list2;
print("list2:",list2);
运行结果;

这说明上面那种删除方式,是清空列表内元素,但列表本身还在,所以打印的是空列表,而下面那种,则是直接把列表本身就删除了,所以打印错误会。

