динамическое добавление функции в класс и создание ее как связанного метода

#python-3.x

#python-3.x

Вопрос:

Я новичок в python. Я хочу написать метод add_function для этого класса, чтобы динамически добавлять любую функцию в мой класс. Эта функция может манипулировать некоторыми атрибутами моего класса, но она написана вне класса. Предположим, что это класс и его метод.

 import numpy as np
import feature_function as ffun



class Features:
    
    def __init__(self,x,fs=None):
        self.x = x
        self.fs = fs

        self.label = []
        self.features = []

    def __mean(self, nan_omit = False, min_samples = 1):
        out = ffun.mean(self.x, nan_omit = nan_omit, min_samples = min_samples)
        self.label.extend(['mean'])
        self.features = np.append(self.features,out)

  

теперь я хочу написать эту функцию за пределами класса:

 def __max(self, nan_omit = False, min_samples = 1):
    out = ffun.max(self.x, nan_omit = nan_omit, min_samples = min_samples)
    self.label.extend(['max'])
    self.features = np.append(self.features,out)
  

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

 
    # Add function dynamically by user
    def add_function(self, name, methodToRun, type ):
        name2 = '__'   name
        # setattr(self, name2, methodToRun)
        setattr(self, mangle_attr(self, name2), methodToRun)

  

mangle_attr это функция для того, чтобы присвоить классу приватную функцию.

 def mangle_attr(source, attr):
    # if source is an object, get the class
    if not hasattr(source, "__bases__"):
        source = source.__class__
    # mangle attr
    tmp = {}
    code = _mangle_template.format(cls=source.__name__, attr=attr)
    eval(compile(code, '', 'exec'), {}, tmp); 
    return tmp['cls'].mangle.__code__.co_varnames[0]

  

использование setattr не привязывает __max функцию к моему классу, например, __mean она ограничена в моем классе, если я вызываю функцию, я могу видеть:

<bound method Features.__mean of <__main__.Features object at 0x7fd4c91aac10>>

однако для __max я все еще вижу это: <function skewness at 0x7fd2b9dbfb90>

есть ли у меня решение этой проблемы?

Комментарии:

1. "now I want to write this function outside of the scope of class:" почему? Она должна либо быть написана внутри класса, к которому она принадлежит, либо, если это может быть применимо к нескольким классам, быть записана внутри родительского класса, который затем подразделяется на подклассы.

2. предположим, что сумасшедший пользователь моей программы, который хочет написать произвольную функцию, которая (возможно) манипулирует атрибутами моего класса, и он хочет, чтобы у моего класса был метод add_function, чтобы добавить его в мой класс.

3. Обратите внимание, что использование искаженных имен очень необычно. Основная цель — защитить детали реализации от переопределения при расширении класса, например, через подклассы. Это противоречит намеренному добавлению искаженных имен извне класса. Методы расширения обычно должны быть общедоступными по определению.

Ответ №1:

Ваш addfunction аргумент привязывается к экземпляру self , а не к классу. Привязать аргумент к классу, например, через type(self) или classmethod :

 class Features:
    ...
    # Add function dynamically by user
    @classmethod
    def add_function(cls, name, methodToRun, type ):
        name2 = '__'   name
        setattr(cls, mangle_attr(self, name2), methodToRun)
  

Связанный метод — это функция в классе, просматриваемая через экземпляр. Добавление функции к экземпляру просто делает ее атрибутом, который, оказывается, можно вызывать.

Ответ №2:

Более простой пример, чтобы показать общую идею:

 # Create the class without a method
class Features():
    def __init__(self):
        self.x = 100

# Create a function outside of the class
def multiply(self):
    return self.x*2

# initialize class object, then add function as a method to the class
obj = Features()
setattr(Features, "multiply", multiply)
obj.multiply()
  

Комментарии:

1. Замена setattr(Features, "multiply", multiply) на Features.multiply = multiply работает. Смотрите repl.it/repls/WretchedAzureAmoeba#main.py

2. Ах, хаха, я глупый, я пытался использовать это для объекта, а не для класса. Вы правы! Есть ли какое-либо преимущество выбора одного над другим?