在这里和那里使用大量导入函数创建 类
Creating classes with a lot of imported functions here and there
假设我在 alotoffunc.py
中有很多函数被不止一种类型的对象使用。
假设ObjectI
和ObjectII
和ObjectXI
都使用了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 *
然后,如果 - 例如 - 我们有变量 o1
、o2
,它们是 Object1
和 Object2
的实例,我们可以这样做:
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
假设我在 alotoffunc.py
中有很多函数被不止一种类型的对象使用。
假设ObjectI
和ObjectII
和ObjectXI
都使用了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 *
然后,如果 - 例如 - 我们有变量 o1
、o2
,它们是 Object1
和 Object2
的实例,我们可以这样做:
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