Python继承的困境

3
这是一个作业问题,但是你可以看到我已经写了大部分的代码 :) 我想要实现的目标是,Agent对象继承自Investor对象的方法,因为Agent对象的方法应该基本相同。唯一不同的是构造函数,Investor接收6个参数,而Agent接收7个参数。你可以看到参数也基本相同。 Investor.loadInvestor.report基本按预期工作。继承自Agent的方法则不行。请参见下面的信息。
我的主要问题有以下几点:
  1. 当我在Investor上运行report(o)时,输出略有错乱。每行的末尾会出现小段落符号,而不是回车符(我在Linux上开发)。
  2. 当我在Agent上运行loadreport时,它没有像应该那样填充我的数组(reportsdata)。由于这个原因,report什么都不输出。如何设置我的类变量,使其按照我想要的方式工作?
谢谢!
>>> from sys import stdout as o
>>> import datetime
>>> from hedgefunds import *
>>>
>>> i = Investor('Flintstone','Fred',datetime.date(1965,12,3),'male','Mr.')
>>>
>>> i
Investor('Flintstone', 'Fred', datetime.date(1965, 12, 3), 'male', 'Mr.', 1)
>>> repr(i)
"Investor('Flintstone', 'Fred', datetime.date(1965, 12, 3), 'male', 'Mr.', 1)"
>>> i.__repr__()  # THIS CONTROLS PREVIOUS TWO LINES
"Investor('Flintstone', 'Fred', datetime.date(1965, 12, 3), 'male', 'Mr.', 1)"
>>> eval(repr(i))  # OBJECT CAN BE RECREATED FROM ITS REPR STRING
Investor('Flintstone', 'Fred', datetime.date(1965, 12, 3), 'male', 'Mr.', 1)
>>>
>>> i  # NOTICE ONE ADDITIONAL BIT OF DATA WE DIDN'T SPECIFY?
Investor('Flintstone', 'Fred', datetime.date(1965, 12, 3), 'male', 'Mr.', 1)
>>> # THE '1' AT THE END IS THE RECORD ID rid. THE REPR STRING INCLUDES ALL DATA SO YOU SEE IT.
>>> # THE INVESTOR CLASS SHOULD ASSIGN A rid IF ONE IS NOT PASSED INTO THE CONSTRUTOR.
>>>
>>> print i
1, Mr. Fred Flintstone, 12/03/1965, male
>>> i.__str__()  # THIS CONTROLS PREVIOUS LINE
'1, Mr. Fred Flintstone, 12/03/1965, male'
>>>
>>> # NOTE THE NAME IS NICELY PUT TOGETHER AND AND rid IS AT THE START
>>> # NOTE datetime.date(YYYY, MM, DD) BUT WE PRINT IN  MM/DD/YYYY FORMAT
>>>
>>> # NOW LET'S LOOK AT OUR INVESTOR OBJECT'S ATTRIBUTES
>>> i.last_name
'Flintstone'
>>> i.first_name
'Fred'
>>> i.dob
datetime.date(1965, 12, 3)
>>> i.date_of_birth
'12/03/1965'
>>> i.gender
'male'
>>> i.title
'Mr.'
>>> i.name
'Mr. Fred Flintstone'
>>> i.rid
1 
>>>
>>> # BUT WE'RE GONNA NEED SOMEHWERE TO STORE MULTIPLE INVESTOR OBJECTS
>>> # SO AS WELL AS CREATING INVESTOR OBJECTS, THE INVESTOR CLASS MUST ACT LIKE A RECORDSET
>>>
>>> Investor.report(o)  # o WAS SET TO STDOUT AT THE TOP OF THIS TRACE BUT COULD BE ANY FILE
>>> Investor.add(i)  # NO RECORDS SO LET'S ADD ONE
>>> Investor.report(o)  # NOW WE HAVE SOMETHING TO REPORT
1, Mr. Fred Flintstone, 12/03/1965, male
>>>
>>> Investor.add(Investor('Flintstone','Wilma',datetime.date(1968,1,15),'female','Mrs.'))
>>> Investor.report(o)
1, Mr. Fred Flintstone, 12/03/1965, male
2, Mrs. Wilma Flintstone, 01/15/1968, female
>>>

>>> # WE COULD CONTINUE ADDING INVESTORS MANUALLY BUT SINCE WE'VE GOT A FILE FULL OF THEM....
>>> Investor.load('investors.csv')
>>> Investor.report(o)
1, Mr. Charles Creed, 12/05/1928, male
2, Miss Sheila Geller, 11/12/1962, female
3, Mr. Fred Kenobi, 07/13/1957, male
4, Miss Rachel Geller, 07/11/1968, female
5, Mr. Charles Rubble, 09/23/1940, male
6, Mrs. Leah Skywalker, 07/02/1929, female
7, Mr. Bill Balboa, 03/06/1988, male
8, Dr. Sheila Barkley, 08/26/1950, female
.
.
>>> # YOU SHOULD SEE 120 RECORDS (OUR TWO MANUALLY ADDED RECORDS ARE GONE)
>>>
>>>
>>>
>>> # AGENTS
>>>
>>> a = Agent(2.1,'Rubble','Barney',datetime.date(1966,4,20),'male','Mr.')
>>> a
Agent(2.1000000000000001, 'Rubble', 'Barney', datetime.date(1966, 4, 20), 'male', 'Mr.', 1)
>>> repr(a)
"Agent(2.1000000000000001, 'Rubble', 'Barney', datetime.date(1966, 4, 20), 'male', 'Mr.', 1)"
>>> eval(repr(a))
Agent(2.1000000000000001, 'Rubble', 'Barney', datetime.date(1966, 4, 20), 'male', 'Mr.', 1)
>>> print a
1, Mr. Barney Rubble, 04/20/1966, male, 2.1
>>> a.last_name
'Rubble'
>>> a.first_name
'Barney'
>>> a.dob
datetime.date(1966, 4, 20)
>>> a.date_of_birth
'04/20/1966'
>>> a.gender
'male'
>>> a.title
'Mr.'
>>> a.name
'Mr. Barney Rubble'
>>> a.rid
1
>>> a.commission
2.1000000000000001
>>> Agent.add(a)
>>> Agent.report(o)
1, Mr. Barney Rubble, 04/20/1966, male, 2.1
>>> Agent.load('agents.csv')
>>> Agent.report(o)
1, Mr. Barney Flintstone, 02/13/1933, male, 4.0
2, Miss Rachel Rubble, 11/21/1982, female, 2.5
3, Dr. Ted Geller, 03/14/1963, male, 8.0
4, Miss Phoebe Creed, 11/06/1959, female, 5.5
5, Mr. Luke Kenobi, 08/24/1945, male, 2.5
6, Dr. Megan Creed, 03/26/1957, female, 5.5
7, Mr. Ted Rubble, 09/14/1931, male, 3.5
8, Mrs. Monica Balboa, 05/07/1934, female, 1.5

抱歉,为了使其易读,我不得不删除一些代码。只是if语句后面的冒号。已经更正了。现在测试一下吧! :) - CODe
是的,我正在尝试学习Python,所以我想在SO上潜伏一下,看看人们的问题的答案。另外,你在init方法中声明了reports和data。那不会使它们成为局部变量吗? - mowwwalker
在声明可变变量时要小心,这些变量是类变量而不是实例变量。具体来说,在您的__init__中,您可能希望像这样分配:self.reports, self.data = [], []。这将确保每个Agent和Investor实例都拥有自己的新列表。否则,您可能会遇到变量混淆的问题。 - g.d.d.c
@g.d.d.c,self.reports=self.data=[]怎么样? - mowwwalker
@GDDC: 在__init__中将Changing reports = []更改为self.reports = []并没有帮助,实际上导致了一个错误! - CODe
显示剩余15条评论
1个回答

2
这里涉及的内容很多,我会尽量简洁明了地翻译。
class Investor(object):
    reports = []
    data = []

    def __init__(self, LastName, FirstName, Date, Gender, Title, Rid=1):
        # the following two lines define variables which only exist inside
        # __init__, so they can basically be gotten rid of.
        # reports = []
        # data = []
        # but they *don't need to be initialized*. Actually creating a new list
        # in each constructor is *bad* unless you want one report per instance

        # ... later, be sure to add "self" instead of adding to the local vars
        self.add(self)

    @classmethod
    def report(self, o):
        result = ""
        for x in self.reports:
            # Just use join, that's what you mean anyway.
            result = ', '.join(x)
            # \n should result in \n\n. I think you mean o.write(result)
            o.write(result + "\n")

    @classmethod
    def load(self, f):
        self.reports = []
        self.data = []
        file = open(f)
        # why the extra readline?
        file.readline()
        list = []
        while 1:
            line = file.readline()
            # you need to get rid of the trailing whitespace
            items = line[:-1].split(", ")
            if not line:
                break
            else:
                # self, here, refers to the class, so you can use it as the
                # constructor as well
                # use the * to make a list into an argument list.
                self(*items)
                # No need to add it, the value is added at the end of __init__
                # as things stand.

class Agent(Investor):
    reports = []
    data = []

    def __init__(self, Commission, LastName, FirstName, \
                       Date, Gender, Title, Rid=1):
        super(Agent, self).__init__(self, LastName, FirstName, Date, \
                                          Gender, Title, Rid)
        self.commission = Commission

    def __str__(self):
        # Be lazy! Use super!
        return super(Agent,self).__str__() + ', ' + self.commission

    # this was doing the same thing in the parent class.
    # def __repr__(self):

    # The classmethod methods are not needed unless you want to redefine 
    # behavior in a child class.
    @classmethod
    def add(self, i):
        # If you do change something, though, make sure to use super
        # here as well...
        super(Agent, self).add(i)

我相信这应该解决了大部分的问题。

如果你想要使用格式 Investor('Flintstone', 'Fred', datetime.date(1965, 12, 3), 'male', 'Mr.', 1),你需要包含 __name__ 并引用属性:

def __repr__(self):
    # notice the " and ' below.
    return self.__name__ + "('" + str(self.rid) + "', '" + \
           self.name + "', " + self.date_of_birth + ", '" + self.gender + "')"

在Agent中,您需要使用子字符串来获取所需内容:
def __repr__(self):
   # remove the Agent( so you can add the commission at the *front* 
   s = super(Agent,self).__str__()
   return self.__name__ + "('" + self.commission + "'," + \
          s[len(self.__name__ + 1):]

2
load是一个类方法,因此self实际上是类对象,所以self.__class__是错误的。 - agf
@agf:他不介意我们寻求帮助,他只是担心其他人会看到我的代码在线上发布并复制它。这样做是错误的假设,我本来也打算将你的答案标记为正确答案! - CODe
如果我担心积分的话,我就不会删除它。不过我会把我的评论删掉。 - agf
@agf:无论如何都没有问题。你的建议并没有解决我的问题。我自己找到了答案,将在提交日期之后重新发布,以避免任何人抄袭我的代码。 - CODe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接