Лямбда не создает метод экземпляра в Python 3.6 - PullRequest
0 голосов
/ 20 декабря 2018

Я пытаюсь создать методы, имена которых основаны на определенном атрибуте экземпляра класса.Мой код похож на это:

class myClass:
    info_to_be_accessed = {
        'infoA': 14,
        'infoB': 21,
        'infoC': False,
        'infoD': 'spam'
    }

    def create_methods(self):
        for info in self.info_to_be_accessed:
            setattr(self, info, lambda self: self.info_to_be_accessed.get(info, None))
        return self

c = myClass().create_methods()
print(c.infoA())

Я ожидал, что c.infoA() будет методом экземпляра, но он оказывается статическим методом, который не получает параметр self при вызове.Выходные данные повышаются до TypeError:

Traceback (most recent call last):
  File "test.py", line 15, in <module>
    print(c.infoA())
TypeError: <lambda>() missing 1 required positional argument: 'self'

Ожидаемый выход:

14

РЕДАКТИРОВАТЬ: Ответ @chepner.Я, честно говоря, не уверен, что это лучший способ справиться с этим, но моя основная проблема заключается в том, что я имею дело с данными, которые находятся за пределами моей базы данных / моего собственного кода.Я извлекаю информацию из базы данных, которой не могу управлять, поэтому ее можно проанализировать с помощью моего кода.По сути, мой класс реального кода имеет фрейм данных pandas с информацией о результате сложного SQL-запроса и возможностью построения диаграммы о нем, но иногда я хочу отфильтровать фрейм данных для его построения, а иногда я хочуСюжет все это.Я на самом деле не анализирую словарь, а создаю методы для фильтрации этого информационного кадра.Дело в том, что (внешний) объект, который я анализирую с помощью этого запроса, имеет фиксированные значения, которыми может быть определенный атрибут, но если эта внешняя база данных изменится в будущем, я не хочу создавать дополнительный код только для покрытия нового значения, котороетам добавленИспользование методов вместо параметров мне просто удобнее при анализе этих данных, но это не код, который идет в производство, а просто то, что я использую в CLI.Вот почему мне удобно иметь отдельные методы для каждого значения, которое может быть передано.

1 Ответ

0 голосов
/ 20 декабря 2018

(в некоторой степени) отвечая на комментарий wim:

Я сам не нашел хорошего варианта использования, но вы можете устанавливать произвольные функции как методы произвольных экземпляров.Это хороший стиль?Вероятно, есть лучший способ в большинстве случаев.Но вы можете, и я покажу, как.


Вы просто устанавливаете атрибут, который оказывается функцией вашего экземпляра.

Функции (не данные) дескрипторы и вы можете использовать их метод __get__ для исправления первого параметра.

Демонстрация:

>>> class myClass: 
...:     def __repr__(self): # nicer output for demo 
...:         return '<myClass object>' 
...:     def create_method_on_instance(self, name, function): 
...:         setattr(self, name, function.__get__(self))                                                               
>>>                                                                                                                    
>>> m1 = myClass()                                                                                                     
>>> m2 = myClass()                                                                                                     
>>> m1.create_method_on_instance('foo', lambda self, x, y: print(self, x + y))                                           
>>> m2.create_method_on_instance('foo', lambda self, x, y: print(self, x - y))                                           
>>>                                                                                                             
>>> m1.foo(3, 4)                                                                                                       
<myClass object> 7
>>> m2.foo(3, 4)                                                                                                 
<myClass object> -1

Я не могу повторить все из дескриптора HowTo Раздел функций и методов здесь, но он разбивается следующим образом:

Когда вы обращаетесь к атрибуту функции в экземпляре через точечную нотацию, функция __get__ метод вызываться не будет.

Однако метод функции __get__ отвечает за привязку первого аргумента (обычно называемого self) функции к рассматриваемому экземпляру (таким образом, создавая метод).

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

>>> class Unrelated: 
...:     pass 
...:
>>> u = Unrelated()                                                                                                                   
>>> u.foo = (lambda self, x, y: print(self, x+y)).__get__(m1)                                                          
>>> u.foo(3, 4)                                                                                                        
<myClass object> 7
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...