Python: 使用 import 将常用函数添加到 class
Python: Using import to add common functions into a class
我有一个现有的 python (python v2.7) 应用程序,它可以即时导入外部 py 文件,其中包含专门命名为 classes 来处理数据。加载的外部py文件是根据post-处理所需数据的类型选择的。
所以我收集了 classes,每个都在自己的文件中。这些文件根据处理类型以特定方式命名,以便主程序知道要从上游请求导入什么文件。
请记住,我和其他人总是在调整这些 class 文件,但我们无法更改主应用程序上的代码。
我想做的是将 "template" 的常用函数导入到 class 作用域中,它可以提供主程序期望的标准控件集,而无需 copy/paste 将它们放入每个文件中。当我发现一个错误并在其中一个主要 class i/o 函数中进行更正时,我讨厌它,然后我必须在三十多个其他文件中复制它。
现在,我通过谷歌搜索了解到我在此处的导入是错误的...我收到消息:
TestClassFile.py:5: SyntaxWarning: import * only allowed at module level
但这种方法是我找到的唯一导入函数的方法,以便它们进入 class 本身的命名空间。我在下面有一个例子...
在 Python 中执行此操作的适当方法(如果有)是什么?
例子
main.py
import TestClassFile
print "New TestClass - Init"
oTest = TestClassFile.TestClass("foo")
print "Should run... Function A"
oTest.funcA()
print "Should run... Function b"
oTest.funcB()
TestClassFile.py
class TestClass:
from TestClassImport import *
def __init__(self, str):
print "INIT! and be ... ", str
def funcA(self):
print "Function A"
TestClassImport.py
def funcB(self):
print "Function B"
非常感谢!
更新
非常感谢大家的贡献。通过研究 MixIn,这些似乎是扩展 class.
的正确 python 方法
TestClassImport.py
class ImportClass:
def funcB(self):
print "Function B"
TestClassFile.py
from TestClassImport import ImportClass
class TestClass(ImportClass):
def __init__(self, str):
print "INIT! and be ... ", str
def funcA(self):
print "Function A"
听起来你应该把导入的函数做成mixin,你可以从中继承。所以:
TestClassImport.py
class ClassB(object):
def funcB(self):
print "Function B"
TestClassFile.py
from TestClassImport import ClassB
from OtherClassImport import ClassX
class TestClass(ClassB, ClassX):
...
我不知道这是否是一个好的解决方案,但是您可以编写一个函数来构造一个元class动态添加属性你的 classes.
def make_meta(*import_classes):
class TestMeta(type):
def __new__(meta, name, bases, dct):
new_class = super(TestMeta, meta).__new__(meta, name, bases, dct)
for import_class in import_classes:
for name in vars(import_class):
if not name.startswith('__'):
prop = getattr(import_class, name)
setattr(new_class, name, prop)
return new_class
return TestMeta
class TestClass:
import TestClassImport
__metaclass__ = make_meta(TestClassImport)
# other functions defined as normal...
这将在 TestClassImport.py 的全局范围内添加不以 '__' 开头的所有内容作为 TestClass
上的 属性。
或者,您可以使用 class 装饰器以相同的方式动态添加属性。
def add_imports(*import_classes):
def augment_class(cls):
for import_class in import_classes:
for name in vars(import_class):
if not name.startswith('__'):
prop = getattr(import_class, name)
setattr(cls, name, prop)
return cls
return augment_class
import TestClassImport
@add_imports(TestClassImport)
class TestClass:
# normal class body
但是 mixin 似乎是一种更好的方法。
这似乎有效:
import types
from TestClassImport import funcB
class TestClass:
def __init__(self, str):
print "INIT! and be ... ", str
setattr(self, 'funcB', types.MethodType(funcB, self, TestClass))
def funcA(self):
print "Function A"
当我 运行 它时,我得到以下输出:
INIT! and be ... foo
Should run... Function A
Function A
Should run... Function b
Function B
您可以为此使用 importlib,例如:
import importlib
class TestClass:
def __init__(self, module_name):
_tmp = importlib.import_module(module_name)
for elem in _tmp.__dir__():
if not elem.startswith('_'):
prop = getattr(_tmp, elem)
setattr(self, elem, prop)
def funcA(self):
print("function A")
tc = TestClass('some_module')
tc.funcB()
>>> prints "function B"
使用这种方法,您可以创建函数 load_module(module_name)
而不是 __init__()
来独立加载彼此的模块(例如,防止名称冲突)。
我有一个现有的 python (python v2.7) 应用程序,它可以即时导入外部 py 文件,其中包含专门命名为 classes 来处理数据。加载的外部py文件是根据post-处理所需数据的类型选择的。
所以我收集了 classes,每个都在自己的文件中。这些文件根据处理类型以特定方式命名,以便主程序知道要从上游请求导入什么文件。
请记住,我和其他人总是在调整这些 class 文件,但我们无法更改主应用程序上的代码。
我想做的是将 "template" 的常用函数导入到 class 作用域中,它可以提供主程序期望的标准控件集,而无需 copy/paste 将它们放入每个文件中。当我发现一个错误并在其中一个主要 class i/o 函数中进行更正时,我讨厌它,然后我必须在三十多个其他文件中复制它。
现在,我通过谷歌搜索了解到我在此处的导入是错误的...我收到消息:
TestClassFile.py:5: SyntaxWarning: import * only allowed at module level
但这种方法是我找到的唯一导入函数的方法,以便它们进入 class 本身的命名空间。我在下面有一个例子...
在 Python 中执行此操作的适当方法(如果有)是什么?
例子
main.py
import TestClassFile
print "New TestClass - Init"
oTest = TestClassFile.TestClass("foo")
print "Should run... Function A"
oTest.funcA()
print "Should run... Function b"
oTest.funcB()
TestClassFile.py
class TestClass:
from TestClassImport import *
def __init__(self, str):
print "INIT! and be ... ", str
def funcA(self):
print "Function A"
TestClassImport.py
def funcB(self):
print "Function B"
非常感谢!
更新
非常感谢大家的贡献。通过研究 MixIn,这些似乎是扩展 class.
的正确 python 方法TestClassImport.py
class ImportClass:
def funcB(self):
print "Function B"
TestClassFile.py
from TestClassImport import ImportClass
class TestClass(ImportClass):
def __init__(self, str):
print "INIT! and be ... ", str
def funcA(self):
print "Function A"
听起来你应该把导入的函数做成mixin,你可以从中继承。所以:
TestClassImport.py
class ClassB(object):
def funcB(self):
print "Function B"
TestClassFile.py
from TestClassImport import ClassB
from OtherClassImport import ClassX
class TestClass(ClassB, ClassX):
...
我不知道这是否是一个好的解决方案,但是您可以编写一个函数来构造一个元class动态添加属性你的 classes.
def make_meta(*import_classes):
class TestMeta(type):
def __new__(meta, name, bases, dct):
new_class = super(TestMeta, meta).__new__(meta, name, bases, dct)
for import_class in import_classes:
for name in vars(import_class):
if not name.startswith('__'):
prop = getattr(import_class, name)
setattr(new_class, name, prop)
return new_class
return TestMeta
class TestClass:
import TestClassImport
__metaclass__ = make_meta(TestClassImport)
# other functions defined as normal...
这将在 TestClassImport.py 的全局范围内添加不以 '__' 开头的所有内容作为 TestClass
上的 属性。
或者,您可以使用 class 装饰器以相同的方式动态添加属性。
def add_imports(*import_classes):
def augment_class(cls):
for import_class in import_classes:
for name in vars(import_class):
if not name.startswith('__'):
prop = getattr(import_class, name)
setattr(cls, name, prop)
return cls
return augment_class
import TestClassImport
@add_imports(TestClassImport)
class TestClass:
# normal class body
但是 mixin 似乎是一种更好的方法。
这似乎有效:
import types
from TestClassImport import funcB
class TestClass:
def __init__(self, str):
print "INIT! and be ... ", str
setattr(self, 'funcB', types.MethodType(funcB, self, TestClass))
def funcA(self):
print "Function A"
当我 运行 它时,我得到以下输出:
INIT! and be ... foo
Should run... Function A
Function A
Should run... Function b
Function B
您可以为此使用 importlib,例如:
import importlib
class TestClass:
def __init__(self, module_name):
_tmp = importlib.import_module(module_name)
for elem in _tmp.__dir__():
if not elem.startswith('_'):
prop = getattr(_tmp, elem)
setattr(self, elem, prop)
def funcA(self):
print("function A")
tc = TestClass('some_module')
tc.funcB()
>>> prints "function B"
使用这种方法,您可以创建函数 load_module(module_name)
而不是 __init__()
来独立加载彼此的模块(例如,防止名称冲突)。