LINUX.ORG.RU

маленький вопрос по Python

 


0

2

Приветствую, ситуация значит следующая, есть некий базовый класс с несколькими переменными-членами(типа общими для всех потомков) и несколько наследованных от него потомков. К потомках есть метод save, который возвращает строчку со значением всех переменных класса: Примерно так:

class Primitive:
    def __init__(self):
        self.type       = None
        self.thickness  = 1
        self.color      = "#000000"

    def save(self):
        pass
    
    def load(self, values):
        pass


class Line(Primitive):
    def __init__(self):
        self.x1 = 0
        self.x2 = 0
        self.y1 = 0
        self.y2 = 0

    def save(self):
        return  self.__class__.__name__ + " " +\
                str(self.x1)            + " " +\
                str(self.y1)            + " " +\
                str(self.x2)            + " " +\
                str(self.y2)            + " " +\
                str(super(Line, self).color)   # <---- ? как обратиться к родителю, чтобы подтянуть значения эго перемнных

    def load(self):
        pass

if __name__ == "__main__":
    line = Line()
    print line.save()

Но возникает вопрос, как из потомка обратиться к родителю, чтобы получить значения его переменных? Т.е на выходе должно быть что-то вроде:

Line 10 10 50 50 line 1 #ff0000
★★★★★

У тебя конструктор Primitive из Line вообще не вызывается.

class Line(Primitive):
    def __init__(self):
        super(Line, self).__init__()
        ...

После этого просто self.color должно работать.

Akari ()
Ответ на: комментарий от Akari

После этого просто self.color должно работать.

Имхо, лучше объявлять как __(private) и делать get'ы.

FIL ★★★★ ()
Последнее исправление: FIL (всего исправлений: 1)
Ответ на: комментарий от FIL

Не спорю, но в этом случае отсутствие вызова конструктора базового класса тоже будет проблемой.

Akari ()
Ответ на: комментарий от Akari

Ну это понятно, да.
/me super для этих целей вообще не юзал

Primitive.__init__(self)
Этого хватало.

FIL ★★★★ ()
Ответ на: комментарий от Akari

Не фурычит :(

class Line(Primitive):
    def __init__(self):
        super(Line, self).__init__()
        self.x1 = 0
        self.x2 = 0
        self.y1 = 0
        self.y2 = 0
        

    def save(self):
        return  self.__class__.__name__ + " " +\
                str(self.x1)            + " " +\
                str(self.y1)            + " " +\
                str(self.x2)            + " " +\
                str(self.y2)            + " " + str(self.color)
  File "C:\Python27\test", line 19, in __init__
    super(Line, self).__init__()
TypeError: must be type, not classobj
xterro ★★★★★ ()
Ответ на: комментарий от FIL

А с таким вызовом говорит вот что:

Traceback (most recent call last):
  File "C:\Python27\test", line 42, in <module>
    line = Line()
  File "C:\Python27\test", line 19, in __init__
    Primitive.__init__()
TypeError: unbound method __init__() must be called with Primitive instance as first argument (got nothing instead)

Да, у меня 2.7 :)

xterro ★★★★★ ()
Последнее исправление: xterro (всего исправлений: 1)
Ответ на: комментарий от xterro
Primitive.__init__(self)

Извиняюсь, да. p.s. вторую версию вообще никогда не юзал, если что

FIL ★★★★ ()
Последнее исправление: FIL (всего исправлений: 1)
Ответ на: комментарий от xterro

А что бы super() работал, нужно что бы базовый класс наследовал от object. man new style classes.

Akari ()

Тег «python» сложно было поставить?

есть некий базовый класс с несколькими переменными-членами(типа общими для всех потомков)

class Primitive:
    type       = None
    thickness  = 1
    color      = "#000000"


^ вот так они будут общими для всех потомков

def save(self):
        return  self.__class__.__name__ + " " +\
Убивать. Чем join не устраивает?:
def save(self):
        return  " ".join(
            self.__class__.__name__,
            str(self.x1),
            ...,
        )

Virtuos86 ★★★★★ ()
Ответ на: комментарий от FIL

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

Virtuos86 ★★★★★ ()
Ответ на: комментарий от Virtuos86

^ вот так они будут общими для всех потомков

Т.е не надо будет потом писать конструкции: Primitive.__init__(self)?

 return  " ".join(
            self.__class__.__name__,
            str(self.x1),

Я ещё маленький и такое не умею (

xterro ★★★★★ ()
Ответ на: комментарий от xterro

Пора учиться. Строки в питоне немутабельные, «+» у них тормозит и практически всегда ты хочешь join вместо него.

x3al ★★★★★ ()
Ответ на: комментарий от Virtuos86

Кстате, неправильно такое, join принимает один iterable параметр, т.е надо отдельно параметры перечислять в списке. Или это может в 3-й версии так сделали?

xterro ★★★★★ ()
Ответ на: комментарий от xterro

Даже str.format выглядит не так отвратительно, как эта конкатенация с переносами.

Mahmood ()
Ответ на: комментарий от Mahmood

Уже поправил, теперь вот так:

    def save(self):
        values = [self.__class__.__name__,
                str(self.x1),
                str(self.y1),            
                str(self.x2),            
                str(self.y2),
                str(self.color)]
        return " ".join(values)
xterro ★★★★★ ()
Ответ на: комментарий от xterro

Угу. Я не проверял. Надо пару скобок добавить, чтобы кортеж получился. Юный падаван, как я смотрю, зачем-то там список выдумал, но это от неопытности.

Virtuos86 ★★★★★ ()
Ответ на: комментарий от xterro

На будущее- такие вещи лучше оформлять кортежем, а не списком. Фактически, кортеж- самая быстрая и легкая датаструктура в Python.

Mahmood ()
Ответ на: комментарий от xterro

Т.е не надо будет потом писать конструкции: Primitive.__init__(self)?

Атрибуты класса будут общими для всех его инстансов и всех дочерних классов, наследующих от него. То есть если потом написать Primitive.color = "#001100", он изменится вообще везде, и Primitive().color, и Line.color, и Line().color будут ссылаться на это значение. Но если поменять это поле в инстансе Primitive или дочернем классе, или инстансе дочернего класса, то они получат собственное поле color и будут ссылаться на него. И, конечно, Primitive.__init__(self) не нужен, ведь в таком случае у тебя отсутствует собственный __init__ у Primitive, инициализировать нечего. Головой-то думать надо :}.

Virtuos86 ★★★★★ ()
Ответ на: комментарий от x3al

Строки в питоне немутабельные, «+» у них тормозит

4.2 Тормозит +=.

tailgunner ★★★★★ ()
Ответ на: комментарий от Akari

А в таких случаях в принципе есть ли смысл наследоваться от object? Что даст мне наследование от object?

xterro ★★★★★ ()
Ответ на: комментарий от xterro

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

Mahmood ()
Ответ на: комментарий от tailgunner

Когда я в последний раз проверял, пустой класс нового стиля весил что-то около 900 с чем-то байт, когда его же версия старого стиля занимала ~150 байт. Хотя я могу и путать.

Mahmood ()
Ответ на: комментарий от xterro

Что даст мне наследование от object?

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

Virtuos86 ★★★★★ ()
Ответ на: комментарий от Virtuos86

Убивать. Чем join не устраивает?:

Я смотрю, опыт заменяет бенчмарки.

$ python q.py 
-----
plusplus  4.13611507416
jointuple 4.38718104362
joinlist  5.04758310318
-----
plusplus  4.32494401932
jointuple 4.58783102036
joinlist  5.27125000954
-----
plusplus  4.15135097504
jointuple 4.9834151268
joinlist  5.38858485222
$ pypy q.py 
-----
plusplus  0.0296730995178
jointuple 0.201213121414
joinlist  1.68824911118
-----
plusplus  0.029510974884
jointuple 0.238065004349
joinlist  1.5527780056
-----
plusplus  0.0254080295563
jointuple 0.199063062668
joinlist  1.52939391136
from timeit import timeit

cnt = 10 * 1000 * 1000

s1 = "He"
s2 = "ll"
s3 = "o,"
s4 = " W"
s5 = "or"
s6 = "ld"
s7 = "!"

def plusplus():
    return s1 + s2 + s3 + s4 + s5 + s6 + s7

def jointuple():
    return "".join((s1,s2,s3,s4,s5,s6,s7))

def joinlist():
    return "".join([s1,s2,s3,s4,s5,s6,s7])

for i in range(3):
    print("-----")
    print("plusplus  " + str(timeit(plusplus, number=cnt)))
    print("jointuple " + str(timeit(jointuple, number=cnt)))
    print("joinlist  " + str(timeit(joinlist, number=cnt)))

i-rinat ★★★★★ ()
Ответ на: комментарий от i-rinat

cnt = 10 * 1000 * 1000

Я смотрю, занудство заменяет здравый смысл.
С join хотя бы тупо проще форматировать код, без повторения " ". А вообще, конечно, «+» просто порвал «join», да.

Virtuos86 ★★★★★ ()
Ответ на: комментарий от Virtuos86

занудство заменяет здравый смысл.

Это не занудство, это и есть здравый смысл. Если возникает спор по поводу субъективных элементов, надо перевести его в объективную плоскость. Конкатенация против join это вопрос личных предпочтений либо выбранного стиля кодирования; никаких объективных причин гнаться за скоростью в этой функции вообще нет.

А если в фразе есть «Убивать», она автоматически теряет право на какое бы то ни было отношение к «здравому смыслу».

i-rinat ★★★★★ ()
Ответ на: комментарий от Mahmood

А, ты об оверхеде на сам объект класса... тогда может быть. Я-то об оверхеде при вызове методов и прочем.

tailgunner ★★★★★ ()
Ответ на: комментарий от i-rinat

Это не занудство, это и есть здравый смысл.

Бенчмарк некорректен ИМХО. И повторю: + не тормозит, тормозит +=.

tailgunner ★★★★★ ()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

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

xterro ★★★★★ ()
Ответ на: комментарий от xterro

Т.е всё таки лучше изначально наследоваться от object, и быть чётким пацаном, а не какашкой?

Да.

и пофиг на оверхед ))

Оверхед 800 байт на класс? Да, пофиг. Сколько у тебя классов в программе?

tailgunner ★★★★★ ()
Ответ на: комментарий от xterro

В третьем питоне без указания родительского класса наследование автоматически идет от object. Разработчики питона решили, что новые классы лучше. Если ты не знаешь различий, то лучше юзай то, что лучше с точки зрения более опытных людей. Да и в новых классах многое стало более логично выглядеть.

anonymous ()
Ответ на: комментарий от tailgunner

Немного, думаю десяток-полтора, не больше

xterro ★★★★★ ()

В треде советчики прям срветчики.

Имхо, лучше объявлять как __(private) и делать get'ы.

@FIL, и зачем?

/me super для этих целей вообще не юзал

А стоило бы.

^ вот так они будут общими для всех потомков

@Virtuos86, так они будут аттрибутами класса.

Юный падаван, как я смотрю, зачем-то там список выдумал, но это от неопытности.

А вы, настоящий джедай, любите преждевременную оптимизацию?

anonymous ()
Ответ на: комментарий от i-rinat

создание списка и tuple нужно было вынести

anonymous ()
Ответ на: комментарий от anonymous

@Virtuos86, так они будут аттрибутами класса.

«аТрибутами», ну ёлы-палы. Я в курсе. И даже ниже по треду описал насколько в курсе. Имхо, он не должен столкнуться со специфичными траблами, а если столкнется — что ж, будет повод углубить познания питоньего ООП. Считай это моей завуалированной ловушкой. И потом, я комментировал слова про общие поля: то, что у него в ОП, это не общие поля.

А вы, настоящий джедай, любите преждевременную оптимизацию?

Какая оптимизация? Кортеж это самый легковесный стандартный контейнер. Юзкейс для списка — необходимость либо динамически менять набор данных (за счет мутабельности list), либо потребность в удобных спискоспецифичных операциях, которые кортеж не поддерживает. Если же набор данных постоянен (а в нашем случае это так), и требуется просто абстрактный объект, поддерживающий итерацию, то кортеж самое то. Разве не так?

Virtuos86 ★★★★★ ()
Ответ на: комментарий от i-rinat

никаких объективных причин гнаться за скоростью в этой функции вообще нет.

А я еще раз повторю, дело не в скорости, а в том, что код со множеством \ + " " + выглядит плохо по сравнению с вариантом с «join». И дело не в стиле. Что, если атрибутов будет пара десятков? Значит, и " " умножится на 20.

Virtuos86 ★★★★★ ()
Ответ на: комментарий от x3al

Тем не менее, официальный tutorial предлагает для соединения строк использовать именно +.

yvv ★★☆ ()
Ответ на: комментарий от Virtuos86

Какая оптимизация? Кортеж это самый легковесный стандартный контейнер.

Но читаемость страдает, ' '.join(('a', 'b', 'c')) читается хуже, чем ' '.join(['a', 'b', 'c']).

anonymous ()

class Primitive(object)

так вроде во 2м питоне.

Bad_ptr ★★★★ ()

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

Спроси у родителя, епт, это ж сраный ООП.

bj ()
Ответ на: комментарий от bj

Вопрос в принципе уже решён, всем спасибо. Теперь я понаблюдаю за вашими спорами ))

xterro ★★★★★ ()
Последнее исправление: xterro (всего исправлений: 1)
Ответ на: комментарий от anonymous

Но читаемость страдает, ' '.join(('a', 'b', 'c')) читается хуже, чем ' '.join(['a', 'b', 'c']).

А не надо так читать. Правильно писать (и читать так):

' '.join((
    'adsjfkgsdflkgsdfgk;l',
    'b;asd;fljsdfl;sdflsdfjg',
    'clk;sd;glslk;gsfjkogsdf', # после последнего элемента неплохо тоже поставить зпт
    ))

' '.join([
    'adsjfkgsdflkgsdfgk;l',
    'b;asd;fljsdfl;sdflsdfjg',
    'clk;sd;glslk;gsfjkogsdf',
    ])
Ну и какая разница? Когда элементы списка/кортежа не односимвольные строки/идентификаторы, ' '.join(['a', 'b', 'c']) всё равно придется форматировать и разбивать на несколько строк, чтобы не разползся слишком широко.

Virtuos86 ★★★★★ ()
Ответ на: комментарий от anonymous

Никто не мешает тебе написать ' '.join( ('a', 'b', 'c') ), хоть это и не совсем по PEP-008.

Mahmood ()
Ответ на: комментарий от Mahmood

Тащемта он против этого варианта. И что, реально в этом PEP есть пункт против такого случая?

Virtuos86 ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.