简体   繁体   English

TypeError:toString()缺少1个必需的位置参数:'self'

[英]TypeError: toString() Missing 1 required positional argument: 'self'

So I wrote a small project to practice objects: 所以我写了一个小项目来练习对象:

import random
import os
import sys

class Animal:
    __name = ""
    __height = 0
    __weight = 0
    __sound = 0

    def __init__(self, name, height, weight, sound):
        self.__name = name
        self.__height = height
        self.__weight = weight
        self.__sound = sound


    def set_name(self, name):
        self.__name = name

    def get_name(self):
        return self.__name

    def set_height(self, height):
        self.__height = height

    def get_height(self):
        return self.__height

    def set_weight(self, weight):
        self.__weight = weight

    def get_weight(self):
        return self.__weight

    def set_sound(self, sound):
        self.__sound = sound

    def get_sound(self):
        return self.__sound

    def get_type(self):
        print("animal")

    def toString(self):
        return "{} is {} cm tall and {} kilograms and says {}".format(self.__name,
                                                                     self.__height,
                                                                     self.__weight,
                                                                     self.__sound)

cat = Animal('Whiskers', 33, 7, 'Meow')

print(cat.toString())

class Dog(Animal):
    __owner = ""
    def __init__(self, name, height, weight, sound, owner):
        self.__owner = owner
        super(Dog, self).__init__(name, height, weight, sound)

    def set_owner(self, owner):
        self.__owner = owner

    def get_owner(self):
        return self.__owner

    def get_type(self):
        print("Dog")

    def toString(self):
        return "{} is {} cm tall and {} kilograms and says {}. His owner is {}".format(self.__name,
                                                                                self.__height,
                                                                                self.__weight,
                                                                                self.__sound,
                                                                                self.__owner)

pitbull = Dog('James', 70, 30, 'woef', 'john')
print(Dog.toString())

It outputs 输出

Whiskers is 33 cm tall and 7 kilograms and says Meow

    Traceback (most recent call last):
      File "C:/Users/*****/AppData/Local/Programs/Python/Python36-32/practice object oriented programming.py", line 78, in <module>
        print(Dog.toString())
    TypeError: toString() missing 1 required positional argument: 'self'

why is this? 为什么是这样? It output the cat correctly even though I didn't define 'self'. 即使我没有定义“自我”,它也可以正确输出猫。 Why doesn't it output dog correctly? 为什么它不能正确输出狗? I have tried multiple things I found here, but I have defined the function and I didn't have to define 'self' with the cat. 我已经尝试过在这里找到的多种方法,但是我已经定义了函数,而不必与猫定义“自我”。 Any help would be appreciated. 任何帮助,将不胜感激。 Thanks 谢谢

Here : 这里 :

pitbull = Dog('James', 70, 30, 'woef', 'john')
print(Dog.toString())

You create a Dog instance named pitbull , but call .toString() on the Dog class, not on the pitbull instance. 您创建一个名为pitbullDog实例,但在Dog类而不是pitbull实例上调用.toString()

Python let's you call instancemethods on the class itself but then you have to pass the instance yourself, ie Dog.toString(pitbull) , else the method's code cannot know on which instance it's supposed to work. Python让我们在类本身上调用instancemethods,但是您必须自己传递实例,即Dog.toString(pitbull) ,否则该方法的代码无法知道应该在哪个实例上工作。 Of course the simplest solution is to invoke the method directly on the instance, so Python can automagically pass the instance as first argument . 当然,最简单的解决方案是直接在实例上调用该方法,因此Python可以自动将实例作为第一个参数传递

IOW, I assume you wanted: IOW,我想你想要:

pitbull = Dog('James', 70, 30, 'woef', 'john')
print(pitbull.toString())

As a side note: your code is totally unpythonic, and might not always work as expected.: 附带一提:您的代码完全是非Python的,可能无法始终按预期工作。

class Animal:

If you're using Python 2.x, you want class Animal(object) , else most of Python's object model features won't work correctly ( super() calls, computed attributes, metaclasses etc). 如果您使用的是Python 2.x,则需要使用class Animal(object) ,否则大多数Python对象模型功能将无法正常工作( super()调用,计算属性,元类等)。

    __name = ""
    __height = 0
    __weight = 0
    __sound = 0

Here you define four class attributes. 在这里,您定义了四个类属性。 "class attributes" means those attributes belong to the class object itself (Python's classes are objects too), so those attributes are shared by all instances of the class. “类属性”表示那些属性属于类对象本身(Python的类也是对象),因此这些属性由该类的所有实例共享。

Class attributes are perfectly legal and have their use case, but defining what attributes an instance of the class will have is not part of class attributes use cases - this is something you do in the initializer (the __init__() method). 类属性是完全合法的,并且具有用例,但是定义类实例将具有的属性并不属于类属性用例的一部分-这是您在初始化程序( __init__()方法)中所做的事情。 Also if the instance defines an attribute by the same name as one of the class attribute (whihc is what you're doing for those four attributes), the instance attribute will shadow the class one when looking up the attribute on an instance. 同样,如果实例使用与类属性之一相同的名称定义了一个属性(这就是您对这四个属性所做的工作),那么当在实例上查找该属性时,实例属性将使一类成为阴影。

To make a long story short: those four class attributes are totally useless and possibly confusing. 长话短说:这四个类属性完全没有用, 并且可能造成混淆。

Also you use the __name notation which invokes a name-mangling scheme , making those names inaccessible (well, not really but you have to use the mangled name) from outside the class, so child classes won't be able to access it (unless using the mangled name, which kind of defeats the whole point). 另外,您还可以使用__name表示法来调用名称处理方案 ,从而使这些名称无法从类外部访问(嗯,不是真的,但必须使用变形的名称),因此子类将无法访问它(除非使用错误的名称,这会破坏整个重点)。

The convention for "protected" attributes (attributes that are not part of your class public API) is to use a single leading underscore. “受保护”属性(不属于类公共API的属性)​​的约定是使用单个前划线。

    def __init__(self, name, height, weight, sound):
        self.__name = name
        self.__height = height
        self.__weight = weight
        self.__sound = sound

Cf the comments above... cf以上评论...

def set_name(self, name):
    self.__name = name

def get_name(self):
    return self.__name

Python is not Java... Nothing wrong about Java, but Python has a strong support for computed attributes, so plain getter/setters pairs (which FWIW make your attributes effectively public) are just plain useless. Python不是Java ... Java没什么错,但是Python对计算属性非常有力的支持,因此简单的getter / setter对(FWIW有效地将您的属性公开)对就毫无用处。 You can just use public attributes, and turn them into computed ones (using the builtin property type or a custom descriptor) if and when the need arises. 您可以只使用公共属性,并在需要时将其转换为计算property (使用内置property类型或自定义描述符)。

def get_type(self):
    print("animal")

A function named get_SOMETHING is usually expected to actually return something - if it prints something (which is more often than not a bad idea for domain model classes which are not supposed to know anything about the UI layer), you should name it print_SOMETHING (and probably pass the stream on which 'something' is to be printed so it can be used with any stream-like object - file or whatever). 通常希望一个名为get_SOMETHING的函数实际返回一些内容-如果它输出一些内容(对于不应该了解UI层的领域模型类,这通常不是一个坏主意),则应将其命名为print_SOMETHING (并且可能会传递要在其上打印“内容”的流,以便可以将其用于任何类似流的对象(文件或其他任何对象)。

Also you could use the class name here ( type(self).__name__ ) instead of hardcoding anything. 您也可以在此处使用类名( type(self).__name__ ),而不用硬编码任何内容。

def toString(self):

Nothing prevents you from using Java-ish nameing conventions (except from the fact that quite a few python coders will hate you for this), but this won't make the best use of Python's object model. 没有什么可以阻止您使用Java式的命名约定(除了相当多的python编码器对此讨厌的事实之外),但这不会充分利用Python的对象模型。 The equivalent to Java's toString() is __str__(self) and will be automagically invoked by Python when trying to format instances of you class as strings ie: 与Java的toString()等效的是__str__(self) ,当尝试将您的类的实例格式化为字符串时,Python将自动调用它,即:

>>> class Foo(object):
...     def __init__(self, name):
...         self.name = name
...     def __str__(self):
...         return "<{} : {}>".format(type(self).__name__, self.name)
... 
>>> f = Foo("yadda")
>>> str(f)
'<Foo : yadda>'
>>> print "{}".format(f)
<Foo : yadda>

Next is you Dog class: 接下来是Dog类:

class Dog(Animal):
    def __init__(self, name, height, weight, sound, owner):
        # ...

Your subclass expects one more argument than it's parent class. 您的子类期望比其父类多一个参数。 This breaks Liskov's substitution principle which states that for a subclass to be a proper subtype of it's parent, any action on the parent class must be done verbatim on the subclass. 这违反了Liskov的替换原则,该原则指出,要使子类成为其父项的正确子类型,对父类的任何操作都必须在子类上逐字进行。 In your case, you could not use the same code to instanciate indifferently an Animal or a Dog - either Animal would complain about getting one expected extra parameter if instanciated with a owner or Dog would complain about the missing owner argument. 在您的情况下,您不能使用相同的代码无差别地实例化AnimalDog -如果Animal ownerAnimal实例化, Animal将抱怨获得一个预期的额外参数,或者Dog将抱怨缺少owner参数。

There are two solutions here: 这里有两种解决方案:

  • make owner optional (=> provide a default) for Dog , 使Dog owner可选(=>提供默认值)
  • allow Animal to accept (and by default ignore) any extra keyword argument: 允许Animal接受(默认情况下忽略)任何其他关键字参数:

    class Animal(object): def init (self, name, height, weight, sound, **kwargs): # your code here Animal(object)类:def init (自身,名称,身高,体重,声音,**虚假):#您的代码在这里

If you want to be fully liskov-compliant, you'll have to use both solutions together so you can still instanciate a Dog without an owner. 如果您想完全与liskov兼容,则必须同时使用这两种解决方案,这样您仍然可以在没有所有者的情况下实例化Dog

NB : note that Python being dynamically typed, subclassing is mainly for implementation reuse, not for subtyping. 注意:请注意,Python是动态类型化的,子类主要用于实现重用,而不是用于子类型化。 You could have two totally unrelated classes (=> not descending from a common base class) yet perfectly compatible wrt/ liskov's principle, and you are of course free to subclass a base class without making your child class a proper subtype of it's parent. 您可能有两个完全不相关的类(=>并非从通用基类派生而来),但它们与wrt / liskov原理完全兼容,并且您当然可以自由地对基类进行子类化,而无需使子类成为其父类的适当子类型。 But your code snippet being partly about both implementation inheritance and subtyping, I thought I'd better mention this. 但是您的代码片段部分涉及实现继承子类型化,我想我最好提一下。

To summarize all this, here's a much more pythonic version of your code: 总结一下,这是代码的更多Python版本:

class Animal(object):

    def __init__(self, name, height, weight, sound, **kwargs):
        self.name = name
        self.height = height
        self.weight = weight
        self.sound = sound

    # Here we use a read-only computed attribute
    @property
    def type(self):
        return type(self).__name__


    # Here we use a protected class attribute, 
    # named in ALL_CAPS to denote it's supposed to 
    # be treated as a constant.
    _STR_FMT = "{self.type} {self.name} is {self.height} cm tall and {self.weight} kilograms and says {self.sound}." 

    def __str__(self):
        return self._STR_FMT.format(self=self)


cat = Animal('Whiskers', 33, 7, 'Meow')
print(str(cat))

class Dog(Animal):
    def __init__(self, name, height, weight, sound, owner=None, **kwargs):
        super(Dog, self).__init__(name, height, weight, sound, **kwargs)
        self.owner = owner

    def __str__(self):
        fmt = self._STR_FMT
        if self.owner:
            fmt += " His owner is {self.owner}."
        else:
            fmt += " He has no known owner."

        return fmt.format(self=self)

pitbull = Dog('James', 70, 30, 'woef', 'john')
print("{}".format(pitbull))
  1. Use pitbull.toString() instead of Dog.toString() 使用pitbull.toString()代替Dog.toString()
  2. __var is not accessible from the class that inherits 不能从继承的类访问__var
  3. use __str__ method rather than toString and print() directly 直接使用__str__方法而不是toString和print()

Full code with fixes 完整代码及修复

import random
import os
import sys

class Animal:
    _name = ""
    _height = 0
    _weight = 0
    _sound = 0

    def __init__(self, _name, _height, weight, sound):
        self._name = _name
        self._height = _height
        self._weight = weight
        self._sound = sound


    def set__name(self, _name):
        self._name = _name

    def get__name(self):
        return self._name

    def set__height(self, _height):
        self._height = _height

    def get__height(self):
        return self._height

    def set_weight(self, weight):
        self._weight = weight

    def get_weight(self):
        return self._weight

    def set_sound(self, sound):
        self._sound = sound

    def get_sound(self):
        return self._sound

    def get_type(self):
        print("animal")

    def __str__(self):
        return "{} is {} cm tall and {} kilograms and says {}".format(self._name,
                                                                     self._height,
                                                                     self._weight,
                                                                     self._sound)

class Dog(Animal):
    __owner = ""
    def __init__(self, _name, _height, _weight, _sound, owner):
        self.__owner = owner
        Animal.__init__(self, _name,_height, _weight, _sound)

    def set_owner(self, owner):
        self.__owner = owner

    def get_owner(self):
        return self.__owner

    def get_type(self):
        print("Dog")

    def __str__(self):
        return "{} is {} cm tall and {} kilograms and says {}. His owner is {}".format(self._name,
                                                                                self._height,
                                                                                self._weight,
                                                                                self._sound,
                                                                                self.__owner)

pitbull = Dog('James', 70, 30, 'woef', 'John')
cat = Animal('Whiskers', 33, 7, 'Meow')
print(cat)
print(pitbull)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 TypeError:save()缺少1个必需的位置参数:“ self” - TypeError: save() missing 1 required positional argument: 'self' 类型错误:check() 缺少 1 个必需的位置参数:&#39;self&#39; - TypeError: check() missing 1 required positional argument: 'self' TypeError:attack()缺少1个必需的位置参数:&#39;self&#39; - TypeError: attack() missing 1 required positional argument: 'self' Luigi: TypeError: ... 缺少 1 个必需的位置参数:'self' - Luigi: TypeError: ... missing 1 required positional argument: 'self' TypeError: analyzers() 缺少 1 个必需的位置参数:'self' - TypeError: analyzers() missing 1 required positional argument: 'self' TypeError:endturn()缺少1个必需的位置参数:&#39;self&#39; - TypeError: endturn() missing 1 required positional argument: 'self' 类型错误:kollision() 缺少 1 个必需的位置参数:&#39;self&#39; - TypeError : kollision() missing 1 required positional argument: 'self' TypeError:itertuples()缺少1个必需的位置参数:“ self” - TypeError: itertuples() missing 1 required positional argument: 'self' 类型错误:get() 缺少 1 个必需的位置参数:“self” - TypeError: get() missing 1 required positional argument: 'self' 类型错误:mainloop() 缺少 1 个必需的位置参数:'self' - TypeError: mainloop() missing 1 required positional argument: 'self'
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM