SebastianOpa?czyński编译
弯月责编
张文出品
CSDN(ID:CSDNnews)在本文中,我们来看一看日常工作中经常使用的一些Python小技巧。集合开发人员常常忘记Python也有集合数据类型,大家都喜欢使用列表处理一切。集合(set)是什么?简单来说就是:集合是一组无序事物的汇集,不包含重复元素。如果你熟练掌握集合及其逻辑,那么很多问题都可以迎刃而解。举个例子,如何获取一个单词中出现的字母?
myword="NanananaBatman"set(myword){N,m,n,B,a,t}就这么简单,问题解决了,这个例子就来自Python的官方文档,大可不必过于惊讶。再举一个例子,如何获取一个列表的各个元素,且不重复?
#firstyoucaneasilychangesettolistandotherwayaroundmylist=["a","b","c","c"]#letsmakeasetoutofitmyset=set(mylist)#mysetwillbe:{a,b,c}#and,itsalreadyiterablesoyoucando:forelementinmyset:print(element)#butyoucanalsoconvertittolistagain:mynewlist=list(myset)#andmynewlistwillbe:[a,b,c]我们可以看到,“c”元素不再重复出现了。只有一个地方你需要注意,mylist与mynewlist之间的元素顺序可能会有所不同:
mylist=["c","c","a","b"]mynewlist=list(set(mylist))#mynewlistis:[a,b,c]可以看出,两个列表的元素顺序不同。下面,我们来进一步深入。假设某些实体之间有一对多的关系,举个更加具体的例子:用户与权限。通常,一个用户可以拥有多个权限。现在假设某人想要修改多个权限,即同时添加和删除某些权限,应当如何解决这个问题?
#thisisthesetofpermissionsbeforechange;original_permission_set={"is_admin","can_post_entry","can_edit_entry","can_view_settings"}#thisisnewsetofpermissions;new_permission_set={"can_edit_settings","is_member","can_view_entry","can_edit_entry"}#nowpermissionstoaddwillbe:new_permission_set.difference(original_permission_set)#whichwillresult:{can_edit_settings,can_view_entry,is_member}#Asyoucanseecan_edit_entryisinbothsets;sowedonotneed#toworryabouthandlingit#nowpermissionstoremovewillbe:original_permission_set.difference(new_permission_set)#whichwillresult:{is_admin,can_view_settings,can_post_entry}#andbasicallyitsalsotrue;weswitchedadmintomember,andadd#morepermissiononsettings;andremovedthepost_entrypermission总的来说,不要害怕使用集合,它们能帮助你解决很多问题,更多详情,请参考Python官方文档。日历当开发与日期和时间有关的功能时,有些信息可能非常重要,比如某一年的这个月有多少天。这个问题看似简单,但是我相信日期和时间是一个非常有难度的话题,而且我觉得日历的实现问题非常多,简直就是噩梦,因为你需要考虑大量的极端情况。那么,究竟如何才能找出某个月有多少天呢?
importcalendarcalendar.monthrange(,2)#willresult:(,3)#BUT!youneedtobecarefulhere,why?Letsreadthedocumentation:help(calendar.monthrange)#Helponfunctionmonthrangeinmodulecalendar:#monthrange(year,month)#Returnweekday(0-6~Mon-Sun)andnumberofdays(28-3)for#year,month.#Asyoucanseethefirstvaluereturnedintupleisaweekday,#notthenumberofthefirstdayforagivenmonth;letstry#togetthesameforcalendar.monthrange(,2)(2,3)#SothisbasicallymeansthatthefirstdayofDecemberisWed#andthelastdayofDecemberis3(whichisobvious,cause#Decemberalwayshas3days)#letsplaywithFebruarycalendar.monthrange(,2)(0,28)calendar.monthrange(2,2)(,28)calendar.monthrange(3,2)(2,28)calendar.monthrange(4,2)(3,29)calendar.monthrange(5,2)(5,28)#asyoucanseeithandlednicelytheleapyear;某个月的第一天当然非常简单,就是号。但是,“某个月的第一天是周X”,如何使用这条信息呢?你可以很容易地查到某一天是周几:
calendar.monthrange(4,2)(3,29)#meansthatFebruary4startsonThursday#letsdefinesimplehelper:weekdays=["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]#nowwecandosomethinglike:weekdays[3]#willresultin:Thursday#nowsimplemathtotellwhatdayis5thofFebruary:offset=3#itsthefirstvaluefrommonthrangefordayinrange(,29):print(day,weekdays[(day+offset-)%7])Thursday2Friday3Saturday4Sunday...8Sunday9Monday20Tuesday2Wednesday22Thursday23Friday24Saturday...28Wednesday29Thursday#whichbasicallymakessense;也许这段代码不适合直接用于生产,因为你可以使用datetime更容易地查找星期:
fromdatetimeimportdatetimemydate=datetime(4,2,5)datetime.weekday(mydate)#willresult:3#or:datetime.strftime(mydate,"%A")Thursday总的来说,日历模块有很多有意思的地方,值得慢慢学习:
#checkingifyearisleap:calendar.isleap()#Falsecalendar.isleap(4)#True#orcheckinghowmanydayswillbeleapdaysforgivenyearspan:calendar.leapdays(,6)#calendar.leapdays(,6)#2#readthehelphere,asrangeis:[y,y2),meaningthatsecond#yearisnotincluded;calendar.leapdays(,4)#枚举有第二个参数是的,枚举有第二个参数,可能很多有经验的开发人员都不知道。下面我们来看一个例子:
mylist=[a,b,d,c,g,e]fori,iteminenumerate(mylist):print(i,item)#Willgive:0ab2d3c4g5e#but,youcanaddastartforenumeration:fori,iteminenumerate(mylist,6):print(i,item)#andnowyouwillget:6a7b8d9c20g2e第二个参数可以指定枚举开始的地方,比如上述代码中的enumerate(mylist,6)。如果你需要处理偏移量,则可以考虑这个参数。if-else逻辑你经常需要根据不同的条件,处理不同的逻辑,经验不足的开发人员可能会编写出类似下面的代码:
OPEN=IN_PROGRESS=2CLOSED=3defhandle_open_status():print(Handlingopenstatus)defhandle_in_progress_status():print(Handlinginprogressstatus)defhandle_closed_status():print(Handlingclosedstatus)defhandle_status_change(status):ifstatus==OPEN:handle_open_status()elifstatus==IN_PROGRESS:handle_in_progress_status()elifstatus==CLOSED:handle_closed_status()handle_status_change()#Handlingopenstatushandle_status_change(2)#Handlinginprogressstatushandle_status_change(3)#Handlingclosedstatus虽然这段代码看上去也没有那么糟,但是如果有20多个条件呢?那么,究竟应该怎样处理呢?
fromenumimportIntEnumclassStatusE(IntEnum):OPEN=IN_PROGRESS=2CLOSED=3defhandle_open_status():print(Handlingopenstatus)defhandle_in_progress_status():print(Handlinginprogressstatus)defhandle_closed_status():print(Handlingclosedstatus)handlers={StatusE.OPEN.value:handle_open_status,StatusE.IN_PROGRESS.value:handle_in_progress_status,StatusE.CLOSED.value:handle_closed_status}defhandle_status_change(status):ifstatusnotinhandlers:raiseException(fNohandlerfoundforstatus:{status})handler=handlers[status]handler()handle_status_change(StatusE.OPEN.value)#Handlingopenstatushandle_status_change(StatusE.IN_PROGRESS.value)#Handlinginprogressstatushandle_status_change(StatusE.CLOSED.value)#Handlingclosedstatushandle_status_change(4)#Willraisetheexception在Python中这种模式很常见,它可以让代码看起来更加整洁,尤其是当方法非常庞大,而且需要处理大量条件时。enum模块enum模块提供了一系列处理枚举的工具函数,最有意思的是Enum和IntEnum。我们来看个例子:
fromenumimportEnum,IntEnum,Flag,IntFlagclassMyEnum(Enum):FIRST="first"SECOND="second"THIRD="third"classMyIntEnum(IntEnum):ONE=TWO=2THREE=3#Nowwecandothingslike:MyEnum.FIRST#MyEnum.FIRST:first#ithasvalueandnameattributes,whicharehandy:MyEnum.FIRST.value#firstMyEnum.FIRST.name#FIRST#additionallywecandothingslike:MyEnum(first)#MyEnum.FIRST:first,getenumbyvalueMyEnum[FIRST]#MyEnum.FIRST:first,getenumbyname使用IntEnum编写的代码也差不多,但是有几个不同之处:
MyEnum.FIRST=="first"#False#butMyIntEnum.ONE==#True#tomakefirstexampletowork:MyEnum.FIRST.value=="first"#True在中等规模的代码库中,enum模块在管理常量方面可以提供很大的帮助。enum的本地化可能有点棘手,但也可以实现,我用django快速演示一下:
fromenumimportEnumfromdjango.utils.translationimportgettext_lazyas_classMyEnum(Enum):FIRST="first"SECOND="second"THIRD="third"
classmethoddefchoices(cls):return[(cls.FIRST.value,_(first)),(cls.SECOND.value,_(second)),(cls.THIRD.value,_(third))]#Andlaterineg.modeldefiniton:some_field=models.CharField(max_length=0,choices=MyEnum.choices())iPythoniPython就是交互式Python,它是一个交互式的命令行shell,有点像Python解释器。首先,你需要安装iPython:pipinstallipython接下来,你只需要在输入命令的时候,将Python换成ipython:
#youshouldseesomethinglikethisafteryoustart:Python3.8.5(default,Jul28,2:59:40)Typecopyright,creditsorlicenseformoreinformationIPython7.8.--AnenhancedInteractivePython.Type?forhelp.In[]:ipython支持很多系统命令,比如ls或cat,tab键可以显示提示,而且你还可以使用上下键查找前面用过的命令。更多具体信息,请参见官方文档。参考链接: