Lambda不在Python 3.6中创建实例方法

时间:2018-12-20 19:11:28

标签: python lambda

我正在尝试创建名称基于类实例的特定属性的方法。我的代码与此类似:

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 :(得分:1)

(有点)回复wim的评论:

我自己还没有遇到好的用例,但是您可以设置 任意函数作为任意实例的方法。风格好吗?在大多数情况下,也许有更好的方法。但是您可以,我会告诉您。


您只是在设置一个恰好是您实例上的函数的属性。

函数是(非数据)descriptors,您可以使用它们的__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

我无法在此处对Descriptor HowTo Functions and Methods section进行重申,但它会像这样分解:

当您通过点符号访问实例上的函数属性时,将不会调用函数的__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