Подтвердить что ты не робот

Есть ли эквивалент Python для частичных классов?

Использование "новых" классов стиля (я нахожусь в python 3.2), есть ли способ разделить класс на несколько файлов? У меня большой класс (который действительно должен быть одним классом с точки зрения объектно-ориентированного дизайна, учитывая связь и т.д., Но было бы неплохо разбить несколько файлов просто для облегчения редактирования класса.

4b9b3361

Ответ 1

Если ваша проблема действительно работает с большим классом в редакторе, первое решение, которое я действительно искал, - лучший способ разбить проблему. Второе решение будет лучшим редактором, желательно с фальцованием кода.

Тем не менее, существует несколько способов разбить класс на несколько файлов. Python позволяет вам использовать папку в качестве модуля, помещая в нее __init__.py, который затем может импортировать файлы из других файлов. Мы будем использовать эту возможность в каждом решении. Сначала создайте папку, называемую bigclass.

  • В папке помещаются различные .py файлы, которые в конечном итоге будут содержать ваш класс. Каждый из них должен содержать функции и определения переменных для конечного класса, а не классов. В __init__.py в той же папке напишите следующее, чтобы объединить их все вместе.

    class Bigclass(object):
    
        from classdef1 import foo, bar, baz, quux
        from classdef2 import thing1, thing2
        from classdef3 import magic, moremagic
        # unfortunately, "from classdefn import *" is an error or warning
    
        num = 42   # add more members here if you like
    

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

  • Вы можете использовать множественное наследование для объединения различных частей вашего класса. В ваших отдельных модулях вы должны написать определение класса для bigclass с частями класса. Затем в __init__.py напишите:

    import classdef1, classdef2, classdef3
    
    class Bigclass(classdef1.Bigclass, classdef2.Bigclass, classdef3.Bigclass):
        num = 42   # add more members if desired
    
  • Если множественное наследование становится проблемой, вы можете использовать одиночное наследование: просто каждый класс наследуется от другого по цепочке. Предполагая, что вы не определяете ничего более чем в одном классе, порядок не имеет значения. Например, classdef2.py будет выглядеть следующим образом:

    import classdef1
    class Bigclass(classdef1.Bigclass):
         # more member defs here
    

    classdef3 будет импортировать bigclass из classdef2 и добавить к нему и т.д. Ваш __init__.py просто импортирует последний:

    from classdef42 import Bigclass
    

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

Чтобы использовать класс в любом из этих сценариев, вы можете просто импортировать его, используя имя папки в качестве имени модуля: from bigclass import Bigclass

Ответ 2

Определения классов, содержащие сотни строк, встречаются "в дикой природе" (я видел некоторые из популярных open-source Python-фреймворков), но я считаю, что если вы подумаете о том, что делают эти методы, можно будет уменьшите длину большинства классов до управляемой точки. Некоторые примеры:

  • Найдите места, где чаще всего один и тот же код встречается более одного раза. Разбейте этот код на свой собственный метод и вызовите его из каждого места с аргументами.
  • "Private" методы, которые не используют какое-либо из состояния объекта, могут быть выведены из класса в виде автономных функций.
  • Методы, которые должны вызываться только при определенных условиях, могут указывать на необходимость размещения этих методов в подклассе.

Чтобы напрямую обратиться к вашему вопросу, можно разделить определение класса. Один из способов - это "обезьяна-патч" класса, определяя его, а затем добавляя к нему внешние функции как методы. Другим является использование встроенной функции type для создания класса "вручную", предоставления его имени, любых базовых классов и его методов и атрибутов в словаре. Но я не рекомендую делать это только потому, что определение будет длинным в противном случае. Такое вид лечения хуже, чем заболевание, на мой взгляд.

Ответ 3

Я раньше играл с чем-то похожим. Мой usecase был иерархией классов узлов в абстрактном синтаксическом дереве, а затем я хотел поместить все, например. prettyprinting в отдельном файле prettyprint.py, но все еще имеют их как методы в классах.

Одна вещь, которую я пробовал, - использовать декоратор, который помещает украшенную функцию как атрибут в указанный класс. В моем случае это означало бы, что prettyprint.py содержит много def prettyprint(self), украшенных разными @inclass(...)

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

def inclass(kls):
    """
    Decorator that adds the decorated function
    as a method in specified class
    """
    def _(func):
        setattr(kls,func.__name__, func)
        return func
    return _

## exampe usage
class C:
    def __init__(self, d):
        self.d = d

# this would be in a separate file.
@inclass(C)
def meth(self, a):
    """Some method"""
    print "attribute: %s - argument: %s" % (self.d, a)

i = C(10)
print i.meth.__doc__
i.meth(20)

Ответ 4

Вы можете сделать это с помощью декораторов:

class Car(object):

    def start(self):
    print 'Car has started'


def extends(klass):
    def decorator(func):
      setattr(klass, func.__name__, func)
      return func
    return decorator

#this can go in a different module/file
@extends(Car)
def do_start(self):
    self.start()


#so can this
car = Car()
car.do_start()

#=> Car has started

Ответ 5

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

Кажется, есть еще несколько способов реализовать это сами.

Вы можете реализовать отдельные части класса как mixins в отдельных файлах, а затем импортировать их где-нибудь и подклассировать их.

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

a.py:

def AFunc( self, something ):
    # Do something
    pass

b.py:

def BFunc( self, something ):
    # Do something else
    pass

c.py:

import a, b

class C:
    AFunc = a.AFunc
    BFunc = b.BFunc

Вы даже можете зайти так далеко, чтобы автоматизировать этот процесс, если вы действительно хотите - пропустите все функции, предоставляемые модулями a и b, а затем добавьте их как атрибуты на C. Хотя это может быть полный перебор.

Могут быть другие (возможно, более эффективные) способы обойти это, но это те 2, которые появились в виду.

Ответ 6

Я встретил ту же ситуацию - я хочу нарезать свой класс на 2 файла. причина в том, что я хочу часть 1 для графического интерфейса GUI, только макет и другой файл сохраняет все функции. как С# Partial class. один для XAML и еще один для функций.

Ответ 7

Во-первых, я не вижу, как разделение класса на несколько файлов упрощает редактирование. Порядочная среда IDE должна иметь возможность легко найти любой метод, будь то в одном файле или несколько; если вы не используете достойную среду IDE, разделение класса означает, что сопровождающий должен угадать, к какому файлу относится данный метод, который звучит сложнее, а не проще.

Более фундаментально этот класс - настолько большой, что вам нужна специальная языковая функция только для поддержки своего веса - звуки принципиально нарушаются. Сколько строк кода мы говорим? Почти наверняка было бы лучше сделать одно из:

  • Рефактор дублирует код на более простые, более общие примитивы
  • Определите базовый класс и расширьте его с помощью подклассов, как предлагает Karoly Horvath в комментариях (это самое близкое к "частичным классам", которые вы просите, я бы одобрил)
  • Определите несколько отдельных классов для инкапсуляции различных частей этого класса и составляют этот класс экземпляров этих меньшие.

Ответ 8

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

  • Запишите класс в несколько файлов, затем прочитайте их как текст, объедините их и exec результирующую строку.

  • Создайте отдельный класс в каждом файле, затем наследуйте их все в мастер-класс как mixins. Однако, если вы подклассифицируете другой класс, это может привести к проблемам MRO. Вы можете обойти это, создав метакласс для своего мастер-класса, который вручную разрешает MRO, но это может стать беспорядочным.

Самый простой вариант - это первый вариант.