-1

I am writing a program to add to and update an address book. Here is my code:

EDITED

import sys
import os

list = []

class bookEntry(dict):
    total = 0

    def __init__(self):
        bookEntry.total += 1
        self.d = {}

    def __del__(self):
        bookEntry.total -= 1
        list.remove(self)

class Person(bookEntry):
    def __init__(self, n):
        self.n = n
        print '%s has been created' % (self.n)

    def __del__(self):
        print '%s has been deleted' % (self.n)

    def addnewperson(self, n, e = '', ph = '', note = ''):
        self.d['name'] = n
        self.d['email'] = e
        self.d['phone'] = ph
        self.d['note'] = note

        list.append()

    def updateperson(self):
        key = raw_input('What else would you like to add to this person?')
        val = raw_input('Please add a value for %s' % (key))
        self.d[key] = val
def startup():
    aor = raw_input('Hello! Would you like to add an entry or retrieve one?')
    if aor == 'add':
        info = raw_input('Would you like to add a person or a company?')
        if info == 'person':
            n = raw_input('Please enter this persons name:')
            e = raw_input('Please enter this persons email address:')
            ph = raw_input('Please enter this persons phone number:')
            note = raw_input('Please add any notes if applicable:')

            X = Person(n)
            X.addnewperson(n, e, ph, note)
startup()

When I run this code I get the following error:

in addnewperson
    self.d['name'] = n
AttributeError: 'Person' object has no attribute 'd'

I have two questions:

UPDATED QUESTIONS 1. why isnt the d object being inherited from bookentry()?

I know this question/code is lengthy but I do not know where to go from here. Any help would be greatly appreciated.

dopatraman
  • 13,416
  • 29
  • 90
  • 154
  • Many problems were already mentioned (and many not mentioned). Just one more: it is not good to shadow list on the module level (list = []) - choose another name the list, or even better, make PhoneBook class to contain bookentries – Roman Susi Jan 08 '12 at 07:41
  • @RomanSusi--that seems like a good point. can you explain why this is better from a design/functionality standpoint? – dopatraman Jan 08 '12 at 15:29
  • @codeninja **list** is a starndard python type, that's why it's better to use another name. The PhoneBook suggestion would allow you to have more than one list of entries, which would improve your program's extensibility even if you don't see any use for it right now (in that case, you could treat PhoneBook as a singleton). – mgibsonbr Jan 08 '12 at 18:23

2 Answers2

4
  1. The addnewperson shoud have 'self' as first argument; actually, the name doesn't matter ('self' is just a convention), but the first argument represent the object itself. In your case, it's interpreting n as the "self" and the other 3 as regular arguments.

  2. ____del____ must not take arguments besides 'self'.

Edit: BTW I spotted a few other problems in your example, that maybe you're not aware of:

1) d in bookentry is a class member, not an instance member. It's shared by all bookentry's instances. To create an instance member, use:

class bookentry(dict):
    def __init__(self,n):
        self.d = {}
        # rest of your constructor

2) you're trying to access d directly (as you would do in Java, C++ etc), but Python doesn't support that. You must have a 'self' parameter in your methods, and access instance variables through it:

class person(bookentry):
    def foo(self,bar):
       self.d[bar] = ...

person().foo(bar)

Update: for the last problem, the solution is to call the super constructor (which must be done explicitly in Python):

class Person(bookEntry):
    def __init__(self, n):
        super(Person, self).__init__()
        self.n = n
        print '%s has been created' % (self.n)

A brief explanation: for people with background in OO languages without multiple inheritance, it feels natural to expect the super type constructor to be called implicitly, automatically choosing the most suitable one if no one is mentioned explicitly. However, things get messy when a class can inherit from two or more at the same time, for this reason Python requires the programmer to make the choices himself: which superclass constructor to call first? Or at all?

The behavior of constructors (and destructors) can vary wildly from language to language. If you have further questions about the life cycle of Python objects, a good place to start would be here, here and here.

Community
  • 1
  • 1
mgibsonbr
  • 21,755
  • 7
  • 70
  • 112
  • @mgibsonbr--thanks for the tips. I still have a couple of questions though: id `__del__` does not take arguments besides `self` how will this statement work?: `def __del__(self): print '%s has been deleted' % (n)` ie how will `n` be passed? – dopatraman Jan 08 '12 at 05:59
  • @mgibsonbr--also, when I use `self.d` I'm getting an error that says `self` is not defined... – dopatraman Jan 08 '12 at 06:00
  • @codeninja I believe you'll have to save `n` as an instance variable, and access it using `self.n` in `__del__`. About the 2nd comment I can't help you without seeing your code (maybe you didn't pass `self` as the first argument of your method?) – mgibsonbr Jan 08 '12 at 06:08
  • @codeninja The `self.d` must be put inside the `__init__` method, not where you'd normally put a method or class field. Weird, I know, but that's how the language is... :P – mgibsonbr Jan 08 '12 at 06:27
  • @mgibsonbr--hmm... it seems as though `addnewperson()` is not recognizing the `d` object inherited from `bookentry()`. This is the error I'm getting now: `in addnewperson self.d['name'] = n AttributeError: 'Person' object has no attribute 'd'` Any ideas? – dopatraman Jan 08 '12 at 06:49
  • @codeninja answer updated. I forgot to mention about the explicit super constructor call - another of Python's quirks... – mgibsonbr Jan 08 '12 at 07:25
  • @mgibsonpr--I'm sorry, could you explain that a little? I'm new to Python and do not know what the 'explicit super constructor call' is – dopatraman Jan 08 '12 at 15:27
4
  1. why isnt the d object being inherited from bookentry()?

That's because __init__ of the bookEntry is not called in the __init__ of the Person:

super(Person, self).__init__()

BTW, why inherit from dict if its functionality is not used? It's better to remove it and inherit from object instead (also class names are usually CamelCased):

class BookEntry(object):
Roman Susi
  • 4,135
  • 2
  • 32
  • 47
  • @RomanSusi--2 questions: 1. isnt the `__init__` of `bookEntry` inherited by `Person` with everything else? 2. If i dont inherit `dict` how will i ensure that `bookEntry` behaves like a dictionary? The goal here is to have a list of dictionaries (an address book) – dopatraman Jan 08 '12 at 15:26
  • 1. You've substituted \_\_init\_\_, so its your responsibility to call the one from superclass. 2. I do not see any hints of dict behavior, on the contrary: self.d is there to hold values. Maybe, you have omitted some methods, which support dict behavior? Right now, your have 2 dicts: self and self.d – Roman Susi Jan 08 '12 at 15:35