Python:使用import将常用函数添加到类中

时间:2017-06-23 21:44:47

标签: python python-2.7 python-import

我有一个现有的python(python v2.7)应用程序,可以动态导入外部py文件,其中包含专门命名的类来处理数据。加载的外部py文件是根据所需数据的后处理类型选择的。

所以我有这个类的集合,每个类都在自己的文件中。根据处理类型以特定方式命名文件,以便主程序知道从上游请求导入的文件。

请记住,我和其他人总是调整这些类文件,但我们无法更改主应用程序上的代码。

我想要做的是导入一个"模板"类通用函数可以提供主程序所需的标准控件集,而无需将它们复制/粘贴到每个文件中。当我发现一个错误并在其中一个主类i / o函数中进行修正时,我讨厌它,然后我必须在其他三十个文件中进行复制。

现在,我从谷歌上了解到我的导入很糟糕......我收到了消息:

TestClassFile.py:5: SyntaxWarning: import * only allowed at module level

但是这个方法是我找到导入函数的唯一方法,因此它们进入类本身的命名空间。我在下面有一个例子......

在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"

非常感谢!

更新

非常感谢大家的贡献。通过研究MixIns,这些似乎是扩展类的正确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"

4 个答案:

答案 0 :(得分:2)

听起来你应该将导入的函数变成mixins,你可以继承它们。所以:

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):
    ...

答案 1 :(得分:0)

我不知道这是否是一个好的解决方案,但你可以编写一个函数来构造一个元类来动态地为你的类添加属性。

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上的属性开头。

或者,您可以使用类装饰器以相同的方式动态添加属性。

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

但mixins似乎是一种更好的方法。

答案 2 :(得分:0)

这似乎有效:

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

答案 3 :(得分:0)

您可以使用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__()来相互独立地加载模块(例如,防止名称冲突)。