11 Pythonic与Python杂记之一


目录

  • 用字典映射代替其他语言中switch case 语句
  • 列表推导式
  • None的特殊性与误区
  • 自定义对象与bool的对应关系
  • 装饰器的副作用
  • 编程能力
  • 海象运算符
  • 用f关键字做字符串拼接
  • 装饰器:@dataclass数据类

以前章节主打基础知识,目的是让你具备不断学习、更新知识体系的能力。这要远远好于把所有知识点罗列出来。

本章节没有主线,只是关于上述主线章节的零碎升级、补充。
毕竟,好的产品,是打磨出来的,没有一蹴而就。这里的产品,不只是app、网站,还包括课程、项目。

七月老师:
虽然是谋生手段,但兴趣爱好,却是具有更加强大的力量。这是件很幸福的事情。

一、用字典映射代替switch case 语句

1.其他语言的switch case 语句

关于条件分支语句,其他语言是用switch case 语句。例如,C#中:

switch(day)
{
    case 0 :
    dayname = "Sunday";
    break;

    case 1 :
    dayname = "Monday";
    break;

    case 2 :
    dayname = "Tuesday";
    break;
    ...
    default :
    dayname = "Unknown";
    break;
}

python中,官方建议可以用if else代替上述语句。
但是,老师认为不合适。
因为其他语言中也有if else,如果能代替,为什么还要多出个switch case语句呢?只有if else不就可以了吗?

因此,老师的建议是,用字典映射来代替其它语言中的switch case语句,更简洁、好用。

2.字典映射

day = 0        #定义一个变量,目的是接受下标数值
switcher = {
    0 : 'Sunday',
    1 : 'Monday',
    2 : 'Tuesday',
}

dayname = switcher[day]      #使用下标,来访问字典
print(dayname)

-->
Sunday

day = 2时,结果是什么?

day = 2        #变量被重新赋值为2
switcher = {
    0 : 'Sunday',
    1 : 'Monday',
    2 : 'Tuesday',
}

dayname = switcher[day]      
print(dayname)

-->
Tuesday

day = 6时,结果是什么?

day = 6        #变量被重新赋值为6
switcher = {
    0 : 'Sunday',
    1 : 'Monday',
    2 : 'Tuesday',
}

dayname = switcher[day]      
print(dayname)

-->
error ❌     #因为字典switcher中,找不到key=6的元素

3.用内置get函数来访问字典

当变量的值,超出了字典中的key范围时,就必须换一种字典的访问方式。
即,内置的get方法,来访问字典。

day = 6        #变量被重新赋值为6
switcher = {
    0 : 'Sunday',
    1 : 'Monday',
    2 : 'Tuesday',
}

dayname = switcher.get(day,'Unknown')    #内置的`get`函数
             # Unknown:指定当day对应的key不存在时,函数调用将返回的结果  
print(dayname)

-->
Unknown

上述利用内置函数get,并补上Unknown,本质上,就是在模拟其他语言中switch case语句里的default分支。

两种字典访问方式对比

通过下标访问用内置函数get访问
优点简单、直接有容错性

4.函数编程融入字典映射

上述字典中的value,只是个字符串,顶多是个lambda表达式。
而,我们知道,其他语言switch case中的case下面,是可以写代码块、写很多行的。
那么,python中的字典又如何模拟呢?

其实,key对应的value不只是字符串,也可以是函数。这跟函数式编程思维中的将函数赋值给变量是一个道理。

day = 0

def get_sunday():       #先定义,后调用
    return 'Sunuday'
def get_monday():
    return 'Monday'
def get_tuesday():
    return 'Tuesday'

switcher = {
    0 : get_sunday,     # key对应的value也可以是函数(名)
    1 : get_monday,
    2 : get_tuesday,
}

dayname = switcher.get(day,'Unknown')()  #因为从字典switcher中,得到的key所对应的value,是函数名。所以要加个小括号()方能调用执行   
print(dayname)

-->
Sunuday
day = 6

def get_sunday():       #先定义,后调用
    return 'Sunuday'
def get_monday():
    return 'Monday'
def get_tuesday():
    return 'Tuesday'

switcher = {
    0 : get_sunday,     # key对应的value也可以是函数(名)
    1 : get_monday,
    2 : get_tuesday,
}

dayname = switcher.get(day,'Unknown')()   
print(dayname)

-->
error ❌    #在get函数中,默认值是'Unknown',即字符串str型。不是函数名!因为Unknown()没意义

为了解决上述问题,应该对默认值的情况,重新定义一个函数。

因为,字典中的value值都用的是函数,所以建议默认值也要用函数。

day = 6

def get_sunday():       
    return 'Sunuday'      #这里只是返回了字符串常量。真正写业务,是可以有很多的逻辑的
def get_monday():
    return 'Monday'
def get_tuesday():
    return 'Tuesday'
def get_default():      #重新定义一个返回默认值的函数
    return 'Unknown'

switcher = {
    0 : get_sunday,     
    1 : get_monday,
    2 : get_tuesday,
}

dayname = switcher.get(day,get_default)()    #这里的get_default,是默认情况下的函数名
print(dayname)

-->
Unknown
七月老师:
其他语言中的switch case下,也是不建议写很多的业务逻辑的,应该是写个方法,case只是调用这个方法。
具体的业务逻辑应该写在方法内部,而不是直接写在case语句下面。

二、列表推导式

叫法很奇怪,其本质跟数学中的集合推导式是一样的。
具有python特色,很pythonic。因为简洁优雅,其他语言中没有。
用途:根据已有的列表,创建一个新的列表。

1.例题
将列表[1,2,3,4,6,7,8,]中的每个元素,都做平方,得到一个新的列表?

(1)写法1:
使用之前的for循环控制语句,进行遍历

a = [1,2,3,4,6,7,8]
b = []         #定义一个空列表,以接受新的列表元素

for x in a:
    b.append(x*x)      #⭐使用内置函数append(),将新的列表元素添加到列表b中

print(b)

-->
[1, 4, 9, 16, 36, 49, 64]

(2)写法2:
只用高阶函数中的map函数,也能遍历

a = [1,2,3,4,6,7,8]
r = map(lambda x:x*x,a)
print(list(r))

-->
[1, 4, 9, 16, 36, 49, 64]

(3)写法3:
使用列表推导式

a = [1,2,3,4,6,7,8]
b = [x*x for x in a]     #结构:How怎么算  Who算谁     #里面是个for循环,但又不是真的for循环
print(b)

-->
[1, 4, 9, 16, 36, 49, 64]

上述的列表推导式,本质上其实就是对写法1的简化。

小知识点:
平方运算,不止可以写为x*x,还可以x**2。后者的指数运算很方便,因为当100个x相乘时,就直接x**100

七月老师:
如果是对列表中的全部元素进行操作,那么其实用map函数更好用。因为其他语言中也都有,用习惯了。

2.推荐的使用场景

当对非全部元素进行操作,即有选择性的操作时,比较方便。

例题

将列表[1,2,3,4,6,7,8,]中的每个大于等于5的元素,都做平方,得到一个新的列表?

写法1:
使用高阶函数中的filter函数

a = [1,2,3,4,6,7,8]
r = filter(lambda x:x*x if x>=5 else None,a)
print(list(r))

-->
[6, 7, 8]     # ?

写法2:
使用列表推导式

a = [1,2,3,4,6,7,8]
b = [x*x for x in a if x >=5]     #只要加个条件筛选即可
print(b)

-->
[36, 49, 64]

3.常见误区
虽然叫列表推导式,但是,不只是能推到列表。
还可以推导集合set、元组tuple、字典dic。

(1)“集合推导式”

a = {1,2,3,4,6,7,8}            #集合
b = [x*x for x in a if x >=5]    
     #因为这里的中括号[],并不是列表推导式的固定字符。如果想得到集合,那么这里就应该是集合符合{}
print(b)

-->
[36, 49, 64]        #结果仍是列表

改为:

a = {1,2,3,4,6,7,8}            #集合
b = {x*x for x in a if x >=5}     #列表推导式的符号改为集合符号{}
    
print(b)

-->
{64, 49, 36}       #结果是集合

(2)“字典推导式”

例题1:
将字典{'喜小乐':18,'石敢当':20,'横小五':15}中的key提取出来,单独制成一个列表?

students = {
    '喜小乐':18,
    '石敢当':20,
    '横小五':15
}

b = [key for key,value in student]   #列表一个形参即可,但字典因为有键值对,必须两个形参
print(b)

-->
error ❌    #字典不能直接被for in循环遍历

通过调用字典的items()方法,来取出很多条目中的一个:

students = {
    '喜小乐':18,
    '石敢当':20,
    '横小五':15
}

b = [key for key,value in student.items()]  
print(b)

-->
['喜小乐', '石敢当', '横小五']   

例题2:
将字典{'喜小乐':18,'石敢当':20,'横小五':15}中的key与value位置颠倒,制成一个新的字典?

students = {
    '喜小乐':18,
    '石敢当':20,
    '横小五':15
}

b = {value:key for key,value in students.items()}   #这里的推导式符号是字典符号{},因为得到的是一个字典
print(b)

-->
{18: '喜小乐', 20: '石敢当', 15: '横小五'}

(3)“元组推导式”

推导式符号,变为中括号时:

students = {
    '喜小乐':18,
    '石敢当':20,
    '横小五':15
}

b = (key for key,value in students.items())     #推导式符号改为元组  #前面只能是key
print(b)

-->
<generator object <genexpr> at 0x0000022569729930>    #得到的不是元组,而是可遍历的对象generator
students = {
    '喜小乐':18,
    '石敢当':20,
    '横小五':15
}

b = (key for key,value in students.items())     
for x in b:
    print(x)

-->
喜小乐
石敢当
横小五

之所以元组会出现这样一个情况:得到一个generator对象,是因为元组是不可变的,它很多行为和列表等一些典型的可变的是有区别的。

声明:Jerry's Blog|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - 11 Pythonic与Python杂记之一


Follow excellence, and success will chase you.