2013-10-06 5 views
1

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

Что я пытаюсь сделать, это добавить метод к классу из строки. Я могу сделать это с помощью метода setattr(), но это не позволит мне использовать self в качестве атрибута в дополнительном методе. Вот пример: (и я извиняюсь за имена переменных, я всегда использую YOLO когда я насмешливо от идеи)

class what: 
    def __init__(self): 
     s = 'def yolo(self):\n\tself.extra = "Hello"\n\tprint self.extra' 
     exec(s) 
     setattr(self,"yolo",yolo) 

what().yolo() 

возвращает это:

Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: yolo() takes exactly 1 argument (0 given) 

и если s = 'def yolo():\n\tself.extra = "Hello"\n\tprint self.extra' тогда я получаю этот результат:

Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<string>", line 2, in yolo 
NameError: global name 'self' is not defined 

Это по существу означает, что я не могу динамически создавать методы для классов, которые я знаю, это плохая практика и unpythonic, потому что метамфетамин ods не смогут получить доступ к переменным, доступ к которым принадлежит остальной части класса.

Я ценю любую помощь.

+0

* Почему вы хотите динамически добавлять методы в класс? – Ivo

+0

@ Иво Ха-ха ... Это потому, что я могу иметь достаточно хорошую причину? – Hovestar

+0

Нет, потому что он совершенно неспокойный. Я слышу, как рубин любит это дерьмо. – Ivo

ответ

5

Вы должны привязать свою функцию к экземпляру класса, чтобы превратить его в метод. Это может быть сделано, окружив его types.MethodType:

import types 

class what: 
    def __init__(self): 
     s = 'def yolo(self):\n\tself.extra = "Hello"\n\tprint self.extra' 
     exec(s) 
     self.yolo = types.MethodType(yolo, self) 

what().yolo() 

На стороне записки, почему бы вам даже не нужно exec в этом случае? Вы можете точно также написать

import types 

class what: 
    def __init__(self): 
     def yolo(self): 
      self.extra = "Hello" 
      print self.extra 

     self.yolo = types.MethodType(yolo, self) 

what().yolo() 

Edit: для полноты картины, можно было бы предпочесть решение через the descriptor protocol:

class what: 
    def __init__(self): 
     def yolo(self): 
      self.extra = "Hello" 
      print self.extra 

     self.yolo = yolo.__get__(self) 

what().yolo() 
+0

Ударьте! Я просто использую это как доказательство концепции, поэтому в этом случае мне это действительно не нужно, но это больше для идеи, чем для практичности. – Hovestar

+0

С одной стороны, я не заметил, что код здесь не позволяет расширяемости, поскольку я должен объявить эту функцию в строке 'self.yolo = types ... ', я думаю, что я мог бы использовать' exec() ', чтобы изменить это , но мне еще нужно будет проверить. – Hovestar

+0

Если вы хотите установить имя атрибута динамически, вы можете использовать '' setattr'' (как и в исходном коде). Я просто написал 'self.yolo =' 'потому что' 'setattr'' со строковым литералом как вторым аргументом совершенно бессмысленно. – fjarri

1

Другой способ, кажется более изящным мне:

class what: 
    pass 

ld = {} 
exec(""" 
def yolo(self): 
    self.extra = "Hello" 
    print(self.extra) 
""", None, ld) 
# print('locals got: {}'.format(ld)) 
for name, value in ld.items(): 
    setattr(what, name, value) 

what().yolo() 
Смежные вопросы