讲讲python“=”运算符上的优雅语法
心路历程:
之前学linux,虽然学的行算不错,不过总感觉差了点什么,自己找不到也说不出来;直到有一天我看到别人mount上了一个普通文件;
当时给我的感觉这太不可思议了,这个文件又不是块设备;后来脑子里突然想到一句话“一切些文件”,一身的冷汉;原来这个就是linx
的哲学它不是一句口号!它是linux这门武功的上乘心法。 linux我顿悟了。
昨天夜里看python看到一句话“python语言最好的品质之一是一致性”;这种高度的一致性来自于哪里?我想应该是针对某一特定的
问题在python中“最优解只有一个”的原因。
从赋值语句看语言的一致性:
赋值语句每一门语言都有不过python真的是玩出了新的高度,下面上干货。
1、常规赋值与其它语言没区别
if __name__ == "__main__": name = "蒋乐哥哥" age = "16" major = "软件工程" job = "dba" print("{} ,{} ,{} ,{}".format(name,age,major,job))
2、玩法1): 序列赋值
if __name__ == "__main__": #name = "蒋乐哥哥" #age = "16" #major = "软件工程" #job = "dba" name,age,major,job = "蒋乐哥哥","16","软件工程","dba" #是不是感觉自己平时不会这样写、也感觉不到这样写有什么好处、别急我们看一下它的变种 1 name,age,major,job = ("蒋乐哥哥","16","软件工程","dba") #事实上这个变种是比较常用的,用于取出可迭代对象中的各个值、别急它还可以再变 name,age,major,job,*ignore =("蒋乐哥哥","16","软件工程","dba","才华横溢","日进斗金","心地善良") print("name={} ,age={} ,major={} ,job={}".format(name,age,major,job)) print("ignore={}".format(ignore)) #输出如下:name=蒋乐哥哥 ,age=16 ,major=软件工程 ,job=dba #输出如下:ignore=['才华横溢', '日进斗金', '心地善良']
可以看到对于我们不关注的数据直接被*ignore接收了,但是高手之间出于对一致性的追求,通常不会用ignore这个变量,而是这样写
name,age,major,job,*_ =("蒋乐哥哥","16","软件工程","dba","才华横溢","日进斗金","心地善良") print("name={} ,age={} ,major={} ,job={}".format(name,age,major,job)) print("ignore={}".format(_))
他们对于用不到的数据通常是给一个“_”变量来保存的;也许你还是感觉这面的写法没有意义,太学院派了;那么下面我们来写一个有意义
的程序,用它来分析linux系统的/etc/passwd文件,这个文件保存的是linux中的用户信息,其中第一列是用户名,最后一列是这个用户对应
的shell。我们这个程序的目的就是取出用户名和它对应的shell,下面是我电脑上的一份。
root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt mail:x:8:12:mail:/var/spool/mail:/sbin/nologin operator:x:11:0:operator:/root:/sbin/nologin games:x:12:100:games:/usr/games:/sbin/nologin ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin nobody:x:99:99:Nobody:/:/sbin/nologin systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin dbus:x:81:81:System message bus:/:/sbin/nologin polkitd:x:999:997:User for polkitd:/:/sbin/nologin postfix:x:89:89::/var/spool/postfix:/sbin/nologin sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin chrony:x:998:996::/var/lib/chrony:/sbin/nologin uwsgi:x:1000:1000::/home/uwsgi:/bin/bash nginx:x:1001:1001::/home/nginx:/bin/bash
想好怎么写了吗?我的代码输出是这样的
python3 main.py root /bin/bash bin /sbin/nologin daemon /sbin/nologin adm /sbin/nologin lp /sbin/nologin sync /bin/sync shutdown /sbin/shutdown halt /sbin/halt mail /sbin/nologin operator /sbin/nologin games /sbin/nologin ftp /sbin/nologin nobody /sbin/nologin systemd-network /sbin/nologin dbus /sbin/nologin polkitd /sbin/nologin postfix /sbin/nologin sshd /sbin/nologin chrony /sbin/nologin uwsgi /bin/bash nginx /bin/bash
然而我的代码是这样的
if __name__=="__main__": with open('/etc/passwd') as passwd: for line in passwd: name,*_,shell = line.split(':') print(name,shell,end='')
上面的代码只是活用了Python的“赋值”代码量就大大减少了。
3、玩法2): 参数传递
参数传递也是“赋值”的另一种形式,但是这两种形式是统一的;下面也用一个学院派的例子来举例。假设我们有如下记录
oprations = [ ('add',1,2), ('add',2,3), ('sub',3,2), ('sub',1,1) ]
第一个字段代表要执行的操作,后面两个字段是操作的参数;也就是说第一个记录的意思就是计算1+2,第三条记录的意思就是计算3-2;
写个加减法并不难! 先来看一下代有C#口音的写法
def add(a,b): print("{} + {} = {} ".format(a,b,a+b)) def sub(a,b): print("{} - {} = {} ".format(a,b,a-b)) if __name__ == "__main__": oprations = [ ('add',1,2), ('add',2,3), ('sub',3,2), ('sub',1,1) ] for op in oprations: if op[0]=='add': add(op[1],op[2]) elif op[0]=='sub': sub(op[1],op[2])
看起来没有什么问题,型参通过对op[]索引操作来完成,想想这是天经地义的;看一下pythonic的写法吧
def add(a,b): print("{} + {} = {} ".format(a,b,a+b)) def sub(a,b): print("{} - {} = {} ".format(a,b,a-b)) if __name__ == "__main__": oprations = [ ('add',1,2), ('add',2,3), ('sub',3,2), ('sub',1,1) ] for op,*args in oprations: if op =='add': add(*args) elif op =='sub': sub(*args)
后都更加的“优雅”,“灵活”;优雅源自于不要再去关心索引,而是直接就能看出参数是怎么传递的;灵活吗?我们再调整一下需求
“要求add,sub支持三个数据相加减,或两个数据相加减”
def add(a,b,c=0): print("{} + {} + {} = {} ".format(a,b,c,a+b+c)) def sub(a,b,c=0): print("{} - {} - {} = {} ".format(a,b,c,a-b-c)) if __name__ == "__main__": oprations = [ ('add',1,2,1), ('add',2,3), ('sub',3,2,1), ('sub',1,1) ] for op,*args in oprations: if op =='add': add(*args) elif op =='sub': sub(*args)
由于pythonic的方式并没有用到索引,所以在调用方完全不要改,只要改一下sub和add的定义就好了,就能同时直接两参数,三参数了;
而使用索引是做不到的!所以呀编码的时候要尽可能的pythonic不要有过多的口音。
------