Слабые ссылки
Для обеспечения ассоциаций объектов без свойственных ссылкам проблем с возможностью образования циклических ссылок, в Python для сложных структур данных и других видов использования, при которых ссылки не должны мешать удалению объекта, предлагается механизм слабых ссылок. Такая ссылка не учитывается при подсчете ссылок на объект, а значит, объект удаляется с исчезновением последней «сильной» ссылки.
Для работы со слабыми ссылками применяется модуль weakref. Основные принципы его работы станут понятны из следующего примера:
Листинг
>>> import weakref
>>>
>>> class MyClass(object):
… def __str__(self):
… return «MyClass»
…
>>>
>>> s = MyClass() # создается экземпляр класса
>>> print s
MyClass
>>> s1 = weakref.proxy(s) # создается прокси–объект
>>> print s1 # прокси–объект работает как исходный
MyClass
>>> ss = weakref.ref(s) # создается слабая ссылка на него
>>> print ss() # вызовом ссылки получается исходный объект
MyClass
>>> del s # удаляется единственная сильная ссылка на объект
>>> print ss() # теперь исходного объекта не существует
None
>>> print s1
Traceback (most recent call last):
File "", line 1, in ?
ReferenceError: weakly–referenced object no longer exists
К сожалению, поведение прокси–объекта не совсем такое, как у исходного: он не может быть ключом словаря, так как является нехэшируемым.
Статический метод
Иногда необходимо использовать метод, принадлежащий классу, а не его экземпляру. В этом случае можно описать статический метод. До появления декораторов (до Python 2.4) определять статический метод приходилось следующим образом:
Листинг
class A(object):
def name():
return A.__name__
name = staticmethod(name)
print A.name()
a = A()
print a.name()
Статическому методу не передается параметр с экземпляром класса. Он ему попросту не нужен.
В Python 2.4 для применения описателей (descriptors) был придуман новый синтаксис — декораторы:
Листинг
class A(object):
@staticmethod
def name():
return A.__name__
Смысл декоратора в том, что он «пропускает» определяемую функцию (или метод) через заданную в нем функцию. Теперь писать name три раза не потребовалось. Декораторов может быть несколько, и применяются они в обратном порядке.
Метод класса
Если статический метод имеет свои аналоги в C++ и Java, то метод класса основан на том, что в Python классы являются объектами. В отличие от статического метода, в метод класса первым параметром передается объект–класс. Вместо self для подчеркивания принадлежности метода к методам класса принято использовать cls.
Пример использования метода класса можно найти в модуле tree пакета nltk (Natural Language ToolKit, набор инструментов для естественного языка). Ниже приведен лишь фрагмент определения класса Tree (базового класса для других подклассов). Метод convert класса Tree определяет процедуру преобразования дерева одного типа в дерево другого типа. Эта процедура абстрагируется от деталей реализации конкретных типов, описывая обобщенный алгоритм преобразования:
Листинг
class Tree:
# …
def convert(cls, val):
if isinstance(val, Tree):
children = [cls.convert(child) for child in val]
return cls(val.node, children)
else:
return val
convert = classmethod(convert)
Пример использования (взят из строки документации метода convert()):
Листинг
>>> # Преобразовать tree в экземпляр класса Tree
>>> tree = Tree.convert(tree)
>>> # " " " " " ParentedTree
>>> tree = ParentedTree.convert(tree)
>>> # " " " " " MultiParentedTree
>>> tree = MultiParentedTree.convert(tree)
Метод класса позволяет более естественно описывать действия, которые связаны в основном с классами, а не с методами экземпляра класса.
Метаклассы
Еще одним отношением между классами является отношение класс–метакласс. Метакласс можно считать «высшим пилотажем» объектно–ориентированного программирования, но, к счастью, в Python можно создавать собственные метаклассы.
В Python класс тоже является объектом, поэтому ничего не мешает написать класс, назначением которого будет создание других классов динамически, во время выполнения программы.
Пример, в котором класс порождается динамически в функции–фабрике классов:
Листинг
def cls_factory_f(func):
class X(object):
pass
setattr(X, func.__name__, func)
return X
Использование будет выглядеть так:
Листинг
def my_method(self):
print «self:", self
My_Class = cls_factory_f(my_method)
my_object = My_Class()
my_object.my_method()
В этом примере функция cls_factory_f() возвращает класс с единственным методом, в качестве которого используется функция, переданная ей как аргумент. От этого класса можно получить экземпляры, а затем у экземпляров — вызвать метод my_method.
Читать дальше