Как узнать, какие члены модуля/пакета определяют? Определив, я имею в виду:
somemodule.py
import os # <-- Not defined in this module
from os.path import sep # <-- Not defined in this module
I_AM_ATTRIBUTE = None # <-- Is defined in this module
class SomeClass(object): # <-- Is defined also...
pass
Поэтому мне нужна какая-то функция, которая при вызове будет давать только I_AM_ATTRIBUTE
и SomeClass
.
Теперь я пытаюсь использовать dir(somemodule)
, но как узнать, какие из них определены в somemodule
? Проверка на __module__
не работает, поскольку это не определено в модулях и атрибутах (например, os
package или sep
).
Очевидно, что дикий импорт (from somemodule import *
) также не позволяет их фильтровать, так что даже возможно?
Лучшее, что я могу получить, это:
import somemodule
for name in dir(somemodule):
try:
value = getattr(somemodule, name)
except:
pass
else:
if hasattr(value, "__module__"):
if value.__module__ != somemodule.__name__:
continue
if hasattr(value, "__name__"):
if not value.__name__.startswith(__name__):
continue
print "somemodule defines:", name
Выбирает os
, но оставляет sep
.
Что означает "определить"? Для меня определено, что некоторый символ является частью открытого интерфейса модуля. Это совпадает с тем, как кажется, что вы пытаетесь использовать этот термин, в том числе и в вашем примере, но если у вас есть какая-то цель, которая не согласуется с этим определением, вам придется прояснить вопрос о том, что вы действительно пытаясь сделать. Это делает проблему с документацией.
Таким образом, вы не можете знать, что определяет модуль, а некоторые вещи, которые импортируются, могут по-прежнему быть "определены в этом модуле" или "определены как часть общедоступного интерфейса этого модуля". Это часто происходит при импорте из частного модуля, включая модули расширения C.
Для ваших собственных модулей используйте __all__ (можете сделать это легко) или неофициальный префикс подчеркивания для непубличных (например, _private_var = 42
). Оба соглашения распознаются с помощью help() и должны использоваться другими генераторами документации.
__all__
, какие вещи должны мы документируем? Я, вероятно, заканчиваю использовать вышеуказанный код, если __all__
не определен ... По крайней мере, он удаляет "os" и такой импорт отключается.
Нет никакого способа сделать это. Это связано с тем, что простые атрибуты (например, I_AM_ATTRIBUTE
в вашем примере) - это просто значения, хранящиеся в словаре модулей. Когда они копируются в другой модуль, они также помещаются в этот словарь модулей, и нет способа узнать, в каком исходном местоположении. Вы можете указывать только объекты, которые предоставляют атрибут __module__
, такой как классы и функции.
Что касается дикого импорта, запуск from somemodule import *
в вашем примере будет импортировать все атрибуты, включая os
и sep
. Если пакет содержит переменную __all__
, дикий импорт импортирует имена, содержащиеся в нем. В противном случае он будет импортировать все имена, не начинающиеся с подчеркивания, независимо от того, из какого модуля они изначально.
__name__
если проверено с помощью __name__
.