3 ms·
It looks like a distinction without a difference. We can consider `None and f()` pattern as explicit syntax that unwraps objects as necessary without infecting
by d0mine 4y ago
It looks like a distinction without a difference. We can consider `None and f()` pattern as explicit syntax that unwraps objects as necessary without infecting other code.
Background: an object that either None or true in a boolean context (true unless overriden for custom objects).
Given such object, we can consider it in a virtual Maybe container/box.
When we want to use it, we have to unwrap it using `obj and obj.method()` syntax.
Then `obj.method()` is ordinary "unwrapped" call.
Just to remind you. Here's how "ergonomic" Maybe variant from the article look like:
# Type hint here is optional, it only helps the reader here:
discount_program: Maybe['DiscountProgram'] = Maybe.from_optional(
user,
).bind_optional( # This won't be called if `user is None`
lambda real_user: real_user.get_balance(),
).bind_optional( # This won't be called if `real_user.get_balance()` is None
lambda balance: balance.credit_amount(),
).bind_optional( # And so on!
lambda credit: choose_discount(credit) if credit > 0 else None,
)
https://github.com/dry-python/returns#maybe-container https://github.com/dry-python/returns#maybe-container
You can decide for yourself what is more readable: all these lambdas or the `None and f()` code.
- kortex 4y agoThe dry-python lambda soup is awful, I totally agree there. That's just there mostly for demonstration purposes though. Generally you'd actually use the flow construct (monads) to compose methods. But `obj and obj.method()` really is not the same thing as `obj.map(method)`. "virtual Maybe container/box" is a nice idea, and does actually type-check with mypy (mostly), but you cannot actually compose it with other functions. The problem is, each time you do `obj and obj.method()`, you end up union-ing type(obj) and type(obj.method). https://mypy-play.net/?gist=5b03d81a64453997984e448df9b889e7 https://mypy-play.net/?gist=5b03d81a64453997984e448df9b889e7 main.py:40: note: Revealed type is "Union[__main__.User, None]" main.py:41: note: Revealed type is "Union[__main__.User, None, builtins.float]" main.py:42: note: Revealed type is "Union[__main__.User, None, builtins.float]" main.py:43: note: Revealed type is "Union[__main__.User, None, builtins.float, builtins.str]" True Maybe types are more precise. Maybe if the Mypy engine could be retooled to recognise the `obj and obj.method()` idiom as tantamount to `obj.map(method)`, this could be avoided.