例外とは何ですか? 名前から明らかです-それらはプログラムで例外が発生したときに発生します。 なぜ例外がアンチパターンであるのか、そしてそれらはタイピングにどのように関係するのかと尋ねるかもしれません。 私はそれを
理解しようとし
ました 、そして今、私はあなたとこれについて議論したい、ハラジテリ。
例外の問題
毎日直面している問題を見つけるのは難しいです。 習慣と盲目はバグを機能に変えますが、例外をオープンマインドで見てみましょう。
例外を見つけるのは難しい
: «»
raise , ; «» , , .
, «» . :
def divide(first: float, second: float) -> float:
return first / second
,
float. - :
result = divide(1, 0)
print('x / y = ', result)
?
print , 1 0 – ,
ZeroDivisionError. , , .
, . Python : , ,
int,
str, , , .
raise something() . , .
.
.
ZeroDivisionError, .
def divide(first: float, second: float) -> float:
try:
return first / second
except ZeroDivisionError:
return 0.0
. 0? 1
None? , ,
None ( ), , - .
? , - ? . , , .
: — , .
,
ZeroDivisionError . - .
, , ? , — - . .
, , - , , . , , 0.
divide .
, . , , ? ? , ,
.
, .
except,
. , , .
, : , , , . ?
« ».
,
goto, .
: HTTP API:
import requests
def fetch_user_profile(user_id: int) -> 'UserProfile':
"""Fetches UserProfile dict from foreign API."""
response = requests.get('/api/users/{0}'.format(user_id))
response.raise_for_status()
return response.json()
. :
- , .
- .
- , .
- .
- API URL.
- .
- .
- -
- .
- JSON, .
, . , , .
?
, , , , . , .
, 0. , , ?
from returns.result import Result, Success, Failure
def divide(first: float, second: float) -> Result[float, ZeroDivisionError]:
try:
return Success(first / second)
except ZeroDivisionError as exc:
return Failure(exc)
:
Success Failure.
Result. , ,
Result[float, ZeroDivisionError] Success[float],
Failure[ZeroDivisionError].
?
, .
Failure : .
1 + divide(1, 0)
.
Result, . .
,
PEP561. mypy , -, .
from returns.result import Result, Success, Failure
def divide(first: float, second: float) -> Result[float, ZeroDivisionError]:
try:
return Success('Done')
except ZeroDivisionError as exc:
return Failure(0)
?
:
Success(4).bind(lambda number: Success(number / 2))
Success(4).map(lambda number: number + 1)
, ,
.bind .map c
Failure:
Failure(4).bind(lambda number: Success(number / 2))
Failure(4).map(lambda number: number / 2)
, .
, , .
Failure(4).rescue(lambda number: Success(number + 1))
Failure(4).fix(lambda number: number / 2)
« », « ». , !
?
, , , .
.unwrap() .value_or():
Success(1).unwrap()
Success(0).value_or(None)
Failure(0).value_or(None)
Failure(1).unwrap()
, , ,
.unwrap() ?
UnwrapFailedErrors?
, , . : . ,
Result:
from returns.result import Result, Success, Failure
class CreateAccountAndUser(object):
"""Creates new Account-User pair."""
def _validate_user(
self, username: str, email: str,
) -> Result['UserSchema', str]:
"""Returns an UserSchema for valid input, otherwise a Failure."""
def _create_account(
self, user_schema: 'UserSchema',
) -> Result['Account', str]:
"""Creates an Account for valid UserSchema's. Or returns a Failure."""
def _create_user(
self, account: 'Account',
) -> Result['User', str]:
"""Create an User instance. If user already exists returns Failure."""
-, -:
class CreateAccountAndUser(object):
"""Creates new Account-User pair."""
def __call__(self, username: str, email: str) -> Result['User', str]:
"""Can return a Success(user) or Failure(str_reason)."""
return self._validate_user(
username, email,
).bind(
self._create_account,
).bind(
self._create_user,
)
- , ,
.unwrap(). ? . ?
@pipeline:
from result.functions import pipeline
class CreateAccountAndUser(object):
"""Creates new Account-User pair."""
@pipeline
def __call__(self, username: str, email: str) -> Result['User', str]:
"""Can return a Success(user) or Failure(str_reason)."""
user_schema = self._validate_user(username, email).unwrap()
account = self._create_account(user_schema).unwrap()
return self._create_user(account)
.
.unwrap() @pipeline : , -
.unwrap() Failure[str],
@pipeline Failure[str] . .
, HTTP API. , ?
Result.
@safe, . , :
from returns.functions import safe
@safe
def divide(first: float, second: float) -> float:
return first / second
def divide(first: float, second: float) -> Result[float, ZeroDivisionError]:
try:
return Success(first / second)
except ZeroDivisionError as exc:
return Failure(exc)
,
@safe, .
, API –
@safe. :
import requests
from returns.functions import pipeline, safe
from returns.result import Result
class FetchUserProfile(object):
"""Single responsibility callable object that fetches user profile."""
_http = requests
@pipeline
def __call__(self, user_id: int) -> Result['UserProfile', Exception]:
"""Fetches UserProfile dict from foreign API."""
response = self._make_request(user_id).unwrap()
return self._parse_json(response)
@safe
def _make_request(self, user_id: int) -> requests.Response:
response = self._http.get('/api/users/{0}'.format(user_id))
response.raise_for_status()
return response
@safe
def _parse_json(self, response: requests.Response) -> 'UserProfile':
return response.json()
, :
@safe , . Result[OldReturnType, Exception].Result , ..unwrap(), .@pipeline, .unwrap .
— . , :
- « ».
Result, . - « ». .
.fix() .rescue(). - « ». -. .
- « ». ! , - .
, .
. - , , .
? Moscow Python Conf++ 5 , ! – dry-python core- Django Channels. dry-python -.