【问题标题】:backport function modifiers to python2.1将函数修饰符向后移植到 python2.1
【发布时间】:2009-07-21 12:57:51
【问题描述】:

我有一些我用 python 2.4++ 开发的代码,你敢打赌,我必须将它反向移植到 python 2.1!

函数装饰器非常吸引人,以至于我在一些地方使用了@classmethod,而没有注意到它仅在版本 2.4 开始可用。函数修饰符提供了相同的功能,但这些出现在 python 2.2 中。 cfr:http://www.python.org/dev/peps/pep-0318/

现在我们的一些客户似乎仍然依赖于 python 2.1(ArcGIS 9.1 附带它并使其不可升级),甚至函数修饰符都不可用...

我一直在寻找 python 2.1 中的一些函数修饰符定义,但我没有找到任何(我的意思是:工作)。有人成功解决了这个问题吗?

更具体地说,我需要一种在 python 2.1 中运行此 2.4 代码的方法:

Python 2.4.6 (#2, Mar 19 2009, 10:00:53) 
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class sic:
...   def f(cls):
...     print cls.__name__
...   f = classmethod(f)
... 
>>> sic().f()
sic
>>> sic.f()
sic
>>> 

【问题讨论】:

  • 您的客户可以安装最新版本的 python 和 2.1,它可以正常工作。
  • 是的,那很好,但我知道这是不可能的,因为 ArcGIS 9.1 与 python 2.1 确实是硬连接的。

标签: python syntax backport


【解决方案1】:

就像我在 2.1 静态方法的旧配方中一样:

class staticmethod:
    def __init__(self, thefunc): self.f = thefunc
    def __call__(self, *a, **k): return self.f(*a, **k)

你应该能够做一个 2.1 类方法:

class classmethod:
    def __init__(self, thefunc): self.f = thefunc
    def __call__(self, obj, *a, **k): return self.f(obj.__class__, *a, **k)

当然不是@-syntax,而是旧的方式(如2.2):

class sic:
  def f(cls): ...
  f = classmethod(f)

如果这不起作用(抱歉,自从我测试 Python 2.1 以来已经有很多年了),需要更明确地提供该类——并且由于您在类对象存在之前调用 classmethod,它需要按名称命名——假设是一个全局类,

class classmethod2:
    def __init__(self, thefunc, clsnam):
        self.f = thefunc
        self.clsnam = clsnam
    def __call__(self, *a, **k):
        klass = globals()[self.clsnam]
        return self.f(klass, *a, **k)

class sic2:
  def f(cls): ...
  f = classmethod2(f, 'sic2')

真的很难找到优雅的方法来获取类对象(抑制对 self 的需要是很容易的部分,而静态方法就足够了:你只需要将函数包装成一个非函数可调用),因为 2.1 只有遗留(旧式类),没有可用的元类,因此没有真正好的方法让 sic2.f() 神奇地获得该 cls。

由于 2.1 中缺少 @ 语法不可避免地需要编辑使用 @classmethod 的代码,因此另一种方法是将功能(将一些方法装饰为“类”方法)向右移动到 class 的末尾之后声明(优点是那个时候类对象确实存在)。

class classmethod3:
    def __init__(self, thefunc, klass):
        self.f = thefunc
        self.klass = klass
    def __call__(self, *a, **k):
        return self.f(self.klass, *a, **k)

def decorate(klass, klassmethodnames):
  for n in klassmethodnames:
    thefunc = klass.__dict__[n]
    setattr(klass, n, classmethod3(thefunc, klass))

class sic2:
  def f(cls): ...
  def g(self): ...
  def h(cls): ...
decorate(sic2, ['f', 'h'])

【讨论】:

  • 你在 python2.1 中测试过你的代码吗?在这里它不起作用,它在任何一种情况下都会给出»TypeError:__call__()至少需要2个参数(1个给定)«
  • 抱歉,没有 Python 2.1 可供测试(从很多年前开始)。
  • 好的,编辑答案以添加一些可能更好的替代方案(一个糟糕,一个更少)! (仍然无法在 2.1 上测试,但古老的霉味记忆开始卷土重来......;-)。
  • 附注:在 classmethod2 »klass = globals()['clsnam']« 应该是 »klass = globals()[self.clsnam]«
【解决方案2】:

如果只需要将 @classmethod 向后移植到 Python 2.1。
有一个recipe of Classmethod emulation in python2.1
希望对您有所帮助。

【讨论】:

  • 不:这是我找到的食谱之一。它不起作用。 »在 python 2.2 中,使用类方法,您可以编写如下内容:Foo.bar()。与之前的 classmethod 函数 raise 相同:必须以实例作为第一个参数调用未绑定的方法。«
  • 如配方注释中所示,您需要嵌套范围: from future import nested_scopes
  • __future__导入nested_scopes
  • from __future__ import nested_scopes #这次应该是正确的
  • 这不是主要问题:如果没有该导入,代码根本无法工作。通过该导入,代码仍然无法执行预期的操作,并在调用修改后的函数时导致异常。
猜你喜欢
  • 1970-01-01
  • 2019-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-09
  • 2019-07-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多