代码之家  ›  专栏  ›  技术社区  ›  MagSec

Python:如果静态类变量获得不同的函数引用指针,如何修复?

  •  2
  • MagSec  · 技术社区  · 10 年前

    我想知道为什么我的类使用参数调用被引用的函数(分配给静态类变量)。如果我将函数引用分配给一个普通类变量,它的工作方式与预期的一样。

    这里是我的示例代码:

    # This function is not editable, because it's imported from an API
    def getStuff(): 
        print "I do my stuff!!!"
    
    class foo(object):
        GET_STUFF = getStuff
    
        def __init__(self):
            print "static var: ",self.GET_STUFF
            self.GET_STUFF()
    
    print "outer func: ",getStuff
    foo()
    

    出现以下错误:

    outer func:  <function getStuff at 0x0000000003219908>
    static var:  <bound method foo.getStuff of <__main__.foo object at 0x00000000030AB358>>
    Traceback (most recent call last):
      File "C:/example.py", line 13, in <module>
        foo()
      File "C:/example.py", line 10, in __init__
        self.GET_STUFF()
    TypeError: getStuff() takes no arguments (1 given)
    

    为了解决这个问题,我将构造函数内的函数引用指向类变量:

    class foo(object):
        def __init__(self):
            self.GET_STUFF = getStuff
            print "static var: ",self.GET_STUFF
            self.GET_STUFF()
    

    结果如预期,效果良好:

    outer func:  <function getStuff at 0x000000000331F908>
    static var:  <function getStuff at 0x000000000331F908>
    I do my stuff!!!
    

    但是:

    我想使用一个静态类变量,因为它易于阅读,并且易于为不同的API设置。因此,最后我将提出一些包装类,如下所示:

    from API01 import getStuff01
    from API02 import getStuff02
    
    # bar calculates stuff object from the API (it calls GET_STUFF)
    # and stores the object into self.stuff
    import bar 
    
    class foo01(bar):
        GET_STUFF = getStuff01
    
        def DoSomething(self, volume):
            self.stuff.volume = volume
    
    class foo02(bar):
        GET_STUFF = getStuff02
    
        def DoSomething(self, volume):
            self.stuff.volume = volume
    
    # [...] and so on..
    

    有没有一种方法可以按照我想要的方式来设置包装类,或者我真的必须为每个包装类定义一个构造函数?

    谢谢

    3 回复  |  直到 10 年前
        1
  •  3
  •   Aaron Digulla    10 年前

    错误的原因是

    self.GET_STUFF()
    

    实际上意味着

    tmp = getattr(self, 'GET_STUFF')
    tmp(self)
    

    这意味着这两个类是等价的:

    def foo(self): pass
    
    class Foo(object):
         a = foo
    
    class Bar(object):
         def a(self): pass
    

    在这两种情况下,函数对象都作为成员添加到类中,这意味着Python需要函数 self 作为第一参数。

    要实现您的目标:

    from API01 import getStuff01
    
    def wrapper01(self):
        getStuff01()
    
    class foo01(object):
        GET_STUFF = wrapper01
    
        2
  •  0
  •   Raydel Miranda    10 年前

    只是为了扩展Aaron答案,如果您想使用静态方法,可以使用@staticmethoddecorator:

    class Calc:
    
      @staticmethod
      def sum(x, y):
        return x + y
    
    print (Calc.sum(3,4))
    
    >>> 7
    
        3
  •  0
  •   MagSec    10 年前

    我已经认为我的对象正在调用引用的函数,并将其自身作为参数。经过一番研究,我终于找到了解决办法。当我使用类变量指向函数时,它不会引用直接指针。它将函数引用为其类的一个反弹方法。要摆脱调用方法的默认调用,请使用 getattr ,的调用函数 获取属性 因为类本身必须被覆盖(在这种情况下,类 bar 因为 foo (包装类)继承了 酒吧 :

    import inspect
    
    class bar(object):
        GET_STUFF = None
    
        def __getattribute__(self, name):
            attr = object.__getattribute__(self,name)
            if name == "GET_STUFF":
                # Check: is method and is bounced?
                if inspect.ismethod(attr) and attr.im_self is not None:
                    return attr.__func__
            return attr
    

    获取属性 属于 酒吧 现在指向原始函数引用,但仅指向类变量 GET_STUFF ,因为我想为其余变量保留默认功能。

    因此,当我现在执行以下操作时:

     class foo(bar):
        GET_STUFF = getStuff
    
        def __init__(self):
            print "inner func: ",self.GET_STUFF
            self.GET_STUFF()
    
    foo()
    

    我得到了预期的结果,可以编写我的包装器,而无需为带有这些包装器类的每个模块生成额外的代码:

    outer func:  <function getStuff at 0x00000000034259E8>
    inner func:  <function getStuff at 0x00000000034259E8>
    I do my stuff!!!