讲讲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不要有过多的口音。

 

 

 

  

 

  

 

 

 

 

 

------

posted on 2018-04-18 16:18  蒋乐兴的技术随笔  阅读(404)  评论(0编辑  收藏  举报

导航