Использование "новых" классов стиля (я нахожусь в python 3.2), есть ли способ разделить класс на несколько файлов? У меня большой класс (который действительно должен быть одним классом с точки зрения объектно-ориентированного дизайна, учитывая связь и т.д., Но было бы неплохо разбить несколько файлов просто для облегчения редактирования класса.
Есть ли эквивалент Python для частичных классов?
Ответ 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, но это может стать беспорядочным.
Самый простой вариант - это первый вариант.