Ссылка на функцию Python, передаваемая в конструктор, превращается в тип данных c_void_p - PullRequest
4 голосов
/ 24 января 2012

Короче говоря, я пытаюсь передать список словарей в контейнерный класс с намерением использовать каждый словарь для создания экземпляра другого класса.Проблема состоит в том, что каждый словарь содержит ссылку на объект функции, которая должна быть назначена подклассу, и по какой-то причине непосредственно перед созданием самого внутреннего подкласса он превращается из объекта функции python в объект c_void_p.

Домен приложения - это создание библиотеки текстовых виджетов пользовательского интерфейса с использованием curses.

Вот дочерний класс, который должен содержать контейнер:

class DigitalReadout(Window):
    # Just a one-line borderless window displaying some data...
    def __init__(self, width, y, x, label, digits, data_source, parent=None):

        super(DigitalReadout, self).__init__(1, width, y, x, parent)

        self.data_source = data_source
        self.data = self.get_data_from_source()
        self.label = label
        self.digits = digits
        self.spaces = self.width - len(self.label) - self.digits # Calc Number of extra spaces

    ###Irrelevant display-related classes omitted###

    def update_data(self):
        self.data = self.get_data_from_source() #return data from function

    def get_data_from_source(self):
        return self.data_source.__call__()

А вот класс 'container':

class ReadoutPanel(BoxedWindow):

    def __init__(self, y, x, readouts, parent=None):

        super(ReadoutPanel,self).__init__(2 + len(readouts), self.find_longest_readout_width(readouts) + 2, y, x, parent)
        self.children = []
        self.initialize_readouts(readouts)

    def find_longest_readout_width(self, readouts):
        #Find the longest member and size container accordingly
        longest_length = 0
        for each_dict in readouts:
            this_dict_length = each_dict['digits'] + len(each_dict['label']) + 1
            if this_dict_length > longest_length:
                longest_length = this_dict_length
        return longest_length

    def initialize_readouts(self, readouts):
        y_readout_index = 1
        for each_hash in readouts:
            function = each_dict['func']
            function()
            self.children.append(DigitalReadout(each_dict['digits'] + len(each_dict['label']) + 1,
                                                1,
                                                y_readout_index,
                                                1,
                                                function,
                                                self.window))

Для справки, можно просмотреть базовые классы Window и BoxedWindow здесь

Когда я запускаюследующий тестовый код, я получаю следующую ошибку:

if __name__ == '__main__':

    #standard cuses initialization here...

    from time import clock

    i = 0

    def print_i():
        return str(i)

    readouts = [{'label': 'count',
                 'digits': 10,
                 'func': print_i},
                {'label': 'clock',
                 'digits':10,
                 'func': print_i}]

    readout_panel = ReadoutPanel(1, 1, readouts) #Initialize that puppy!


    curses.endwin()

Ошибка:

 Traceback (most recent call last):
 File "window.py", line 515, in <module>
 readout_panel = ReadoutPanel(1, 1, readouts)
 File "window.py", line 455, in __init__
 self.initialize_readouts(readouts)
 File "window.py", line 476, in initialize_readouts
 self.window))
 File "window.py", line 183, in __init__
 self.data = self.data_source()
 TypeError: 'c_void_p' object is not callable

Printlining показывает, что функция выбирается из словаря и по-прежнему является функциональным объектом.Однако когда он передается в конструктор для DigitalReadout, он каким-то образом возвращает объект c_void_p.Есть идеи, почему это происходит?

Заранее спасибо и извиняюсь за ужасно длинный вопрос.

1 Ответ

3 голосов
/ 24 января 2012

Это конструктор DigitalReadout:

def __init__(self, width, y, x, label, digits, data_source, parent=None)

Вот как вы его называете:

DigitalReadout(each_dict['digits'] + len(each_dict['label']) + 1, # width
                                        1,                        # y
                                        y_readout_index,          # x
                                        1,                        # label
                                        function,                 # digits
                                        self.window)              # data_source

Похоже, вы пропустили параметр в конструкторе (height?), потому что, если я правильно читаю, функция должна быть data_source, а теперь это digits.

...