【问题标题】:'self' seems to be hogging one of my arguments'self' 似乎占据了我的一个论点
【发布时间】:2025-12-01 06:10:02
【问题描述】:

我正在尝试在 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(self, date, hours, rate)' 中的'self' 似乎占用了我的输入参数之一。

谁能告诉我这里缺少什么?

.....更新.....

所以现在我在 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(day 部分,但我不知道如何解决它。我知道除非指定变量不是全局变量,但我的逻辑告诉我该方法应该是。所以它一定是 .append(day 正在寻找一个名为“day”的预先存在的变量。我很困惑,因为这种方法在书中的示例中有效。

【问题讨论】:

  • Timesheetday() 方法中,您尝试调用day(),这会(如果您的语法正确)导致无限循环。您实际上想要完成什么?
  • 是的,我偶然发现了那个无限循环!我现在已经整理好了。我忘记了我应该调用另一个名为 Work_day 的类,而不是在 day() 中调用 day()。感谢您的帮助和耐心!

标签: python oop class self


【解决方案1】:

问题的根源在于您还不了解 Python 类和实例的工作原理。

类,如Timesheet,是方法(函数)和变量的集合,它们位于类的命名空间中。实例是类的特定 实例(即,this 时间表,与现有的所有其他时间表相对)。每个实例都有自己的命名空间,有点特殊:当你在实例命名空间中查找方法或变量时,如果没有找到名称,接下来会搜索类命名空间。 (如果该类继承自其他类,则会按顺序搜索其祖先的命名空间,直到找到该名称或没有更多命名空间可供搜索。)

现在,在类中定义的方法(函数)具有特殊的行为,而在类外部定义的函数却没有——这就是为什么对定义的函数使用不同的术语(方法)的原因在课堂上,帮助提醒您这种特殊行为。特殊行为是这样的:如果在类的 instance 上调用函数,则该实例将作为“额外”第一个参数传递给函数。 (按照惯例,第一个参数称为self,但如果您愿意,没有理由不能将其称为fhqwhgads。您不应该——它只会让您的代码完全难以阅读——但是如果你愿意,你可以。)为什么额外的第一参数?好吧,还记得我说过实例有自己的命名空间吗?如果您想查找实例上的变量(例如,您想查找 this 时间表上的条目,而不是那里的其他时间表),那么您需要对该实例的引用。 self 参数提供该引用。

现在,如果您调用 class 上的方法,而不是 instance 上的方法,则不需要额外的 self 参数,因为您显然已经有对该类的引用:该引用是名称Timesheet。因此,当您执行Timesheet.day(...) 时,将不会在您的其他参数之前添加“额外”的第一个参数。那是因为您不是在引用实例,而是在引用一个类。

但是,如果您致电Timesheet().day(...),则会发生两件事。首先,您正在创建一个TimesheetinstanceTimesheet() 公式是您创建实例的方式),然后在该实例上调用day() 方法 。因此,“额外”的第一个参数将传递给您的 day() 方法,以便您在 day() 中的代码能够访问该实例的变量。

您需要了解的另一件事是:变量何时属于一个实例,何时属于一个类。您可以问自己一个非常简单的问题来确定这一点:“这适用于每个时间表,还是仅适用于特定时间表?”您的day() 方法显然需要访问特定时间表中的值(Joe 的工作时间与 Bob 不同,工资率不同),因此您需要在 instances上调用它>,不在课堂上。因此,在您的 day() 方法中使用 self 参数是有意义的,但您还需要从方法中调用它,而不是从类中。

因此,您应该执行以下操作,而不是 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 中称为“静态方法”,顺便说一句)。我能想到的每一个示例方法都是实例方法(即,应该在实例上调用的方法,因为它需要访问 该特定时间表中的数据)。

有点啰嗦,但我希望这能帮助你更好地理解类和实例。

【讨论】:

  • 感谢您的精彩解释。我必须创建一个类的实例,这非常有意义,谢谢!
【解决方案2】:

workday = Timesheet.day(date, hours, rate) 更改为workday = Timesheet().day(date, hours, rate)

【讨论】:

  • 除非您将return self 添加到Timesheet.day 的末尾,否则这将不起作用。
  • 应该是workday = Timesheet(),然后是workday.day(date, hours, rate)的第二行。这样一来,您仍然拥有 workday 实例的副本,并且以后可以用它做其他事情,例如计算总工资。
【解决方案3】:

您遇到的问题是您没有在当前代码中创建 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)

【讨论】:

    最近更新 更多