日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

python粘性拓展_Python基础之:拓展解决问题的思路

發布時間:2023/11/27 生活经验 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python粘性拓展_Python基础之:拓展解决问题的思路 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

0、錘子原理

在手里拿著一把錘子的人眼中,世界就像一根釘子。

大多人試圖以一種思維模型來解決問題,而其思維往往只來自某一專業學科,

但你必須知道各種重要學科的重要理論。

一一《窮查理寶典》

在過去十年的工作中,我經常看到一些不可思議的代碼,這些代碼有時候看起來相當的愚蠢。而且大部分時候,這些代碼都有非常簡單而高效的替代方案。而寫出這些代碼的人,往往是因為沒有掌握相關的基礎知識,或者是因為總是用一個思路去解決問題,形成了思維慣性。

要巧妙地解決某些問題,有時候可能需要掌握非常專業和生僻的知識;但大部分時候,你只需要掌握一些非?;A的知識,和一個拓展性的思維。

本文皆在拋磚引玉,用非?;A的Python知識,用不同的思路巧妙地解決相似的問題。

1、判定元素是否存在

在列表在查找一個元素,判定元素是否存在,是一個相當常見的操作。

在貫穿本小節的所有例子中,我們都是為了查找符合某個條件的元素是否存在。如果存在,則做dealWhenFound操作;如果不存在,則做dealWhenNotFound操作。后文中用到這兩個函數,我們將直接使用,不再進行聲明。

def dealWhenFound(elem):

# 如果元素找到了,做點什么

print("{}is found".format(elem))

def dealWhenNotFound(elem):

# 如果元素沒有找到,做點什么

print("{}is not found".format(elem))

假如我們有一個名字列表,現在需要在其中查找某個元素是否存在。通用我們可以這么做:

names = ["Jim", "Tom", "Mary", "Hugo", "Tim", "John", "Alby"]

is_found = False

target = "Tom"

is_found = False

for name in names:

if name == target:

is_found = True

break

if is_found:

dealWhenFound(target)

else;

dealWhenNotFound(target)

這是一份通用可行且非常樣板式的代碼。但在Python中,我們有更加高效且解決方案。正如本小節的標題所述的,用in關鍵字就可以了。

if name in names:

dealWhenFound(target)

else:

dealWhenNotFound(target)

in操作符是用來判定一個元素是否存在一個可迭代對象中(list、tuple、dict、set等)。對于這種查找條件比較簡單的搜索,思路就是這么簡單,甚至不值得一提。但對于稍微復雜一點的查找條件,in就不那么勝任了。

我們把查找條件修改為:判定是否存在以某個字母開頭的名字。這個時候,我們就沒有辦法用in操作符來直接判定了。我們發現反而是第1份for代碼,才能更好地解決我們的問題。

prefix = "J"

is_found = False

for name in names:

if name.startswith(prefix): # 判定name是否以J開頭

is_found = True

break

if is_found:

dealWhenFound(prefix)

else;

dealWhenNotFound(prefix)

Python考慮到了這種情況的普遍性,為我們提供了for/else結構。

for iter in a_list:

if some_test(iter):

break

else:

# 如果循環結果,且沒有break語句被執行,則else塊會被執行

在for/else結構中,如果for循環正常結束(即沒有break語句被執行),則else下的代碼會被執行;否則else下的代碼不會被執行。

利用這個特性,我們可以將代碼進行如下的優化:

prefix = "J"

for name in names:

if name.startswith(prefix): # 判定name是否以J開頭

dealWhenFound(prefix)

break

else:

dealWhenNotFound(prefix)

如果你知道any函數,那你應該知道這份代碼還會優化的空間。any函數接受一個可迭代對象(包括生成器)做為參數,并且只要任意一個元素被判定為True,則返回True。配合map,我們的代碼可以進一步地簡化:

prefix = "J"

if any(map(lambda name: name.startswith(prefix), names)):

dealWhenFound(prefix)

else:

dealWhenNotFound(prefix)

如果你覺得上面這份代碼不好理解,我們可以進行拆解。

test_func = lambda name: name.startswith(prefix)

map_obj = map(test_func, names)

if any(map_obj):

dealWhenFound(prefix)

else:

dealWhenNotFound(prefix)

除了本小節用到的一些關鍵字和函數之外,Python也為我們提供了很多其它便利。在這里我們列舉一些比較常用的,但不再深入介紹用法。

in

any

all

for/else

map

reduce

filter

enumerate

zip

2、頻數統計

在實際開發過程,統計是另一個常見的需求。

還是以名字列表為例,將首字母相同的名字放在同一個分組(列表)里邊。我們很容易想到使用dict數據結構:用首字母做為key,以一個list對象做為value即可。

names = ["Jim", "Tom", "Mary", "Hugo", "Tim", "John", "Alby", "Abigal", "Hamish", "Jeremy"]

groups = dict()

for name in names:

key = name[0]

if key in groups:

groups[key].append(name)

else:

g = [name]

groups[key] = g

使用dict的setdefault函數,上面這段代碼可以進行簡化:

for name in names:

key = name[0]

groups.setdefault(key, []).append(name)

d.setdefault(key, dft_val)的操作是,檢測key是否存在,如果存在則返回value;如果不存在,則將dft_val存儲到d[key],并返回dft_val。在上面的例子中, 我們在dict中存儲了list對象,所以我們可以通過鏈式調用,在一行代碼里完成比較復雜的操作。

到目前為止,一切都簡單到不值得一提。但如果我們把分組的需求改為,編者首字母相同的名字的個數,那就是另一個情況了。這時候dict的value類型是int,我們不可以進行簡單的鏈式操作,所以使用setdfault也就不存在優勢了。一個比較直觀的實現,還是對第一段代碼進行簡單的改造:

names = ["Jim", "Tom", "Mary", "Hugo", "Tim", "John", "Alby", "Abigal", "Hamish", "Jeremy"]

groups = dict()

for name in names:

key = name[0]

if key in groups:

groups[key] += 1

else:

groups[key] = 1

或者使用get函數來簡化代碼:

for name in names:

key = name[0]

val = groups.get(key, 0)

groups[key] = val + 1

對于集合類型的操作,Python提供了一個更加高效便捷的庫collections。利用collections,我們可以對代碼進行進一步的簡化:

import collections

names = ["Jim", "Tom", "Mary", "Hugo", "Tim", "John", "Alby", "Abigal", "Hamish", "Jeremy"]

groups = collections.defaultdict(int)

for name in names:

groups[name[0]] += 1

collections.Counter類為我們提供了統計列表(可迭代對象)元素數量的便利,配合列表解析表達式(list comprehension),我們可以用一行代碼就完成統計的操作。

import collections

names = ["Jim", "Tom", "Mary", "Hugo", "Tim", "John", "Alby", "Abigal", "Hamish", "Jeremy"]

groups = collections.Counter(name[0] for name in names)

print(groups)

# 打印結果:

# Counter({'J': 3, 'T': 2, 'H': 2, 'A': 2, 'M': 1})

collections為我們提供了更容易使用的容器類型(如list、tuple、dict等)的子類及其它一些便利。本文只是拋磚引玉,并不打算深入介紹collections的用法。在閱讀本文之后,各位讀者可自行深入學習。以下兩個鏈接都來自Python官方文檔,第一個是英文鏈接,第二個是中文鏈接。8.3. collections - High-performance container datatypes - Python 2.7.18 documentation?docs.python.orghttps://docs.python.org/zh-cn/3/library/collections.html?docs.python.org

3、多次條件判定

我們經常會遇到一種情況,在執行特定操作之前,往往需要通過多次的條件判定。只有在所有的條件都滿足的情況下,才會進行目標操作。

有一個改名的需要求,只有當名字滿足一系列的條件,才可以對名字進行更改;否則提示改名失敗的原因。名字需要滿足的一系列條件是:

1、長度不得大于10

2、只包含26個英文字母

3、有且只有首字母大寫,其它字母都是小寫

4、最后一個字母必須是元音字母

我們先為各種判定結果定義一些常量,方便后面使用:

# Python沒有enum類型,我們可以通過class來模擬

class EAlterRet:

Succ = 0,

SizeOutOfRange = 1,

InvalidCharacter = 2,

NotCapitalized = 3,

EndWithConsonant = 4,

AlterNameErrors = (

"Succ", # 成功

"SizeOutOfRange", # 太長

"InvalidCharacter", # 非法字符

"NotCapitalized", # 非首字母大寫的

"EndWithConsonant", # 未以元音字母結尾

)

第一個實現方式,也就是最容易想到的實現方式,自然是多個if語句了。

import re

class Human:

def __init__(self, name):

self.name = name

def dealWithErrors(self, target, code):

ret = AlterNameErrors[code]

msg = "Alter name to '{}', result:{}".format(target, ret)

print(msg)

def alterName(self, target):

# 長度是否大于10

if len(target) > 10:

self.dealWithErrors(target, EAlterRet.SizeOutOfRange)

return

# 是否存在非法字符

if re.search(r'[^a-zA-z]', target):

self.dealWithErrors(target, EAlterRet.InvalidCharacter)

return

# 是否有且只有首字母大寫

if target.lower().capitalize() != target:

self.dealWithErrors(target, EAlterRet.NotCapitalized)

return

# 是否以無意結尾

if not re.search(r'[AEIOUaeiou]$', target):

self.dealWithErrors(target, EAlterRet.EndWithConsonant)

return

# 改名成功

self.name = target

第二種方式是使用類似于do/while(false)的結構。由于Python沒有do/while(false)結構,我們可以使用一次for循環來替換。

import re

class Human:

def __init__(self, name):

self.name = name

def alterName(self, target):

error = EAlterRet.Succ

for i in range(0, 1):

if len(target) > 10:

error = EAlterRet.SizeOutOfRange

break

if re.search(r'[^a-zA-z]', target):

error = EAlterRet.InvalidCharacter

break

if target.lower().capitalize() != target:

error = EAlterRet.NotCapitalized

break

if not re.search(r'[AEIOUaeiou]$', target):

error = EAlterRet.EndWithConsonant

break

if error == EAlterRet.Succ: # 條件滿足,改名成功

self.name = target

else: # 條件不滿足,處理錯誤

ret = AlterNameErrors[code]

msg = "Alter name to '{}', result:{}".format(target, ret)

print(msg)

使用for/break的好處是,我們可以把錯誤放到后面統一處理,避免使用重復的錯誤處理代碼。

第三種方式是得用異常。雖然我們這個例子引入異常有點牽強,但舉一反三,各位讀者在以后的實際開發過程中,就可以多一個思路。

import re

class Human:

def __init__(self, name):

self.name = name

def alterName(self, target):

error = EAlterRet.Succ

try:

if len(target) > 10:

raise Exception(EAlterRet.SizeOutOfRange)

if re.search(r'[^a-zA-z]', target):

raise Exception(EAlterRet.InvalidCharacter)

if target.lower().capitalize() != target:

raise Exception(EAlterRet.NotCapitalized)

if not re.search(r'[AEIOUaeiou]$', target):

raise Exception(EAlterRet.EndWithConsonant)

expect Exception as ex:

ret = AlterNameErrors[ex.args[0]]

msg = "Alter name to '{}', result:{}".format(target, ret)

print(msg)

else:

self.name = target

finally: # 如果有需要的話,可以有finally語句

# 做點別的什么事情

在不考慮效率的情況下,使用異常應該是三種方式中最簡潔的方式。使用異常還有一個好處,就是可以在finally中做點別的什么事件。因為無論try中有raise還是有return,finally的語句總是會被執行。也就是說,無論發生什么情況,我們總是可以在finally做一些清理工作,如關閉之前打開的文件、關閉socket、或者打一些日志……

4、猜猜看

猜猜下面的這段代碼中,構造函數做了些什么。請在評價區中進行留言和討論 。

class FancyConstructor:

def __init__(self, a, b, c, d, e, f, g):

self.__dict__.update({k: v for k, v in locals().items() if k != 'self'})

總結

以上是生活随笔為你收集整理的python粘性拓展_Python基础之:拓展解决问题的思路的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。