Как я могу проверить, является ли идентификатор ненадежным или закрытым для класса (т.е. будет искажен)? - PullRequest
3 голосов
/ 12 июля 2020

Я пишу проект, который дает советы по поводу имен переменных, и я хочу, чтобы он сообщал, соответствует ли имя любому из зарезервированных классов идентификаторов . Первый ("частный") довольно прост, просто name.startswith('_'), но имена dunder и class-private более сложны. Есть ли встроенная функция, которая может мне сказать? Если нет, то какие внутренние правила использует Python?

Для dunder проверка name.startswith('__') and name.endswith('__') не работает, потому что, например, это будет соответствовать '__'. Может быть, регулярное выражение, например ^__\w+__$, будет работать?

Для закрытого класса name.startswith('__') не работает, потому что имена dunder не искажены, а также имена с просто подчеркиванием, например '___'. Поэтому мне кажется, что мне нужно проверить, начинается ли имя с двух знаков подчеркивания, не заканчивается ли двумя знаками подчеркивания и содержит ли хотя бы один символ без подчеркивания. Это правильно? В коде:

name.startswith('__') and not name.endswith('__') and any(c != '_' for c in name)

Меня больше беспокоят крайние случаи, поэтому я хочу убедиться, что правила на 100% верны. Я прочитал Что означают одинарное и двойное подчеркивание перед именем объекта? , но деталей недостаточно.

1 Ответ

4 голосов
/ 12 июля 2020

Вот внутренние правила. Обратите внимание, что я с трудом могу прочитать C, поэтому возьмите это с недоверием.

Dunder

На основе is_dunder_name в Objects/typeobject.c (используя str.isascii из Python 3.7):

len(name) > 4 and name.isascii() and name.startswith('__') and name.endswith('__')

Это регулярное выражение ^__\w+__$ будет работать, но для этого потребуется re.ASCII, чтобы убедиться, что \w соответствует только символам ASCII .

Класс-частный

На основе _Py_Mangle в Python/compile.c:

name.startswith('__') and not name.endswith('__') and not '.' in name

Хотя, строго говоря, имя с точкой является «ссылкой на атрибут», а не именем, поэтому вы можете удалить эту проверку:

name.startswith('__') and not name.endswith('__')

И это соответствует правилам в документации в разделе Идентификаторы (имена) .

Я не понял, но not name.endswith('__') следит за тем, чтобы имя содержало хотя бы один символ без подчеркивания.

...