Функция dir()
Несмотря на то, что относительно легко найти и импортировать модуль, не так-то просто запомнить, что каждый модуль содержит. И вряд ли вам захочется всякий раз смотреть исходный код, чтобы это выяснить. К счастью, Python предоставляет способ определения содержимого модулей (и других объектов) с помощью встроенной функции dir().
Функция dir(), вероятно, наиболее известная из всех интроспективных механизмов Python. Она возвращает отсортированный список имен атрибутов для любого переданного в нее объекта. Если ни один объект не указан, dir() возвращает имена в текущей области видимости. Давайте применим dir() к нашему модулю keyword и посмотрим, что она покажет:
Листинг 16. Атрибуты модуля keyword
>>> dir(keyword) ['__all__', '__builtins__', '__doc__', '__file__', '__name__', 'iskeyword', 'keyword', 'kwdict', 'kwlist', 'main']
А как насчет модуля sys, который мы рассматривали выше?
Листинг 17. Атрибуты модуля sys
>>> dir(sys) ['__displayhook__', '__doc__', '__excepthook__', '__name__', '__stderr__', '__stdin__', '__stdout__', '_getframe', 'argv', 'builtin_module_names', 'byteorder', 'copyright', 'displayhook', 'exc_info', 'exc_type', 'excepthook', 'exec_prefix', 'executable', 'exit', 'getdefaultencoding', 'getdlopenflags', 'getrecursionlimit', 'getrefcount', 'hexversion', 'last_traceback', 'last_type', 'last_value', 'maxint', 'maxunicode', 'modules', 'path', 'platform', 'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setdlopenflags', 'setprofile', 'setrecursionlimit', 'settrace', 'stderr', 'stdin', 'stdout', 'version', 'version_info', 'warnoptions']
Без указания аргумента dir() возвращает имена в текущей области видимости. Заметьте, что keyword и sys присутствуют в этом списке, поскольку мы импортировали их ранее. Импортирование модуля добавляет имя этого модуля в текущую область видимости:
Листинг 18. Имена в текущей области
>>> dir() ['__builtins__', '__doc__', '__name__', 'keyword', 'sys']
Мы упоминали, что функция dir() является встроенной функцией, что означает, что нам не нужно импортировать модуль, чтобы использовать эту функцию.
Python распознает встроенные функции без нашего участия. И теперь мы видим это имя, __builtins__, возращенное обращением к dir(). Возможно, здесь имеется какая-то связь. Давайте введем имя __builtins__ в приглашение Python и посмотрим, скажет ли нам Python о нем что-нибудь интересное:
Листинг 19. Что такое __builtins__?
>>> __builtins__ <module '__builtin__' (built-in)>
Итак, __builtins__, похоже, является в текущей области именем, связанным с объектом модуля по имени __builtins__. (Поскольку модули - это не простые объекты с одиночными значениями, Python показывает информацию об этом модуле внутри угловых скобок.) Заметьте, что, если вы будете искать файл __builtin__.py на диске, то вы ничего не найдете. Этот особый объект модуля создается интерпретатором Python из ниоткуда, так как он содержит элементы, которые всегда доступны интерпретатору. И, несмотря на то, что физически файла не существует, мы все же можем применить нашу функцию dir() к этому объекту, чтобы увидеть все встроенные функции, объекты ошибок и несколько различных атрибутов, которые он содержит:
Листинг 20. Атрибуты модуля __builtins__
>>> dir(__builtins__) ['ArithmeticError', 'AssertionError', 'AttributeError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FloatingPointError', 'IOError', 'ImportError', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'OverflowWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeError', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '_', '__debug__', '__doc__', '__import__', '__name__', 'abs', 'apply', 'bool', 'buffer', 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'eval', 'execfile', 'exit', 'file', 'filter', 'float', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'min', 'object', 'oct', 'open', 'ord', 'pow', 'property', 'quit', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'round', 'setattr', 'slice', 'staticmethod', 'str', 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip']
Функция dir() работает со всеми типами объектов, включая строки, целые числа, списки, кортежи, словари, функции, экземпляры и методы классов и классы, определенные пользователем. Давайте применим dir() к строковому объекту и посмотрим, что возвратит Python. Как вы можете видеть, даже простая строка Python имеет ряд атрибутов:
Листинг 21. Атрибуты строки
>>> dir('this is a string') ['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__repr__', '__rmul__', '__setattr__', '__str__', 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'replace', 'rfind', 'rindex', 'rjust', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
Поэкспериментируйте со следующими примерами, чтобы выяснить, что они возвратят. Заметьте, что символ # обозначает начало комментария. Все от начала комментария и до конца строки игнорируется Python:
Листинг 22. Применяем dir() к другим объектам
dir(42) # Integer (and the meaning of life) dir([]) # List (an empty list, actually) dir(()) # Tuple (also empty) dir({}) # Dictionary (ditto) dir(dir) # Function (functions are also objects)
Чтобы продемонстрировать динамическую сущность интроспективных возможностей Python, давайте рассмотрим некоторые примеры, применяя dir() к классу, определенному пользователем, и нескольким экземплярам класса. Определим наш собственный класс интерактивно, создадим несколько экземпляров этого класса, и, добавив уникальный атрибут только к одному из этих экземпляров, посмотрим, сможет ли Python со всем этим разобраться. Ниже приведены результаты:
Листинг 23. Применяем dir() к классам, определенным пользователем, экземплярам класса и атрибутам
>>> class Person(object): ... """Person class.""" ... def __init__(self, name, age): ... self.name = name ... self.age = age ... def intro(self): ... """Return an introduction.""" ... return "Hello, my name is %s and I'm %s." % (self.name, self.age) ... >>> bob = Person("Robert", 35) # Создать экземпляр Person >>> joe = Person("Joseph", 17) # Создать еще один экземпляр >>> joe.sport = "football" # Присвоить одному экземпляру новый атрибут >>> dir(Person) # Атрибуты класса Person ['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__repr__', '__setattr__', '__str__', '__weakref__', 'intro'] >>> dir(bob) # Атрибуты bob ['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__repr__', '__setattr__', '__str__', '__weakref__', 'age', 'intro', 'name'] >>> dir(joe) # Заметьте, что joe имеет дополнительный атрибут ['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__repr__', '__setattr__', '__str__', '__weakref__', 'age', 'intro', 'name', 'sport'] >>> bob.intro() # Вызов метода intro экземпляра bob "Hello, my name is Robert and I'm 35." >>> dir(bob.intro) # Атрибуты метода intro ['__call__', '__class__', '__cmp__', '__delattr__', '__doc__', '__get__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__repr__', '__setattr__', '__str__', 'im_class', 'im_func', 'im_self']