所以我写了一个小项目来练习对象:
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())
输出
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'
这是为什么?即使我没有定义“自我”,它也能正确输出猫。为什么它没有正确输出狗?我尝试了很多我在这里找到的东西,但是我已经定义了这个功能,而且我没有必要定义“自我”。与猫。任何帮助,将不胜感激。感谢
答案 0 :(得分:1)
这里:
pitbull = Dog('James', 70, 30, 'woef', 'john')
print(Dog.toString())
您创建名为Dog
的{{1}}个实例,但在pitbull
类上调用.toString()
,而不是在Dog
实例上调用pitbull
。
Python让你在类本身上调用instancemethods然后你必须自己传递实例,即Dog.toString(pitbull)
,否则方法的代码无法知道它应该在哪个实例上工作。当然最简单的解决方案是直接在实例上调用方法,因此Python可以automagically pass the instance as first argument。
我,我想你想要:
pitbull = Dog('James', 70, 30, 'woef', 'john')
print(pitbull.toString())
作为旁注:您的代码完全是untythonic,并且可能无法始终按预期工作。:
class Animal:
如果您使用的是Python 2.x,则需要class Animal(object)
,否则大多数Python的对象模型功能将无法正常工作(super()
调用,计算属性,元类等)。
__name = ""
__height = 0
__weight = 0
__sound = 0
在这里定义四个类属性。 “类属性”表示属于类对象本身的属性(Python的类也是对象),因此这些属性由类的所有实例共享。
类属性是完全合法的并且具有它们的用例,但是定义类的实例的属性不属于类属性用例 - 这是你在初始化器中做的事情( __init__()
方法)。此外,如果实例使用与其中一个类属性相同的名称定义属性(这是您为这四个属性执行的操作),则实例属性将在查找实例上的属性时隐藏第一类。
总而言之:这四个类属性完全没用和可能令人困惑。
你也使用__name
符号invokes a name-mangling scheme,使这些名称不可访问(好吧,不是真的,但你必须使用受损的名字)来自课外,所以子类不会能够访问它(除非使用受损的名称,哪种方式会破坏整点)。
“受保护”属性(不属于您的类公共API的属性)的约定是使用单个前导下划线。
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
Python不是Java ...... Java没有什么不对,但Python对计算属性有很强的支持,因此普通的getter / setters对(FWIW使你的属性有效地公开)只是毫无用处。您可以使用公共属性,并在需要时将它们转换为计算属性(使用内置property
类型或自定义描述符)。
def get_type(self):
print("animal")
一个名为get_SOMETHING
的函数通常应该实际上返回某些东西 - 如果它打印出一些东西(对于那些不应该知道的域模型类来说,这通常不是一个坏主意)关于UI层的任何事情,你应该将它命名为print_SOMETHING
(并且可能传递要打印'某事'的流,以便它可以与任何类似流的对象 - 文件或其他任何东西一起使用。)
此外,您可以在此处使用类名(type(self).__name__
),而不是硬编码任何内容。
def toString(self):
没有什么能阻止你使用Java-ish命名约定(除了相当多的python编码器会讨厌你的事实),但这不会充分利用Python的对象模型。相当于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>
接下来是你Dog
课程:
class Dog(Animal):
def __init__(self, name, height, weight, sound, owner):
# ...
您的子类需要多一个参数而不是它的父类。这打破了Liskov的替换原则,该原则指出,为了使子类成为其父类的正确子类型,必须在子类上逐字完成对父类的任何操作。在您的情况下,您无法使用相同的代码对Animal
或Dog
进行无差别的实例化 - 如果与{{1}实例化,Animal
会抱怨获得一个预期的额外参数}或owner
会抱怨缺少Dog
参数。
这里有两种解决方案:
owner
制作owner
可选(=&gt;提供默认值),允许Dog
接受(并默认忽略)任何额外的关键字参数:
类Animal(对象): def init (自我,名字,身高,体重,声音,** kwargs): #您的代码
如果您希望完全符合liskov标准,则必须同时使用这两种解决方案,这样您仍然可以在没有所有者的情况下实现Animal
。
注意:注意Python是动态类型的,子类化主要用于实现重用,而不是用于子类型。你可以有两个完全不相关的类(=&gt;不是从一个公共基类下降)但是完全兼容wrt / liskov的原则,你当然可以自由地子类化一个基类而不使你的子类成为它的父类的正确子类型。但是你的代码片段部分涉及实现继承和子类型,我想我最好提一下。
总结这一切,这里有一个更加pythonic版本的代码:
Dog
答案 1 :(得分:1)
pitbull.toString()
代替Dog.toString()
__var
__str__
方法而不是直接使用toString和print()包含修正的完整代码
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)