2014-09-26 4 views
2

У меня есть файл, например:Создание класса, который наследует от Dict, используя txtfile - питона

1 23 
2 21 
5 23 
561 2 
73 19781 

И с этой функцией:

def readx(x): 
    return {int(line.split()[0]):int(line.split()[1]) for line in x.split('\n')} 

я могу получить это:

{1: 23, 2: 21, 5: 23, 73: 19781, 561: 2} 

Но мне нужно положить его в какой-то классный объект, поэтому я пробовал это:

z = """1 23 
2 21 
5 23 
561 2 
73 19781""" 

def readx(x): 
    return {int(line.split()[0]):int(line.split()[1]) for line in x.split('\n')} 


class Foo(dict): 
    def __init__(self, x): 
     self = readx(x) 

f = Foo(z) 
print f 

Но вместо словаря он возвращает None.

  1. Есть ли более питонический способ сделать readx()? Это немного уродливое, как сейчас.
  2. Как получить объект класса для работы и сделать foo с помощью ключей и значений?
+0

На самом деле это '{1: 23, 2: 21, 5: 23, 73: 19781, 561: 2}' уже является своего рода объектом класса, не так ли? Это экземпляр 'dict' –

+0

@alvas пытается сделать' для k, v в readx (x) .items(): self [k] = v' ... –

+0

в вашем конструкторе использовать self .__ x = readx (x) и свойство вашего класса для доступа к переменной self .__ x – tschm

ответ

2

На первый вопрос, да, это понимание немного нечитаемым, простой цикл может работать лучше:

def read_dict(fp): 
    d = {} 
    for line in fp: 
     k, v = line.strip().split(); 
     d[int(k)] = int(v) 
    return d 

где fp любая итерацию , например файловый объект.

На второй вопрос, если ваш __init__ не делает никакой полезной работы, просто избавиться от него, и передать результат read в качестве аргумента конструктора, который затем прозрачно ссылаться на родительский dict.__init__:

class Foo(dict): 
    # stuff 

with open(path) as fp: 
    foo = Foo(read_dict(fp)) 

Кроме того, экземпляр Foo прямо в read и вернуть его:

def read_foo(fp): 
    d = Foo() 
    for line in fp: 
     # etc, just as above 

, а затем просто

with open(path) as fp: 
    foo = read_foo(fp) 

Вы можете также сделать read метод класса в Foo структурировать ваш код лучше:

class Foo(dict): 

    @classmethod 
    def read(cls, fp): 
     d = cls() 
     for line in fp: 
      #etc 

, а затем:

with open(path) as fp: 
    foo = Foo.read(fp) 

Наконец, если вы хотите инициализировать Foo непосредственно из fp объект, вам нужно __init__:

class Foo(dict): 
    def __init__(self, fp): 
     for line in fp: 
      k, v = line.strip().split() 
      self[int(k)] = int(v) 

, а затем

x = Foo(fp) 

Этот код следует использовать с осторожностью, хотя, так как это нарушает Liskov substitution principle, и что, как правило, не очень хорошая вещь.

+1

+1 для метода класса. Строя структуру inline, мы устраняем накладные расходы дополнительной копии. –

+0

, но 'Foo' будет' type 'и не является объектом Foo? Поэтому, если я хочу добавить больше методов в Foo, а 'foo' должен получить к нему доступ, будет ли это возможно? или это похоже на то, чтобы положить все снаружи как обычные функции 'def'? – alvas

+0

@alvas: нет, если вы выполняете 'x = Foo (что угодно)', 'x' будет' type Foo', независимо от того, есть ли у вас '__init__' или нет. – georg

3

Использование super:

class Foo(dict): 
    def __init__(self, x): 
     super(Foo, self).__init__(readx(x)) 

Это будет вызывать dict конструктор по данным, скопировав его в объект.

Обратите внимание, что это работает и на Python 3.

+1

есть ли причина, по которой требуется супер()? – alvas

+0

В данном случае это не обязательно; вы можете использовать 'dict .__ init __ (self, readx (x))' вместо этого, если хотите. Но поскольку есть другие случаи, когда это * имеет значение, мы могли бы также сделать привычку использовать 'super' сейчас. –

2

Альтернативой без super является:

class Foo(dict): 
    def __init__(self, x): 
     for k, v in readx(x).items(): 
      self[k] = v 
+1

, но это означало бы, что мне нужно будет перебирать ключи дважды, один раз для readx() и один раз для init, правильно? – alvas

+1

@alvas Я думаю, что мы заканчиваем итерацию дважды в любом случае, так как конструктор 'dict' создает копию. –

+0

@alvas вы копируете содержимое словаря, созданного 'readx()' в свой класс, используя это для цикла –

Смежные вопросы