Самый "пуфонический" способ организации атрибутов класса, аргументов конструктора и значений по умолчанию для подкласса?

Будучи относительно новым для Python 2, я не знаю, как лучше всего организовать файлы классов в наиболее "питоническом" виде. Я бы не стал просить об этом, но из-за того, что у Python есть несколько способов сделать вещи, которые сильно отличаются от того, что я ожидал от языков, к которым я привык.

Вначале я просто рассматривал классы, как обычно я рассматривал их на С# или PHP, что, конечно, заставляло меня путешествовать по всему месту, когда я в конце концов обнаружил измененные значения gotcha:

class Pants(object):
    pockets = 2
    pocketcontents = []

class CargoPants(Pants):
    pockets = 200

p1 = Pants()
p1.pocketcontents.append("Magical ten dollar bill")
p2 = CargoPants()

print p2.pocketcontents

Хлоп! Не ожидал этого!

Я потратил много времени на поиск в Интернете и через какой-то источник для других проектов, чтобы узнать, как лучше всего организовать мои классы, и одна из вещей, которые я заметил, это то, что люди, похоже, объявляют множество своих переменных экземпляра - mutable или иначе - в конструкторе, а также скомпилировать аргументы конструктора по умолчанию довольно густо.

После такого развития некоторое время я все еще немного почесываю голову о незнакомости. Рассматривая длины, на которые идет язык python, чтобы сделать вещи более интуитивными и очевидными, мне кажется совершенно странным в тех немногих случаях, когда у меня довольно много атрибутов или много аргументов конструктора по умолчанию, особенно когда я Подклассы m:

class ClassWithLotsOfAttributes(object):
    def __init__(self, jeebus, coolness='lots', python='isgoodfun', 
             pythonic='nebulous', duck='goose', pants=None, 
             magictenbucks=4, datawad=None, dataload=None,
             datacatastrophe=None):

        if pants is None: pants = []
        if datawad is None: datawad = []
        if dataload is None: dataload = []
        if datacatastrophe is None: datacatastrophe = []
        self.coolness = coolness
        self.python = python
        self.pythonic = pythonic
        self.duck = duck
        self.pants = pants
        self.magictenbucks = magictenbucks
        self.datawad = datawad
        self.dataload = dataload
        self.datacatastrophe = datacatastrophe
        self.bigness = None
        self.awesomeitude = None
        self.genius = None
        self.fatness = None
        self.topwise = None
        self.brillant = False
        self.strangenessfactor = 3
        self.noisiness = 12
        self.whatever = None
        self.yougettheidea = True

class Dog(ClassWithLotsOfAttributes):
    def __init__(self, coolness='lots', python='isgoodfun', pythonic='nebulous', duck='goose', pants=None, magictenbucks=4, datawad=None, dataload=None, datacatastrophe=None):
        super(ClassWithLotsOfAttributes, self).__init__(coolness, python, pythonic, duck, pants, magictenbucks, datawad, dataload, datacatastrophe)
        self.noisiness = 1000000

    def quack(self):
        print "woof"

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

  • Каков самый, ну, "путинский" способ объявить класс с таким количеством атрибутов? Лучше ли выставлять их против класса, если значение по умолчанию является неизменным, ala Pants.pockets или лучше помещать их в конструктор, ala ClassWithLotsOfAttributes.noisiness?

  • Есть ли способ устранить необходимость переопределять значения по умолчанию для всех аргументов конструктора подкласса, как в Dog.__ init__? Должен ли я даже включать в это множество аргументов со значениями по умолчанию?

Ответ 1

  • Если атрибуты будут отличаться от экземпляра к примеру сделать их экземпляром атрибут, то есть создать их внутри __init__, используя self, если им нужно делиться между экземплярами класса как постоянная, помещать их в класс уровень.

  • Если ваш класс действительно должен пройти, много аргументов в __init__, пусть вывести список аргументов использования класса и аргументы ключевых слов, например.

class Dog(ClassWithLotsOfAttributes):
    def __init__(self, *args , **kwargs):
        super(ClassWithLotsOfAttributes,    self).__init__(*args , **kwargs)
        self.coolness = "really cool!!!
  • Не нужно передавать все переменные, кроме нескольких важных, в __init__, класс может принимать некоторые по умолчанию и пользователь может их изменить позже, если необходимо.
  • Используйте 4 пробела вместо закладки.

  • если вам нужно добавить дополнительный аргумент arg, для Dog и ключевого слова arg old тоже

class CoolDog(ClassWithLotsOfAttributes):
    def __init__(self, bite, *args , **kwargs):
        self.old = kwargs.pop('old', False) # this way we can access base class args too
        super(ClassWithLotsOfAttributes,    self).__init__(*args , **kwargs)
        self.bite = bite
        self.coolness = "really really cool!!!

различные способы использованияCoolDog

CoolDog(True)
CoolDog(True, old=False)
CoolDog(bite=True, old=True)
CoolDog(old=True, bite=False)

Ответ 2

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

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

Вы должны назначить их self, но не как атрибуты класса. Обратите внимание на разницу:

class Class1(object):
    attr1 = 'abc'

class Class2(object):
    def __init__(self):
        self.attr1 = 'abc'

Class1.attr1 # returns 'abc'
c = Class1()
c.attr1 # Also returns 'abc'
Class1.attr1 = 'def'
c.attr1 # Returns 'def'!
c.attr1 = 'abc' # Now the c instance gets its own value and will show it
                # independently of what Class1.attr1 is. This is the same
                # behavior that Class2 exhibits from the start.