我正在尝试在python 3中学习面向对象的编程。我正在制作一本笔记本程序的变体,我在一本书中但不是在笔记本中添加笔记而是试图在时间表中添加日期。
在原始教程中,这是在主程序中:
def add_note(self):
memo = input("Enter a memo: ")
self.notebook.new_note(memo)
print("Your note has been added")
这是在类模块(笔记本)中:
def new_note(self, memo, tags = ''):
'''create a new note and add it to the list'''
self.notes.append(Note(memo,tags=''))
我的变体如下:
主:
def add_work_day(self):
date = input ("Enter date : ")
hours = input ("Enter hours worked : ")
rate = input ("Enter hourly rate : £")
workday = Timesheet.day(date, hours, rate)
模块:
class Timesheet:
def __init__(self):
self.timesheet = []
def day(self, date, hours, rate):
self.timesheet.append(day(date, hours, rate))
它给了我这个错误:
File "C:\Python33\timesheet_menu.py", line 39, in add_work_day
workday = Timesheet.day(date, hours, rate)
TypeError: day() missing 1 required positional argument: 'rate'
似乎'def day(自我,日期,小时,费率)中的'自我'正在占据我的输入参数之一。
有人可以告诉我这里缺少什么吗?
..... .....更新
所以现在我在main中创建了一个Timesheet()实例:
def add_work_day(self):
date = input ("Enter date : ")
hours = input ("Enter hours worked : ")
rate = input ("Enter hourly rate : £")
workday = Timesheet()
workday.add_day(date, hours, rate)
但是我的Timesheet()方法'day'
我收到了一个新错误class Timesheet:
def __init__(self):
self.timesheet = []
def day(self, date, hours, rate):
self.timesheet.append(day(date, hours, rate))
File "C:\Python33\timesheet_menu.py", line 40, in add_work_day
workday.add_day(date, hours, rate)
File "C:\Python33\timesheet.py", line 29, in add_day
self.timesheet.append(day(date, hours, rate))
NameError: global name 'day' is not defined
我明白问题是.append(日期部分,但我无法弄清楚如何解决它。我知道变量不是全局的,除非指定但我的逻辑告诉我该方法应该是。所以它必须是.append(白天正在寻找一个名为'day'的预先存在的变量。我很困惑,因为这个方法适用于本书的例子。
答案 0 :(得分:2)
问题的根源在于您还不了解Python类和实例的工作原理。
类,如Timesheet
,是一个方法(函数)和变量的集合,它们存在于类的命名空间中。实例是类的特定实例(即此时间表,而不是存在的所有其他时间表)。每个实例都有自己的命名空间,这有点特殊:当您在实例命名空间中查找方法或变量时,如果找不到该名称,则接下来将搜索类命名空间。 (如果该类继承自其他类,则将按顺序搜索其祖先的名称空间,直到找到该名称或者没有剩余的名称空间可供搜索。)
现在,类中定义的方法(函数)具有特殊的行为,类在之外的函数没有 - 这就是为什么不同的术语(方法)用于定义的函数在课堂上,帮助提醒你这种特殊的行为。特殊行为是这样的:如果在类的实例上调用该函数,那么该实例将作为“额外”第一个参数传递给该函数。 (按照惯例,第一个参数称为self
,但如果你愿意的话,没有理由你不能称之为fhqwhgads
。你不应该 - 它只会让你的代码完全混淆读 - 但你可以,如果你想。)为什么额外的第一个参数?那么,还记得我说过实例有自己的命名空间吗?如果要在实例上查找变量(例如,您想在此时间表上查找条目,而不是那边的其他时间表),那么您需要对该实例的引用。 self
参数提供该引用。
现在,如果您调用类上的方法而不是实例上的方法,则不需要额外的self
参数,因为您显然已经有了对类的引用:该引用是名称Timesheet
。因此,当您执行Timesheet.day(...)
时,在其他参数之前不会添加“额外”第一个参数。那是因为您没有引用实例,而是引用了一个类。
但是如果你打电话给Timesheet().day(...)
,那么就会发生两件事。首先,您正在创建Timesheet
的实例(Timesheet()
表达式是您创建实例的方式),然后您调用day()
方法在该实例上。因此,“额外”第一个参数将传递给您的day()
方法,以便day()
中的代码能够访问该实例的变量。
您需要了解的另一件事:变量属于某个实例,何时属于某个类。有一个非常简单的问题,你可以问自己确定这个:“这适用于每个时间表,还是只适用于特定的时间表?”您的day()
方法显然需要访问特定时间表中的值(Joe的工作时间与Bob不同,工作时间不同),因此您需要在实例上调用< / em>,不在课堂上。因此,在self
方法中使用day()
参数是有道理的,但您还需要从方法中调用它,而不是从类中调用它。
因此,您应该执行以下操作:
,而不是Timesheet.day(...)
my_timesheet = Timesheet()
my_timesheet.day(...)
# Now do something with the timesheet: calculate total pay, print it out, etc.
my_timesheet.calculate_total_pay() # Made up example
my_timesheet.print_to_screen() # Made up example
执行Timesheet.calculate_total_pay()
没有任何意义,因为总薪水取决于特定的个人时间表中的值。因此calculate_total_pay()
也应该是一个实例方法,因此应该有一个self
参数。实际上,在这种情况下,我没有想出任何应该被称为Timesheet.some_method()
的方法。 (在Python,BTW中称为“静态方法”的方法)。我可以提出的每个示例方法都是一个实例方法(即,应该在实例上调用的方法,因为它需要从访问特定时间表的数据)。
有点啰嗦,但我希望这能帮助你更好地理解课程和实例。
答案 1 :(得分:1)
将workday = Timesheet.day(date, hours, rate)
更改为workday = Timesheet().day(date, hours, rate)
答案 2 :(得分:0)
您遇到的问题是您没有在当前代码中创建Timesheet
实例。你只是直接在类上调用一个方法。由于未绑定方法只是函数,因此不会出现参数不匹配错误,因为没有self
对象可以隐式传递。
以下是我修复代码的方法:
def add_work_day(self):
date = input ("Enter date : ")
hours = input ("Enter hours worked : ")
rate = input ("Enter hourly rate : £")
workday = Timesheet() # create Timesheet instance
workday.day(date, hours, rate) # add a workday to it
# presumably you'll also want to do something with `workday` here too
现在,您可能已经在您的方法所在的类中的其他位置创建了Timesheet
实例。在这种情况下,您只需要引用它(通过self
),而不是创建一个新的:
def add_work_day(self):
date = input ("Enter date : ")
hours = input ("Enter hours worked : ")
rate = input ("Enter hourly rate : £")
self.myTimesheetInstanceCreatedSomewhereElse.day(date, hours, rate)