Добавление функций из других файлов в класс Python - PullRequest
1 голос
/ 26 марта 2012

У меня проблемы с этой настройкой, главным образом потому, что я не уверен, чего на самом деле хочу, чтобы решить эту проблему.

Это настройка

- main.py
- lib
  - __init__.py 
  - index.py
  - test.py

__ init__.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

main.py имеет этот код на данный момент

from lib.index import *
print User.__dict__

index.py имеет этот код

class User(object):
    def test(self):
        return "hi"
    pass

test.py имеет этот код

class User(object):
    def tes2(self):
        return "hello"

При выполнении main.py он успешно печатает метод test из index.py но я пытаюсь найти способ, с помощью которого я могу просто создать файл в папке lib, где у него имеется только одна функция в формате

class User(object):
    def newFunction(self):
       return abc

, и эта функция должна быть автоматически доступнадля меня в main.py

Я уверен, что это не сложно сделать, но я, честно говоря, не знаю, что я хочу (что искать, чтобы решить эту проблему), что мешает мне исследоватьрешение.

Ответы [ 3 ]

2 голосов
/ 26 марта 2012

Вы можете использовать метакласс для настройки создания классов и добавления функций, определенных в других местах:

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

Иmetaclass найдет их, превратит в методы и присоединит к вашему классу.

1 голос
/ 26 марта 2012

Классы - это объекты, а методы - не более чем атрибуты объектов-классов.

Поэтому, если вы хотите добавить метод к существующему классу вне исходного блока класса, все, что вам нужно - это добавить атрибут к объекту, что, я надеюсь, вы знаете, как это сделать:

class User(object):
    pass

def newFunction(self):
    return 'foo'

User.newFunction = newFunction

Ответ метакласса agf - это в основном изящный автоматический способ сделать это, хотя он работает путем добавления дополнительных определений в блок класса до создания класса, вместо добавления дополнительных атрибутов к объекту класса впоследствии.

Это должно быть практически все, что вам нужно для разработки инфраструктуры, в которой вещи, определенные в одном модуле, автоматически добавляются в класс, определенный в другом месте. Но вам все равно нужно принять ряд дизайнерских решений, таких как:

  1. Если вашим внешне определенным функциям нужны вспомогательные определения, как вы определяете, что должно быть добавлено в класс и что является просто зависимостью?
  2. Если у вас есть несколько классов, которые вы расширяете таким образом, как вы определяете, что входит в этот класс?
  3. В какой момент (ы) в вашей программе происходит автоматическое расширение?
  4. Вы хотите сказать в своем классе "у этого класса есть расширения, определенные в другом месте", или в ваших расширениях сказать "это расширение для класса, определенного в другом месте", или ни одно из них и где-то не связывает расширения с классами извне из обоих?
  5. Нужно ли иметь возможность иметь несколько версий "одного" класса с разными активными расширениями одновременно?

Метакласс, такой как предложенный agf, может быть очень хорошим способом реализации такого рода фреймворков, потому что он позволяет вам поместить весь сложный код в одно место, все еще «помечая» каждый класс, который не работает так, как классы. нормально работают. Тем не менее, он исправляет ответы на некоторые из вопросов, которые я поставил выше.

0 голосов
/ 26 марта 2012

здесь рабочий код, который мы использовали в проекте, я не уверен, что это лучший способ, но он работал, и почти нет дополнительного кода для добавления в другие файлы

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)

для использования класса importCPU от cpu.py

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...