騰龍?jiān)诰€開戶——SKSKFC
python 3.10支持match語句,3,10以下不支持。
match語句接受一個(gè)表達(dá)式,并將其值與作為一個(gè)或多個(gè)case塊給出的連續(xù)模式進(jìn)行比較。這表面上類似于C、Java或JavaScript(以及許多其他語言)中的switch語句,但更類似于Rust或Haskell等語言中的模式匹配。只有第一個(gè)匹配的模式才會被執(zhí)行,它還可以將值中的組件(序列元素或?qū)ο髮傩裕┨崛〉阶兞恐小?/p>
最簡單的形式是將一個(gè)目標(biāo)值與一個(gè)或多個(gè)字面值進(jìn)行比較:
def
http_error(status):
????
match status:
????????
case
400
:
????????????
return
"Bad request"
????????
case
404
:
????????????
return
"Not found"
????????
case
418
:
????????????
return
"I'm a teapot"
????????
case _:
????????????
return
"Something's wrong with the internet"
注意最后一個(gè)代碼塊:“變量名” _ 被作為 通配符 并必定會匹配成功。 如果沒有 case 語句匹配成功,則不會執(zhí)行任何分支。
使用 | (“ or ”)在一個(gè)模式中可以組合多個(gè)字面值:
case
401
|
403
|
404
:
????
return
"Not allowed"
模式的形式類似解包賦值,并可被用于綁定變量:
# point is an (x, y) tuple
match point:
????
case (
0
,
0
):
????????
print
(
"Origin"
)
????
case (
0
, y):
????????
print
(f
"Y={y}"
)
????
case (x,
0
):
????????
print
(f
"X={x}"
)
????
case (x, y):
????????
print
(f
"X={x}, Y={y}"
)
????
case _:
????????
raise
ValueError(
"Not a point"
)
請仔細(xì)研究此代碼! 第一個(gè)模式有兩個(gè)字面值,可以看作是上面所示字面值模式的擴(kuò)展。但接下來的兩個(gè)模式結(jié)合了一個(gè)字面值和一個(gè)變量,而變量 綁定 了一個(gè)來自目標(biāo)的值(point)。第四個(gè)模式捕獲了兩個(gè)值,這使得它在概念上類似于解包賦值 (x, y) = point。
如果使用類實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu),可在類名后加一個(gè)類似于構(gòu)造器的參數(shù)列表,這樣做可以把屬性放到變量里:
class
Point:
????
x:
int
????
y:
int
?
?def
where_is(point):
????
match point:
????????
case Point(x
=
0
, y
=
0
):
????????????
print
(
"Origin"
)
????????
case Point(x
=
0
, y
=
y):
????????????
print
(f
"Y={y}"
)
????????
case Point(x
=
x, y
=
0
):
????????????
print
(f
"X={x}"
)
????????
case Point():
????????????
print
(
"Somewhere else"
)
????????
case _:
????????????
print
(
"Not a point"
)
可在 dataclass 等支持屬性排序的內(nèi)置類中使用位置參數(shù)。還可在類中設(shè)置 __match_args__ 特殊屬性為模式的屬性定義指定位置。如果它被設(shè)為 ("x", "y"),則以下模式均為等價(jià)的,并且都把 y 屬性綁定到 var 變量:
Point(
1
, var)
Point(
1
, y
=
var)
Point(x
=
1
, y
=
var)
Point(y
=
var, x
=
1
)
讀取模式的推薦方式是將它們看做是你會在賦值操作左側(cè)放置的內(nèi)容的擴(kuò)展形式,以便理解各個(gè)變量將會被設(shè)置的值。 只有單獨(dú)的名稱(例如上面的 var)會被 match 語句所賦值。 帶點(diǎn)號的名稱 (例如 foo.bar)、屬性名稱(例如上面的 x= 和 y=)或類名稱(通過其后的 "(...)" 來識別,例如上面的 Point)都絕不會被賦值。
模式可以任意地嵌套。例如,如果有一個(gè)由點(diǎn)組成的短列表,則可使用如下方式進(jìn)行匹配:
match points:
????
case []:
????????
print
(
"No points"
)
????
case [Point(
0
,
0
)]:
????????
print
(
"The origin"
)
????
case [Point(x, y)]:
????????
print
(f
"Single point {x}, {y}"
)
????
case [Point(
0
, y1), Point(
0
, y2)]:
????????
print
(f
"Two on the Y axis at {y1}, {y2}"
)
????
case _:
????????
print
(
"Something else"
)
為模式添加成為守護(hù)項(xiàng)的 if 子句。如果守護(hù)項(xiàng)的值為假,則 match 繼續(xù)匹配下一個(gè) case 語句塊。注意,值的捕獲發(fā)生在守護(hù)項(xiàng)被求值之前:
match point:
????
case Point(x, y)
if
x
=
=
y:
????????
print
(f
"Y=X at {x}"
)
????
case Point(x, y):
????????
print
(f
"Not on the diagonal"
)
match 語句的其他特性:
與解包賦值類似,元組和列表模式具有完全相同的含義,并且實(shí)際上能匹配任意序列。 但它們不能匹配迭代器或字符串。
序列模式支持?jǐn)U展解包操作:[x, y, *rest] 和 (x, y, *rest) 的作用類似于解包賦值。 在 * 之后的名稱也可以為 _,因此,(x, y, *_) 可以匹配包含至少兩個(gè)條目的序列,而不必綁定其余的條目。
映射模式:{"bandwidth": b, "latency": l} 從字典中捕獲 "bandwidth" 和 "latency" 的值。與序列模式不同,額外的鍵會被忽略。**rest 等解包操作也支持。但 **_ 是冗余的,不允許使用。
使用 as 關(guān)鍵字可以捕獲子模式:
case (Point(x1, y1), Point(x2, y2) as p2): ...
將把輸入的第二個(gè)元素捕獲為 p2 (只要輸入是包含兩個(gè)點(diǎn)的序列)
大多數(shù)字面值是按相等性比較的,但是單例對象 True, False 和 None 則是按標(biāo)識號比較的。
模式可以使用命名常量。 這些命名常量必須為帶點(diǎn)號的名稱以防止它們被解讀為捕獲變量:
from
enum
import
Enum
class
Color(Enum):
????
RED
=
'red'
????
GREEN
=
'green'
????
BLUE
=
'blue'
?
?color
=
Color(
input
(
"Enter your choice of 'red', 'blue' or 'green': "
))
?
?match color:
????
case Color.RED:
????????
print
(
"I see red!"
)
????
case Color.GREEN:
????????
print
(
"Grass is green"
)
????
case Color.BLUE:
????????
print
(
"I'm feeling the blues :("
)