te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>How does "MaybeNone" (also known as "The Any Trick") work in Python type hints? - Stack Over
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

How does "MaybeNone" (also known as "The Any Trick") work in Python type hints? - Stack Over

programmeradmin1浏览0评论

In typestubs for the Python standard library I noticed a peculiar type called MaybeNone pop up, usually in the form of NormalType | MaybeNone. For example, in the sqlite3-Cursor class I find this:

class Cursor:
    # May be None, but using `| MaybeNone` (`| Any`) instead to avoid slightly annoying false positives.
    @property
    def description(self) -> tuple[tuple[str, None, None, None, None, None, None], ...] | MaybeNone: ...

The definition of this MaybeNone is given as:

# Marker for return types that include None, but where forcing the user to
# check for None can be detrimental. Sometimes called "the Any trick". See
# CONTRIBUTING.md for more information.
MaybeNone: TypeAlias = Any  # stable

(I could not find additional information in the CONTRIBUTING.md, which I assume to be this one.)

I understand the intention of marking a return type in such a way that a user is not forced to null check in cases where the null is more of a theoretical problem for most users. But how does this achieve the goal?

  1. SomeType | Any seems to imply that the return type could be anything, when what I want to say is that it can be SomeType or in weird cases None, so this doesn't seem to express the intent.

  2. MyPy already allows superfluous null-checks on variables that can be proven not to be None even with --strict (at least with my configuration?) so what does the special typing even accomplish as compared to simply doing nothing?

In typestubs for the Python standard library I noticed a peculiar type called MaybeNone pop up, usually in the form of NormalType | MaybeNone. For example, in the sqlite3-Cursor class I find this:

class Cursor:
    # May be None, but using `| MaybeNone` (`| Any`) instead to avoid slightly annoying false positives.
    @property
    def description(self) -> tuple[tuple[str, None, None, None, None, None, None], ...] | MaybeNone: ...

The definition of this MaybeNone is given as:

# Marker for return types that include None, but where forcing the user to
# check for None can be detrimental. Sometimes called "the Any trick". See
# CONTRIBUTING.md for more information.
MaybeNone: TypeAlias = Any  # stable

(I could not find additional information in the CONTRIBUTING.md, which I assume to be this one.)

I understand the intention of marking a return type in such a way that a user is not forced to null check in cases where the null is more of a theoretical problem for most users. But how does this achieve the goal?

  1. SomeType | Any seems to imply that the return type could be anything, when what I want to say is that it can be SomeType or in weird cases None, so this doesn't seem to express the intent.

  2. MyPy already allows superfluous null-checks on variables that can be proven not to be None even with --strict (at least with my configuration?) so what does the special typing even accomplish as compared to simply doing nothing?

Share Improve this question edited 2 days ago Daraan 3,8657 gold badges22 silver badges46 bronze badges asked 2 days ago julainejulaine 1,7241 gold badge14 silver badges29 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 6

SomeType | Any seems to imply that the return type could be anything [...]

SomeType | Any is not the same as Any. It means "a type that is lowerbounded to SomeType".


To give a simple example:

(playgrounds: Mypy, Pyright)

a: Any
a.foo()  # no error
class C:
  b: int

c: C | Any
c.foo()  # error: `C` has no attribute `foo`

For an operation not to cause any type errors when applied to an union, it must be type-safe when applied to every member of that union. Since C | None has None as a member, many operations like attribute access (None.foo), subscription (None[...]) and invocation (None()) would fail.

This is considered not user-friendly,[citation needed] especially when Python does not have a built-in "assert not None" shorthand. Using MaybeNone/Any instead of None saves the user from an unergonomic check without sacrificing (too much) type safety.


The explanation has since been removed from CONTRIBUTING.md in a more recent PR (it predates the comment).

A nice summary can be found in this comment explaining the "Any Trick" of typeshed.

We tend to use it whenever something can be None, but requiring users to check for None would be more painful than helpful.

As background they talk about xml.etree.ElementTree.getroot which in some case returns None (Happens when the tree is initialized without a root).
To reflect this, it was updated to def getroot(self) -> Element | Any: ... with the possible return types + Any.

The different possibilities and effects are summarized as:

-> Any means "please do not complain" to type checkers. If root has type Any, you will no error for this.

-> Element means "will always be an Element", which is wrong, and would cause type checkers to emit errors for code like if root is None.

-> Element | None means "you must check for None", which is correct but can get annoying. [..., it could be possible used] to do things like ET.parse("file.xml").getroot().iter("whatever").

-> Element | Any means "must be prepared to handle an Element". You will get an error for root.tagg, because it is not valid when root is an Element. But type checkers are happy with if root is None checks, because we're saying it can also be something else than an Element.

I did slightly modify the quotes by adding italics and -> type

发布评论

评论列表(0)

  1. 暂无评论