【问题标题】:How to to split() a string and pass it into an object's __init__() method?如何拆分()字符串并将其传递给对象的 __init__() 方法?
【发布时间】:2018-05-14 02:38:53
【问题描述】:

我正在尝试使用文件中的信息创建 Soda 对象的多个实例。该文件的格式如下名称,价格,编号

Mtn. Dew,1.00,10

Coke,1.50,8

Sprite,2.00,3

我的代码是这样的(这是 main() 中的一个函数):

from Sodas import Soda

def fillMachine(filename) :

    # Create an empty list that will store pop machine data
    popMachine = []

    # Open the file specified by filename for reading
    infile = open(filename, "r")

    # Loop to read each line from the file and append a new Soda object 
    # based upon information from the line into the pop machine list.
    for line in infile :
        popMachine.append(Soda(str(line.strip())))

    # Close the file
    infile.close()

    # Return the pop machine list
    return popMachine

如果我猜对了,popMachine 应该是 3 个不同的 Soda 对象的列表,每个对象都有一行输入文件。

然后,在我的班级中,我需要能够获得名称、价格或数量,以便以后用于计算。我的苏打水课代码如下所示:

#Constructor
def __init__(self, _name = "", _price = 0.0, _quantity = 0) :
        self._name = self.getName()
        self._price = _price
        self._quantity = _quantity

def getName(self) :
    tempList = self.split(",")
    self._name = tempList[0]
    return self._name

这是我遇到问题的地方。 IIRC self 代替主代码中的行,因此 self 应该是一个字符串,例如“Mtn.Dew,1.00,10”,并且 split(",") 方法的预期结果应该形成一个类似 ["Mtn . Dew", "1.00", "10"] 然后我可以使用该列表的索引来返回名称。

但是,我收到此错误“AttributeError: Soda instance has no attribute 'split'”而且我不知道为什么。此外,这段代码中的所有 cmets 都来自我的导师,作为作业的一部分,所以即使有更快/更好的方法来完成这一切,这也是我必须这样做的方式:/

【问题讨论】:

  • self 指的是您的 Soda 实例,因此除非您定义一个名为 split 的方法,否则它没有。
  • 您实际上没有将字符串传递给getName__init__。 Caling self.getName() 没有传入任何字符串。
  • 在这种情况下,__init__ 需要正确的参数 (name,price,number),而不是字符串。所以 Pythonic 的事情是添加一个 staticmethod from_string/make/make_from_string,然后 调用 Soda() 构造函数。而不是您的getName从构造函数调用,这是一个更加痛苦的分解。

标签: python class split factory static-methods


【解决方案1】:

当你使用self时,你指的是Soda的实例,由于你没有定义一个split方法,所以它不会有一个。

您可以简单地使用解包将split 的结果传递给类。

您可能需要添加一些检查以确保解包返回三个值,但由于您使用默认参数,它只会在您提供更多三个值时出错。

class Soda:
  def __init__(self, name = "", price = 0.0, quantity = 0) :
        self.name = name
        self.price = price
        self.quantity = quantity


sodas = []
with open('test.txt') as f:
  for line in f:
    sodas.append(Soda(*line.split(',')))

for soda in sodas:
  print(soda.name)

输出:

Mtn. Dew
Coke
Sprite

您甚至可以定义一个帮助方法,从文件中的一行返回一个 Soda 实例:

@staticmethod
def make_soda(line):
  try:
    name, price, quantity = line.split(',')
    return Soda(name, price, quantity)
  except:
    raise ValueError('Bad Soda')

您可以使用以下方式调用:

Soda.make_soda(line)

【讨论】:

    【解决方案2】:

    self 变量指的是对象实例。您可以做的是或者像这样在构造函数中拆分行

    def __init__(self, line):
        name, price, quantity = line.split(',')
        self.name = name
        self.price = price
        self.quantity = quantity
    

    ...或者你可以在被要求时懒惰地拆分它

    def __init__(self, line):
        self._name = None
        self.line = line
    
    @property
    def name(self):
        if self._name is None:
            self._name = self.line.split()[0]
        return self._name
    

    请注意,在 python 中,函数名称等变量通常按约定为snake_case

    【讨论】:

    • 我认为在您的第二个示例中拆分一行并没有什么懒惰的地方:您已经在初始化期间拆分了一行。因此,只需返回 self._name
    • 对,那不应该在那里。应该只有第一行,谢谢。现已编辑。
    • 我没有看到惰性选项的好处。您仍在存储完全相同数量的信息,您所做的只是在每次您想知道苏打水的名称时调用split 的额外调用。此外,它还将与创建类相关的错误(没有足够的值等)推迟到以后,而不是在实例化类时。
    • 我没有提及或暗示任何好处,但它一个选项。
    • 这是一个相当大的改变,您应该在进行修改以改变他们的代码工作方式之前与用户核实。
    【解决方案3】:

    IIRC self 在主代码中代替 line,所以 self 应该是 一个字符串,例如“Mtn. Dew,1.00,10”和预期的结果 split(",") 方法应该形成一个类似 ["Mtn. Dew", "1.00", "10"] 的列表 然后我可以使用该列表的索引只返回名称。

    请稍等。当人们学习编码时,这是一个常见的误解。从根本上说,您将源代码与数据类型str 混为一谈。这是一个容易犯的错误,因为确实,在编写源代码时会创建一个文本文件。一个人将文本写入文件,甚至可以在 Python 中加载它(open('my_script.py').read()),我们得到一个字符串!是的,当您的源代码从您的编程语言转变为机器代码时,您运行的程序会使用字符串. 但我主张你将这两件事分开。你的源代码不是一个字符串。它应该在概念上位于它“之上”(无论如何,我们在这里处理有用的抽象) . 所以,虽然你的想法基本上是正确的,

    self 代替主代码中的行

    但这里的“行”是指行所指,由您的代码执行的一段逻辑,而不是您编写的代码行。因此,self 指的是对象 instance 当方法由类的实例执行时。

    所以,self 不是字符串。它是您的类定义的类型的对象。你的班级没有那个方法。 str 对象可以。

    这里稍微看一下python数据模型。 “自我”非常简单。实例本身作为参数传递。这是通过“魔法”(稍后您可以学习使用的魔法)为您完成的,但本质上,my_instance.some_method()几乎等同于MyClass.some_method(my_instance)

    所以考虑一下,

    In [1]: class SomeClass:
       ...:     def __init__(self, name):
       ...:         self.name = name
       ...:     def foo(self):
       ...:         print(self.name, 'says foo!')
       ...:
    
    In [2]: some_instance = SomeClass('Juan')
    
    In [3]: some_instance.foo()
    Juan says foo!
    
    In [4]: SomeClass.foo(some_instance)
    Juan says foo!
    

    方法只是属于类的一个函数,如果它被该类的实例调用,它会自动神奇地将实例本身作为第一个参数传递。请注意,这里优先考虑的是参数的位置,而不是仅是约定的名称 self。它可以是你想要的任何东西。名称甚至不必在类内保持一致(当然,在函数本身内保持一致)。让我们称它为西葫芦吧:

    In [8]: class WhyNot:
       ...:
       ...:     def __init__(self):
       ...:         self.foo_flag = False
       ...:         self.bar_flag = False
       ...:
       ...:     def foo(zucchini):
       ...:         print("I speak American English")
       ...:         zucchini.foo_flag = True
       ...:
       ...:     def bar(courgette):
       ...:         print("And British English")
       ...:         courgette.bar_flag = True
       ...:
    In [9]: x = WhyNot()
    
    In [10]: x.foo()
    I speak American English
    
    In [11]: x.bar()
    And British English
    
    In [12]: x.foo_flag
    Out[12]: True
    
    In [13]: x.bar_flag
    Out[13]: True
    

    但请遵守约定。

    【讨论】:

      【解决方案4】:

      在 Soda 类中,关键字“self”指的是 Soda 的一个实例。在这里简单地“拆分”一个 Soda 对象没有多大意义。您要做的实际上是在创建每个 Soda 对象时拆分字符串参数。

      因此,更好的方法是在 init() 函数中将参数拆分为名称、价格和数量。

      def __init__(self, args = "", _price = 0.0, _quantity = 0):
              args = args.split(",")
              self._name = args[0]
              self._price = args[1]
              self._quantity = args[2]
      

      在 getName 函数中,顾名思义,最好只获取名称。

      def getName(self) :
          return self._name
      

      希望对你学习 Python 有帮助~

      【讨论】:

        【解决方案5】:

        您实际上没有将字符串传递给getName__init__。调用self.getName() 没有传入任何字符串。

        这是 init 期望 (name,price,number) 而不是字符串的情况。所以Pythonic的事情是添加一个静态方法from_string/make/make_from_string

        class Soda:
            def __init__(self, name = '', price = 0.0, quantity = 0) :
                    self._name = name
                    self._price = price
                    self._quantity = quantity
        
            @staticmethod
            def from_string(s):
                return Soda(s.split(','))
        
        
         >>> Soda.from_string('Mtn. Dew,1.00,10')
         <__main__.Soda object at 0x107428f60>
         # Success! Mind you, your class could do with a __str__() method now...
        

        【讨论】:

          猜你喜欢
          • 2021-09-20
          • 2013-05-09
          • 2019-11-16
          • 2022-06-11
          • 2010-09-20
          • 2015-03-24
          • 1970-01-01
          • 2018-09-29
          • 1970-01-01
          相关资源
          最近更新 更多