Python:具有相同名称的常规方法和静态方法

cal*_*531 15 python static class decorator

介绍

我有一个Python类,其中包含许多方法.我希望其中一个方法具有静态对应物 - 即具有相同名称的静态方法 - 可以处理更多参数.经过一番搜索,我发现我可以使用@staticmethod装饰器来创建一个静态方法.

问题

为方便起见,我创建了一个简化的测试用例来重现问题:

class myclass:

    @staticmethod
    def foo():
        return 'static method'

    def foo(self):
        return 'public method'

obj = myclass()
print(obj.foo())
print(myclass.foo())
Run Code Online (Sandbox Code Playgroud)

我希望上面的代码将打印以下代码:

public method
static method
Run Code Online (Sandbox Code Playgroud)

但是,代码打印以下内容:

public method
Traceback (most recent call last):
  File "sandbox.py", line 14, in <module>
    print(myclass.foo())
TypeError: foo() missing 1 required positional argument: 'self'
Run Code Online (Sandbox Code Playgroud)

从这里,我只能假设调用myclass.foo()尝试调用其非静态对应物而没有参数(这将无效,因为非静态方法总是接受参数self).这种行为让我感到困惑,因为我希望对静态方法的任何调用都能实际调用静态方法.

我已经在Python 2.7 3.3中测试了这个问题,只是为了收到同样的错误.

问题

为什么会发生这种情况,我该如何修复我的代码以便打印:

public method
static method
Run Code Online (Sandbox Code Playgroud)

正如我所料?

joh*_*aas 13

类似的问题在这里:在python编程中覆盖具有相同名称的方法

函数按名称查找,因此您只需使用实例方法重新定义foo.在Python中没有重载函数这样的东西.您可以使用单独的名称编写新函数,也可以以可以处理两者的逻辑的方式提供参数.

换句话说,您不能拥有相同名称的静态版本和实例版本.如果你看它,vars你会看到一个foo.

In [1]: class Test:
   ...:     @staticmethod
   ...:     def foo():
   ...:         print 'static'
   ...:     def foo(self):
   ...:         print 'instance'
   ...:         

In [2]: t = Test()

In [3]: t.foo()
instance

In [6]: vars(Test)
Out[6]: {'__doc__': None, '__module__': '__main__', 'foo': <function __main__.foo>}
Run Code Online (Sandbox Code Playgroud)


Mat*_*son 11

因为Python中的属性查找是程序员控制的内容,所以这种技术在技术上是可行的.如果你把任何值放在以"pythonic"方式编写代码中(使用python社区的首选约定和习惯用法),很可能是构建问题/设计的错误方法.但是如果你知道描述符如何允许你控制属性查找,以及函数如何成为绑定函数(提示:函数描述符),你可以完成大致你想要的代码.

对于给定的名称,只有一个对象可以在类上查找,无论您是在类的实例上查找名称,还是在类本身上查找名称.因此,你正在查找的东西必须处理这两种情况,并适当地发送.

(注意:这不完全正确;如果实例在其属性名称空间中的名称与其类的名称空间中的名称发生冲突,则实例上的值将在某些情况下获胜.但即使在这些情况下,它也赢了不会像你希望的那样成为一种"约束方法".)

我不建议使用这样的技术来设计您的程序,但以下内容将大致按照您的要求进行.了解它的工作原理需要对python作为一种语言有一个相对深刻的理解.

class StaticOrInstanceDescriptor(object):

    def __get__(self, cls, inst):
        if cls is None:
            return self.instance.__get__(self)
        else:
            return self.static

    def __init__(self, static):
        self.static = static

    def instance(self, instance):
        self.instance = instance
        return self


class MyClass(object):

    @StaticOrInstanceDescriptor
    def foo():
        return 'static method'

    @foo.instance
    def foo(self):
        return 'public method'

obj = MyClass()
print(obj.foo())
print(MyClass.foo())
Run Code Online (Sandbox Code Playgroud)

哪个打印出来:

% python /tmp/sandbox.py
static method
public method
Run Code Online (Sandbox Code Playgroud)


Dol*_*gan 11

虽然没有严格的可能做,正如所指出的那样,你可以通过在实例化时重新定义方法来"伪造"它,如下所示:

class YourClass(object):

    def __init__(self):
        self.foo = self._instance_foo

    @staticmethod
    def foo():
        print "Static!"

    def _instance_foo(self):
        print "Instance!"
Run Code Online (Sandbox Code Playgroud)

这会产生预期的结果:

>>> YourClass.foo()
Static!
>>> your_instance = YourClass()
>>> your_instance.foo()
Instance!
Run Code Online (Sandbox Code Playgroud)


cod*_*ros 5

从谷歌来到这里,所以我想我会发布我对这个“问题”的解决方案......

class Test():
    def test_method(self=None):
        if self is None:
            print("static bit")
        else:
            print("instance bit")
Run Code Online (Sandbox Code Playgroud)

这样您就可以像静态方法或实例方法一样使用该方法。