Преобразовать встроенный тип функции в тип метода (в Python 3)

Рассмотрим простую функцию типа

def increment(self): self.count += 1 

который запускается через Cython и скомпилирован в модуль расширения. Предположим, теперь я хотел бы сделать эту функцию методом для класса. Например:

 class Counter: def __init__(self): self.count = 0 from compiled_extension import increment Counter.increment = increment 

Теперь это не сработает, так как соглашение о вызове на уровне C будет нарушено. Например:

 >>> c = Counter() >>> c.increment() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: increment() takes exactly one argument (0 given) 

Но в Python 2 мы можем преобразовать функцию в несвязанный метод, выполнив:

 Counter.increment = types.MethodType(increment, None, Counter) 

Как я могу выполнить то же самое в Python 3?

Один простой способ – использовать тонкую обертку:

 from functools import wraps def method_wraper(f): def wrapper(*args, **kwargs): return f(*args, **kwargs) return wraps(f)(wrapper) Counter.increment = method_wrapper(increment) 

Есть ли более эффективный способ сделать это?

2 Solutions collect form web for “Преобразовать встроенный тип функции в тип метода (в Python 3)”

Первое, что правильно называют имена:

 >>> def increment(obj): ... obj.count += 1 ... >>> class A(object): ... def __init__(self): ... self.count = 0 ... >>> o = A() >>> o.__init__ <bound method A.__init__ of <__main__.A object at 0x0000000002766EF0>> >>> increment <function increment at 0x00000000027797C8> 

Таким образом, правильные имена – это функции и связанные методы . Теперь вы можете посмотреть, как привязать Unbound Method, и вы, вероятно, в конечном итоге будете читать о дескрипторах :

В общем, дескриптор является атрибутом объекта с «поведением привязки», тот, чей доступ к атрибуту был переопределен методами в протоколе дескриптора. Этими методами являются __get__ , __set__ и __delete__ . Если какой-либо из этих методов определен для объекта, он называется дескриптором.

Вы можете легко преобразовать функцию в метод, просто используя разные вызовы __get__

 >>> increment.__get__(None, type(None)) <function increment at 0x00000000027797C8> >>> increment.__get__(o, type(o)) <bound method A.increment of <__main__.A object at 0x00000000027669B0>> 

И это работает как шарм:

 >>> o = A() >>> increment.__get__(None, type(None))(o) >>> o.count 1 >>> increment.__get__(o, type(o))() >>> o.count 2 

Вы можете легко добавить эти новые ограниченные методы к объектам:

 def increment(obj): obj.count += 1 def addition(obj, number): obj.count += number class A(object): def __init__(self): self.count = 0 o = A() o.inc = increment.__get__(o) o.add = addition.__get__(o) print(o.count) # 0 o.inc() print(o.count) # 1 o.add(5) print(o.count) # 6 

Или создайте свой собственный дескриптор , который преобразует функцию в связанный метод :

 class BoundMethod(object): def __init__(self, function): self.function = function def __get__(self, obj, objtype=None): print('Getting', obj, objtype) return self.function.__get__(obj, objtype) class B(object): def __init__(self): self.count = 0 inc = BoundMethod(increment) add = BoundMethod(addition) o = B() print(o.count) # 0 o.inc() # Getting <__main__.B object at 0x0000000002677978> <class '__main__.B'> print(o.count) # 1 o.add(5) # Getting <__main__.B object at 0x0000000002677978> <class '__main__.B'> print(o.count) # 6 

И вы также можете видеть, что это хорошо согласуется с принципами функции / связанного метода :

Классовые словари хранят методы как функции. В определении класса методы записываются с использованием def и lambda, обычных инструментов для создания функций. Единственное отличие от обычных функций состоит в том, что первый аргумент зарезервирован для экземпляра объекта. По соглашению Python ссылка экземпляра называется self, но может быть вызвана этим или любым другим именем переменной.

Для поддержки вызовов методов функции включают метод __get__() для привязки методов во время доступа к атрибутам. Это означает, что все функции являются не-данными дескрипторами, которые возвращают связанные или несвязанные методы в зависимости от того, вызывается ли они из объекта или класса.

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

 >>> B.add # Getting None <class '__main__.B'> <function addition at 0x00000000025859C8> >>> o.add # Getting <__main__.B object at 0x00000000030B1128> <class '__main__.B'> <bound method B.addition of <__main__.B object at 0x00000000030B1128>> 

Импортируйте расширение следующим образом:

 import compiled_extension 

В своем классе вы пишете:

 def increment: return compiled_extension.increment() 

Это кажется более читаемым и может быть более эффективным.

  • Невозможно очистить текст от определенного элемента LI
  • Новый порт Python 3 API Google Python API
  • Как отменить каждое слово в строке, но в том же предложении?
  • Python 3 SQLite3 - неправильное количество привязок
  • Получить определяющий класс объекта несвязанного метода в Python 3
  • PermissionError: в python
  • использование locals () внутри понимания словаря
  • Узнать, была ли вызвана функция
  •  
    Interesting Posts for Van-Lav

    заменяя все регулярные выражения в одной строке

    Python, требуется ведение журнала с вращением журнала и сжатием

    Разница между использованием двойной кавычки и кавычками в python

    сопоставление шаблонов в malayalam делает TypeError: ожидаемая строка или буфер

    В Python существует ли элегантный способ распечатки списка в пользовательском формате без явного цикла?

    Параметр функции Python: кортеж / список

    Как работает оператор смены сдвига в инструкции печати python?

    Работа с UTF-8 в Python

    Частные переменные и методы в Python

    Tensorflow: как передать результат с предыдущего временного шага в качестве входного сигнала для следующего временного интервала

    Импорт / контекст флажка-SQLAlchemy

    правильно отправлять данные между python и Java по Bluetooth

    Как сохранить пользовательский категоризированный корпус в NLTK

    RAII в Python – автоматическое разрушение при выходе из области

    Добавление / вычитание столбцов Pandas

    Python - лучший язык программирования в мире.