【问题标题】:abstract method and self variable and NameError抽象方法和自变量以及 NameError
【发布时间】:2021-10-17 14:42:50
【问题描述】:

我给你看两段代码:

from abc import ABC, abstractmethod
class AbstractEmployee(ABC):
  new_id = 1
  def __init__(self):
    self.id = AbstractEmployee.new_id
    AbstractEmployee.new_id += 1

  @abstractmethod
  def say_id(self):
    pass

# Write your code below
class Employee(AbstractEmployee):
    def say_id(self):
      print('Sim, o ID dele é {}'.format(self.id))

e1 = Employee()
e1.say_id()

输出:Sim,o ID dele é 1

第二个代码:

from abc import ABC, abstractmethod

class AbstractEmployee(ABC):
  new_id = 1
  def __init__(self):
    self.id = AbstractEmployee.new_id
    AbstractEmployee.new_id += 1

  @abstractmethod
  def say_id(self):
    pass

# Write your code below
class Employee(AbstractEmployee):
    # def say_id(self): do not use say_id
    print('Sim, o ID dele é {}'.format(self.id))

e1 = Employee()
e1.say_id()

输出:NameError: name 'self' is not defined

为什么我会得到这个 NameError?我想既然我在Employee类中继承了AbstractEmployee,我不应该能够从AbstractEmployee类中访问self.id吗?为什么我能 在第一段代码中访问它并打印“Sim,o ID dele é 1” 而不是在第二个?

我将添加第三段代码,但我仍然得到同样的错误,即使我删除了抽象方法:

class AbstractEmployee:
  new_id = 1
  def __init__(self):
    self.id = AbstractEmployee.new_id
    AbstractEmployee.new_id += 1

  def say_id(self):
    pass

# Write your code below
class Employee(AbstractEmployee):
    # def say_id(self):
  print('Sim, o ID dele é {}'.format(self.id))

e1 = Employee()
e1.say_id()

输出:NameError: name 'self' is not defined

【问题讨论】:

  • 您为什么认为self 会在该类块中的任何位置定义?
  • 如果print() 不在say_id() 方法定义中,则调用它的时间点与调用e1.say_id() 的时间点完全无关。事实上,它发生在Employee 类的定义期间 - 甚至还没有该类的实例存在,因此没有要打印的 id。
  • @jasonharper 但是因为我继承了 AbstractEmployee 它不应该工作吗?
  • 我刚刚在 Pythontutor 上运行了第三个代码,当 Python 读取 Employee 类时它崩溃了:tinyurl.com/ykd35sff
  • 继承与此完全无关。 print() 不在方法中,因此它在类定义期间被调用。

标签: python oop abstract-class self


【解决方案1】:

您的第二个版本在将您的类定义解析为字节码的过程中发现了一个错误。

在示例 2 中,如果您更改代码以完全避免对 self 的引用,

print('Sim, o ID dele é XX')

然后你会得到一个新的错误:

TypeError: Can't instantiate abstract class Employee with abstract method say_id

要覆盖一个抽象方法,您需要在子类中重新定义该方法。

更一般地说,self 没有什么特别之处——Python 总是为方法提供对方法所属对象的引用。你可以把它叫做任何你想要的。例如:

class NamedPerson:
    def __init__(joker,name):
        joker.name = name

    def get_name(bill):
        print(bill.name)

person = NamedPerson("Carl")
person.get_name()

您将获得输出“Carl”。

方法的第一个参数的变量self被Python社区很好地遵守,很容易把它误认为是关键字,比如Java中的this,这个关键字总是指向调用它的对象。

您正在尝试使用 self,就像 Java 用户使用 this 一样,但这不是 Python 的设计方式。

【讨论】:

  • 肯定是运行时错误,不是语法错误,python语法完全有效
  • @juanpa.arrivillaga 我的意思是它被抛出是因为它是一个语法问题——你甚至不会到达e1 = Employee() e1.say_id()
  • @juanpa.arrivillaga 好的——“语法错误”的错误用法——但是,我的 linter 抓住了它——我修改为简单地指出它在哪里失败而没有尝试对错误进行分类。
  • @JoãoVitorGomes 不——你只能在第一个版本中访问 self 因为你是从第一个函数参数中获得的——在幕后 python 总是将对象的引用作为第一个参数——参见我回答的后半部分
  • @JoãoVitorGomes 你的第二个版本有两个错误——没有定义 self 并且你没有覆盖抽象方法。您的第三个版本仍然尝试使用 self.同样,self 不是关键字——init 函数中的 self.id 不会创建名为 self 的通用变量。
猜你喜欢
  • 1970-01-01
  • 2017-08-02
  • 1970-01-01
  • 2022-11-20
  • 1970-01-01
  • 2017-09-26
  • 2011-08-24
  • 2012-10-10
  • 1970-01-01
相关资源
最近更新 更多