在这里和那里使用大量导入函数创建 类

Creating classes with a lot of imported functions here and there

假设我在 alotoffunc.py 中有很多函数被不止一种类型的对象使用。

假设ObjectIObjectIIObjectXI都使用了alotoffunc.py中的一些函数。每个对象都使用不同的函数集,但所有对象都有变量 object.table.

alotoffunc.py:

def abc(obj, x):
  return obj.table(x) * 2

def efg(obj, x):
  return obj.table(x) * obj.table(x)

def hij(obj, x, y):
  return obj.table(x) * obj.table(y)

def klm(obj, x, y):
  return obj.table(x) *2 - obj.table(y)

然后我导入函数并重载它们:

import alotoffunc

class ObjectI:
  def abc(self, x):
    return alotoffunc.abc(self, x)

  def efg(self, x):
    return alotoffunc.efg(self, x)

class ObjectII:
  def efg(self, x):
    return alotoffunc.efg(self, x)
  def klm(self, x, y): 
    return alotoffunc.klm(self, x, y)

class ObjectXI:
  def abc(self, x):
    return alotoffunc.abc(self, x)
  def klm(self, x, y):
    return alotoffunc.klm(self, x, y)

现在看起来一团糟,我应该如何构建我的对象 class 并安排我的 alotoffunc.py

你可以这样做:

from alotoffunc import *

然后,如果 - 例如 - 我们有变量 o1o2,它们是 Object1Object2 的实例,我们可以这样做:

abc(o1,x)
efg(o2,x)
...

它不像调用 o1.abc(x) 的 OO 方法那样'pretty',但它比必须覆盖所有方法更易于维护。

from ___ import * 所做的是让您不必使用 alotoffunc.abc 等包名。

编辑

正如@JamesKing 评论的那样,如果您的 类 中有同名函数,则此解决方案不起作用。因为它们看起来没用——它们只是调用导入的函数——我正在考虑删除它们。如果这不适用于您的代码,您应该像他说的那样使用 from ___ import ___ as ___

(1) 你可以有一个实现所有方法的基础 class 然后覆盖不必要的方法以在子 class 中引发 NotImplementedError

(2) 你可以使用 mixin 来减少重复:

import alotoffunc

class MixinAbc:
    def abc(self, x):
        return alotoffunc.abc(self, x)

class MixinEfg:
    def efg(self, x):
        return alotoffunc.efg(self, x)

class MixinKlm:
    def klm(self, x, y):
        return alotoffunc.klm(self, x, y)

class ObjectI(MixinAbc, MixinEfg):
    pass

class ObjectII(MixinEfg, MixinKlm):
    pass    

class ObjectXI(MixinAbc, MixinKlm):
    pass

您也可以将此方法与@cpburnz 的方法结合使用。

最简单的方法是将所需函数作为实例方法直接绑定到其定义中的 class。请注意,每个函数都将接收 self 作为第一个参数。

import alotoffunc

class ObjectI:
  abc = alotoffunc.abc
  efg = alotoffunc.efg

class ObjectII:
  efg = alotoffunc.efg
  klm = alotoffunc.klm

class ObjectXI:
  abc = alotoffunc.abc
  klm = alotoffunc.klm

如果各种功能没有清晰、合乎逻辑的分组,这可能是定义混入 classes 的一种更简单的方法。分组确实取决于您的用例,因此混合方法可以根据情况更好。

如果我想避免混合,也许是为了尽量减少代码的不透明性,我会这样做:

class ObjectI:
    from alotoffunc import abc, efg

class ObjectII:
    from alotoffunc import efg, klm

class ObjectXI:
    from alotoffunc import abc, klm

只要您创建 class 的实例,导入的方法就会自动绑定。换句话说,它们默认是实例方法。

如果您希望它们是静态方法,请按如下方式使用 staticmethod

class ObjectI:
    from alotoffunc import abc, efg
    abc = staticmethod(abc)

此外,我不会太担心这些多个导入语句的性能问题,因为 Python 足够聪明,只 运行 一次导入模块,然后将其保存在内存中以防以后需要。

如果您要导入的函数有某种逻辑分组,那么您绝对应该使用 mixin,或者将函数组织到单独的 "mixin modules" 中,这样您甚至可以 from mixinmodule import *.对于 mixin-class 方法,我认为常规 import 语句比 from-import 效果更好,除非你的函数名很长而且你只想输入一次!

这是一种"factory"方法。如果你没有那么多功能,可能会过于复杂,但如果你真的有 "a lot",它可能会成功。

import alotoffunc

class Builder(object):
    def __init__(self, objtype):
        objtypes = { 'ObjectI': ['abc', 'efg'],
                     'ObjectII': ['efg', 'klm'],
                     'ObjectXI': ['abc', 'klm']}

        for func in objtypes[objtype]:
            self.__dict__[func] = getattr(alotoffunc, func)

这个怎么样:

import alotoffunc
import types

class ObjectI:
    def __init__(self):
        setattr(self, abc, types.MethodType(alotoffunc.abc, self))
        setattr(self, efg, types.MethodType(alotoffunc.efg, self))

class ObjectII:
    def __init__(self):
        setattr(self, efg, types.MethodType(alotoffunc.efg, self))
        setattr(self, klm, types.MethodType(alotoffunc.klm, self))

class ObjectXI:
    # ...

(可能会有一些瑕疵或错别字,但基本思路是正确的。我在代码中使用了类似的东西。

这会在创建时将原始函数绑定到每个实例。 setattr() 不是必需的,但我更喜欢用它来表示发生了一些 "magic".

我很确定有更好的方法可以在 class 对象中创建方法,但这可能需要 metaclasses and/or 更多魔法。

我认为实现目标的更简洁的方法是使用 python 的多重继承特性。许多程序员讨厌 MI,声称它会产生混乱的代码或难以维护。只要您在规划 classes 时小心,使用 MI 就会非常有帮助。

One of the many links returned by Google

SomeClasses.py -- 通常每个 class 都存储在一个单独的文件中。

class ABCClass:
    def abc(obj, x):
    return obj.table(x) * 2

class DEFClass:
    def efg(obj, x):
        return obj.table(x) * obj.table(x)

class HIJClass:
    def hij(obj, x, y):
        return obj.table(x) * obj.table(y)

class KLMClass:
    def klm(obj, x, y):
        return obj.table(x) *2 - obj.table(y)

TheProject.py -- 不需要额外的代码,除非你确实需要重写基础 classes 的功能。

import SomeClasses #or each class file

class ObjectI (ABCClass, EFGClass):
    pass

class ObjectII (EFGClass, KLMClass):
    pass

class ObjectXI (ABCClass, KLMClass):
    pass

当然这是一个微不足道的例子,每个碱基class只有一个功能。我想到的一个真实例子是将图像打包到共享纹理资源上。您想要 PIL.Image 附带的功能,但能够将图像存储为自制树数据结构中的叶节点。您可以使用多重继承来使用最少的代码获得两个 classes 的方法。 LeafImage 将具有两个 classes 的所有方法,当您决定修改 TreeLeaf 时,LeafImage 中不需要额外的代码。

class LeafImage (PIL.Image, TreeLeaf):
    pass