将其他文件中的函数添加到Python类

将其他文件中的函数添加到Python类,python,class,inheritance,Python,Class,Inheritance,我在这个设置上遇到了问题,主要是因为我不确定我到底想要什么来解决这个问题 这是设置 - main.py - lib - __init__.py - index.py - test.py \uuuu init\uuuu.py有以下代码 import os for module in os.listdir(os.path.dirname(__file__)+"/."): if module == '__init__.py' or module[-3:] != '.py':

我在这个设置上遇到了问题,主要是因为我不确定我到底想要什么来解决这个问题

这是设置

- main.py
- lib
  - __init__.py 
  - index.py
  - test.py
\uuuu init\uuuu.py有以下代码

import os
for module in os.listdir(os.path.dirname(__file__)+"/."):
    if module == '__init__.py' or module[-3:] != '.py':
        continue
    __import__(module[:-3], locals(), globals())
del module
class User(object):
    def test(self):
        return "hi"
    pass
class User(object):
    def tes2(self):
        return "hello"
main.py现在有此代码

from lib.index import *
print User.__dict__
index.py有以下代码

import os
for module in os.listdir(os.path.dirname(__file__)+"/."):
    if module == '__init__.py' or module[-3:] != '.py':
        continue
    __import__(module[:-3], locals(), globals())
del module
class User(object):
    def test(self):
        return "hi"
    pass
class User(object):
    def tes2(self):
        return "hello"
test.py有以下代码

import os
for module in os.listdir(os.path.dirname(__file__)+"/."):
    if module == '__init__.py' or module[-3:] != '.py':
        continue
    __import__(module[:-3], locals(), globals())
del module
class User(object):
    def test(self):
        return "hi"
    pass
class User(object):
    def tes2(self):
        return "hello"
当我执行
main.py
时,它成功地从
index.py
打印出方法
test
,但我想做的是找到一种方法,在lib文件夹中创建一个文件,而该文件在格式中只有一个函数

class User(object):
    def newFunction(self):
       return abc
这个函数应该在main.py中自动对我可用


我确信这不是一件困难的事情,但我真的不知道我想要什么(搜索什么来解决这个问题),这妨碍了我研究解决方案。

您可以使用元类自定义类创建并添加其他地方定义的函数:

import types
import os
import os.path
import imp

class PluginMeta(type):
    def __new__(cls, name, bases, dct):
        modules = [imp.load_source(filename, os.path.join(dct['plugindir'], filename))
                    for filename in os.listdir(dct['plugindir']) if filename.endswith('.py')]
        for module in modules:
            for name in dir(module):
                function = getattr(module, name)
                if isinstance(function, types.FunctionType):
                    dct[function.__name__] = function
        return type.__new__(cls, name, bases, dct)


class User(object):
    __metaclass__ = PluginMeta
    plugindir = "path/to/the/plugindir"

    def foo(self):
        print "foo"

user = User()
print dir(user)
然后在插件文件中,只需创建函数而不是类:

def newFunction(self, abc):
    self.abc = abc
    return self.abc

元类将找到它们,将它们转换为方法,并将它们附加到类中。

类是对象,方法只不过是类对象上的属性

因此,如果您想将方法添加到现有类中,在原始类块之外,所有这一切都是向对象添加属性的问题,我希望您知道如何做到:

class User(object):
    pass

def newFunction(self):
    return 'foo'

User.newFunction = newFunction
agf的元类答案基本上是一种巧妙的自动实现方法,尽管其工作原理是在创建类之前向类块添加额外的定义,而不是在创建类之后向类对象添加额外的属性

这基本上就是开发一个框架所需的全部内容,在这个框架中,一个模块中定义的内容将自动添加到其他地方定义的类中。但您仍然需要做出一些设计决策,例如:

  • 如果外部定义的函数需要辅助定义,那么如何确定应该添加到类中的内容以及依赖项
  • 如果您有多个这样扩展的类,那么如何确定在哪个类中使用了什么
  • 自动扩展在程序中的什么点发生
  • 你想在你的类中说“这个类在别处定义了扩展”,还是在你的扩展中说“这是一个在别处定义的类的扩展”,或者两者都不存在,并且在某个地方从外部将扩展绑定到这两个类
  • 您是否需要能够同时激活具有不同扩展的“同一”类的多个版本

  • agf提出的元类可能是实现这种框架的一种非常好的方法,因为它允许您将所有复杂的代码放在一个地方,同时仍然“标记”每个不按类正常工作方式工作的类。不过,它确实解决了我上面提出的一些问题。

    这里是我们在项目中使用的工作代码,我不确定这是最好的方法,但它工作了,而且几乎没有额外的代码添加到其他文件中

    cpu.py:

    from cpu_base import CPU, CPUBase
    
    import cpu_common
    import cpu_ext
    
    cpu_base.py:

    def getClass():
        return __cpu__
    
    def setClass(CPUClass):
        global __cpu__
        __cpu__ = CPUClass
        __classes__.append(CPUClass)
    
    def CPU(*kw):
        return __cpu__(*kw)
    
    class CPUBase:
        def __init__(self):
            your_init_Stuff
            # optionally a method classname_constructor to mimic __init__ for each one
            for c in __classes__:
                constructor = getattr(c, c.__name__ + '_constructor', None)
                if constructor is not None:
                    constructor(self)
    setClass(CPUBase)
    
    cpu_common.py:

    from cpu_base import getClass, setClass
    class CPUCommon(getClass()):
        def CPUCommon_constructor(self):
            pass
    setClass(CPUCommon)
    
    cpu_ext.py:

    from cpu_base import getClass, setClass
    
    class CPUExt(getClass()):
        pass
    setClass(CPUExt)
    

    使用类import CPU from CPU.py

    实现Ruby的开放类思想会导致一个难以调试的代码。您好,它给了我一个错误
    dct[function.\uuu name\uuu]=types.MethodType(function)TypeError:调用元类基instancemethod时出错,需要至少2个参数,修复了1个
    @Kartik。正确的版本是
    types.MethodType(function,cls)
    非常感谢。代码在为目录添加函数方面起作用,但我在访问它们时遇到了问题。在这种情况下,我似乎无法在任何文件中调用
    self.foo()
    。我得到的错误是PluginMeta没有属性foo。那不应该是
    User()
    ?@Kartik我不知道你的意思。您可以使用的唯一位置是实例方法内部--
    User
    上的实例方法内部,或者
    PluginMeta
    正在为您转变为实例方法的一个插件函数内部。您不能在任何其他地方调用
    self.foo()
    ,插件文件中也不应该有任何其他代码。@Kartik好的,明白了。我的错误。这又是同一行——调用
    MethodType
    是完全错误的;我很困惑。我修复了上面的代码,但只需将该行更改为
    dct[function.\uuuu name\uuuu]=function
    ,您就可以了。