python学习_一


2020/04/25
lstrip:删去左端空格。
rstrip:删去右端空格。
strip:删去两端空格。
都不改变原字符串。


在使用数字类型和字符串类型拼接时,单纯拼接(像Java那样做)会报错,需要将其中的数字显示转换,如:

mes = “i'm "+32

此时会报错,需要使用函数str()将数字32显示转换成字符串。


方括号([])来表示列表。列表与Java中的数组形式以及访问方式都差不多,只是在数组用{}包括元素,列表用[]包括元素。
同时列表可以使用-1下标来访问最后一个元素,并且可以使用list[s:e]的形式来分片,得到的结果时从下标s到下标e(但不包括e处的元素)的所有元素构成的一个列表。
如果省略s,则从第一个元素(包括第一个元素)开始到e,若省略e则从s到最后一个元素(包括最后一个),如果都省略则返回整个列表。

如果想返回包含倒数几个元素的列表则使用负索引,如:list[-3:],这个将返回包含列表中最后三个元素的列表。


列表元素都可以像数组那样修改其某个位置的值。同时其具备数组不具备的性质:动态添加/删除元素。
通过list.append()方法在列表尾部添加,list.insert(index,elem)方法向指定位置(index)添加指定元素elem。
通过del list[index] 删除index处的元素(可以看出该方法不归list所有,这是与添加元素的方法不一样的地方)
通过list.pop() 方法弹出列表末尾的元素,该方法有返回值:弹出的末尾元素。

通过list.pop(index) 方法弹出列表中index位置处的元素,同样返回弹出的元素。

通过list.remove(elem) 方法删除指定的元素,若有重复的elem元素则需重复删除。


list.sort()方法对列表进行排序,一般根据字母序顺序排列,若要逆序则使用reverse参数:list.sort(reverse=true)即可。会改变原列表(若不想改变原列表则使用sorted()函数,使用详情一样)。

list.reverse():将列表反转。会改变原列表。

len(list):返回列表元素个数。


使用函数range()几乎能够创建任何需要的数字集。该函数有三个参数:range(s,e,step),表示从s开始到e的一系列数字,并且各个数字之间间隔step。step省略时默认为1.
range(s,e):生成从s到e的一连串数字,但不包括e本身。这个函数一般用于for循环,直接打印没有作用(不会像列表那样),如:
arr = range(1,5)

print(arr)

此时只会打印:range(1,5)。(如果要出现像列表那样打印结果则需要将arr进行类型转换:arr = list(arr) 即可,此时再去打印arr则会打印出一个列表:[1,2,3,4])
在循环中使用则可以:

for value in range(1,5);

    print(value)

此时会打印1,2,3,4四个数字。


list里面的元素的数据类型也可以不同,并且列表可以包含列表。


元组tuple,又称有序列表,使用()来包括元素(与list的[]不一样)。同时,一个元组以及元组中的元素在初始化后就不可变,也就是只读不可写。
正因为元组不可变因此比列表更安全。


如果想要定义只有一个元素的元组,则需要在定义的元素后面添上一个 逗号。如下:

t = (1,)

这样定义的t就是一个只有一个元素的元组。但是如果:

t = (1)

如果想要定义可变的元组类型,则只需在元组中添加list类型的元素,但是此时只是能改变这个list类型的元素而已,其他非list类型的元素依然无法改变。


input()返回的数据类型是str。


字典类型。
该类型就是java里面的map类型,都是采用键值对的形式存储于访问,只不过定义的形式不一样。
在python中同样使用 [] 来包含字典类型的元素,但是里面的单个元素需要同时指定键和值(与list类型不一样),示例如下:
dic = [key1:value1, key2:value2,…]

由于字典类型和map一样,所以键值对的映射也是通过计算键的hash值来确定的,因此,作为字典的键的类型一般是不可改变的类型,如字符串,数字,元组,而列表就不可以。
如果要访问字典中的值,有几种方法:

①dic[key1]
此时会输出key1对应的值。但是这样做有风险,因为key1这个键可能在dic中未被定义,此时就会报错。
tips:
如果要判断某个键是否在字典中,可以使用:
key in dic
语句。存在则返回true。
②使用dic.get(key)
此函数返回的结果一方法①一样,但是如果key在dic中不存在此时程序并不会报错而是会返回一个None(tips:返回None的时候Python的交互环境不显示结果,因此无法显示进行判断存在与否)。
此时如果想要dic.get(key)在key不存在dic中的时候返回想要(可以用于显示判断)的某个值,则可以在get函数中添加一个value参数,如下:
dic.get(key,-1)

此时如果在dic中不存在键key,程序则会返回-1。


使用dic.pop(key)可以删除key这个键(同时清除并返回其对应的值)。


使用def 定义一个函数

def fucName(parameter):
	//do something

如果想定义一个什么事也不做的空函数,可以用pass语句

def fucName(parameter):
	pass

python中的函数可以返回多个值,实际上是返回一个元组。

定义函数时可以使用默认参数:

def fucName(a, b, c=2):
         //fuc block

此时再调用该函数的时候如果只传入了两个参数,同样不会报错,因为第三个参数默认传入一个 2 。同样如果想要传入第三个参数也没有问题。可以看出python的函数定义可以非常灵活。

在传入参数时可以像插入数据库语句那样指定某个参数的值,而不一定要按照参数定义的顺序传入参数。

注意!!!!
使用默认参数时需要非常小心,如下:

def fucName(L=[]):
       L.append("ddd")
       return L

此时如果在控制台调用该函数,则会发现L越来越长,并且都是重复的“ddd”元素
原因在于如果在函数定义中指定了一个默认参数,事实上python会为该默认参数开辟一个“专属空间”,并且每次都使用这个空间,也就是说,如果这个默认参数如果可变(像是list类型),此时如果在函数体中对该默认参数进行增改,那么该默认参数会持久的改变直至其所在空间被释放。
所以默认参数一般使用字符串、数字等不可变类型。
如果非要指定一个默认的list对象,则将其默认值设为None,与此同时在函数体中将该参数重新赋给一个空list即可:

def fucName(L=None):
      if L is None:
	L = []
      L.append("ddd")
      return L

此时不会有叠加的不想出现的效果,因为None是一个不可改变的对象。


如果要定义可变参数个数的函数,可以:
①传入一个元组或者列表再遍历即可
②定义函数参数时在参数前加上 * ,如下:

def fucName(*nums):
      for num in nums:
            //do something

在调用该函数时将自动将传入的参数转换为元组类型。


关键字参数:

def fucName(para1, para2, **para3):
      //do something

此时不仅可以实现传入的参数可变,而且会将传入的从第三个参数开始的所有参数组装成一个字典。
此时前两个参数必须,第三个参数非必需。
如果传入多与两个参数,则从第三个参数开始都需要指定参数名(自定义参数名),命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错。但是如果关键字参数也指定了默认值则不会报错。

>>>ducName("d", 1, key1=v1,k2=v2)

此时将后两个参数拼装成 {key1:v1, k2:v2}。
注意,此时的key1、k2都无需带引号,如:

>>>fucName('name', '1', 'job'='sss')

此时会报错:keyword can't be an expression


如果要限制关键字参数的名字,就可以用 命名关键字 参数,例如,只接收city和job作为关键字参数。这种方式定义的函数如下:

def fucName(name, age, *, city, job):
     pass

此时相当于定义了一个仅仅可以传入两个可变参数的函数,如果传入可变参数时所指定的参数名不是job或者city则会报错。如果传入两个及两个以上的同名参数同样会报错。

如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:

def fucName(name, age, *arg, job, city):

在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。
但是参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。


小结
Python的函数具有非常灵活的参数形态,既可以实现简单的调用,又可以传入非常复杂的参数。

默认参数一定要用不可变对象,如果是可变对象,程序运行时会有逻辑错误!

要注意定义可变参数和关键字参数的语法:

*args是可变参数,args接收的是一个tuple;

**kw是关键字参数,kw接收的是一个dict。

以及调用函数时如何传入可变参数和关键字参数的语法:

可变参数既可以直接传入:func(1, 2, 3),又可以先组装list或tuple,再通过args传入:func((1, 2, 3));

关键字参数既可以直接传入:func(a=1, b=2),又可以先组装dict,再通过kw传入:func({‘a’: 1, ‘b’: 2})。

使用*args和**kw是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。

命名的关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。

定义命名的关键字参数在没有可变参数的情况下不要忘了写分隔符*,否则定义的将是位置参数。


默认情况下,dict迭代的是key。如果要迭代value,可以用for value in d.values(),如果要同时迭代key和value,可以用for k, v in d.items()


如果要对list实现类似Java那样的下标循环怎么办?Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身。如下:

for i, value in enumerate(['A', 'B', 'C']):
       print(i, value)

如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。
generator是一个生成器,主要用于数据的动态生成,比如如果我们需要10000个数,此时如果使用列表存起来将会浪费很多空间,因为在我们使用前面的数的时候后面的数并没有被使用,这就是浪费。此时如果使用generator,则只是在需要使用这个数的时候才存储,不需要的数暂时不存储。

generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。类似下面例子:

def eGenerator():
    for i in range(10):
        yield i


e = eGenerator()
print(e)   #单纯输出此变量知道该变量为generator类型
for i in e:
    print(i)

-打印:

>><generator object eGenerator at 0x000001F1961A37C8>
0
1
2
3
4
5
6
7
8
9

---

2020/04/27
可以使用isinstance()判断一个对象是否是Iterable对象。
所有的集合对象像list、tuple、dict、set、str都可以迭代,
同时generator生成器以及generator函数也可以迭代。
具体使用:如测试str是否可迭代:

>>>isinstance('abc', Iterable)
true

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
很显然,generator及generator函数是iterator对象,而其他的iterable对象不是iterator对象。
同样可以借助isinstance()来判断。
但是可以使用iter()函数将iterable对象转换为iterator对象。


Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
原因在于iterator对象只有在调用next()函数时才计算存储即将需要输出的值,也就是 可以有,但是没有调用next()之前没有必要233333333。
但是list这类不管要不要使用都要全部存下来。


函数本身也可以赋值给变量,即:变量可以指向函数。(与java很不同的地方)
如:

>>>f = abs
>>>f(-10)
10

此时变量f就起着abs函数的作用。可以看出函数名也是一个“指针”,指向函数体。
正是因为python的这种特性,因此python中可以将一个函数作为另一个函数的参数传入。此种方式编写的函数称为高阶函数。
接下来介绍一些典型的高阶函数:

①map()函数:
map()函数接受两个参数,第一个是一个函数名,第二个是一个iterable对象(像list等)。
并且会返回一个iterator对象。
举个栗子:

def f(x):
    return x*x

m = map(f,[1,2,3,4])

print(m)
print(list(m))

会依次返回:

<map object at 0x000001F19618BBC8>
[1, 4, 9, 16]

可以看出map函数会遍历传入的iterable参数的每一个元素并为每一个元素执行一次第一个参数对应的函数体。

②reduce()函数:
该函数需要传入的参数和map函数一样,但是功能不一样。
如果reduce(f,[x1,x2,x3,x4]):
= f(f(f(x1,x2),x3),x4)

最后结合map函数与reduce函数,构造一个将str转换为整数的函数:
#利用map以及reduce函数构造将str转换为int的函数

def fn(x,y):
    return x*10 + y

def str2int(s):
    digits = {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}
    return digits[s]

from functools import reduce

#//先使用map函数将str中的字符逐个转换,再通过reduce函数将map函数返回的iterator对象逐个使用fn函数。
#可以看出,map函数实际上是将iterable参数的元素逐个传入其函数名参数中。
#reduce函数实际上是使用一种类似构造哈夫曼数(只是不需要比较大小而已)的方法对传入的iterable参数进行函数名对应的函数操作。

res = reduce(fn,map(str2int,"1234"))

print(res)

③filter()函数:
和map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
#只保留奇数

def is_odd(n):
    return n%2 == 1
t = list(filter(is_odd,[1,2,3,4]))
print(t)
>>>[1,3]
#去掉空字符
def not_empty(s):
    return s and s.strip()

④sorted()函数:
用法与前面的有点点不同,参数为:sorted(iterable,key=函数名,reverse=True/False),第二、三个参数可省略。
此时使用key对应的函数来进行排序(如自定义的冒泡、快排等)。
举个栗子:

sorted([36, 5, -12, 9, -21], key=abs)

使用绝对值函数对列表进行排序。

#忽略大小写的排序:

sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)

#先按成绩排序再按名字排序

L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]

def by_name(t):
    return t[0]

def by_grade(t):
    return -t[1]
    
    
t = sorted(L,key = by_name)
t = sorted(t,key = by_grade)

从上面可以看出,sorted函数在排序时使用的key对应的排序方式与java中的compator一样,基本都是通过比较大小实现,并且根据返回的是0、-1、1来排序。


python中,函数的返回结果还是可以是另一个函数,一个函数内部可以定义内部函数,且内部函数可以使用外函数的参数以及局部变量,这种特征称为闭包。
如:

def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return sum

当我们调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数。
f1()和f2()的调用结果互不影响。

#利用闭包返回一个计数器函数,每次调用它返回递增整数:

def createCounter():
    f = 0
    def counter():
        nonlocal f
        f = f + 1
        return f
    return counter
#此时如果调用该函数,第一次调用返回1,第二次调用返回2,以此类推。
f1 = createCounter()
#print(f1(),f1(),f1(),f1())

#想要理解为什么会这样,就必须要抓住,
#闭包是在调用的时候才执行
#这里不是很好懂。
#可以这样去想,当我使用f1 = createCounter()这条语句时,实际上就可以理解为,
#我已经将外函数的部分写到环境中了,也就是将外函数“剥去了”,但是内部函数还是一个函数没有被调用,
#但是现在内函数已经暴露出来了,同时如果在内函数中会引用外函数的参数以及局部变量,可以看做编译器会自动将内函数内使用的参数及变量加上global,此时参数和变量就统一了。
#但是内函数还是没有执行,因为没有被调用。
#所以在上面的函数中,当使用f1()时,就是一次调用内函数的过程。而因为内函数内部使用了外函数的变量并在其内部定义为nonlocal,所以此时对变量f的修改会持久影响后面的调用(就像改变了一个全局变量一样,只不过这里的“全局”是外函数的全局,而不是整个文件的全局)。


再看匿名函数,使用lambda关键字来表示匿名函数:

lambda x: x * x实际上就是:
def f(x):
    return x * x

冒号前面的x表示函数参数。
用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数:
f = lambda x : x*x

此时f就是一个函数了
使用:f(2)就可以调用
这样相当于给匿名函数赋名
如下两种方式等值:

1.
def is_odd(n):
    return n % 2 == 1
2.
is_odd = lambda n : n%2==1

函数对象有一个__name__属性,可以拿到函数的名字。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值