Python - 类和 OOP 基础知识

新手上路,请多包涵

我不完全理解课程。我已经阅读了 python 文档和其他几个教程。我明白了它的基本要点,但不明白其中的细微差别。例如在我的代码中:

 class whiteroom():
    """ Pick a door: red, blue, green, or black. """

    do = raw_input("> ")

    if "red" in do:
        print "You entered the red room."

    elif "blue" in do:
        print "You entered the blue room."

    elif "green" in do:
        print "You entered the green room."

    elif "black" in do:
        print "You entered the black room."

    else:
        print "You sit patiently but slowly begin to stave.  You're running out of time."
        return whiteroom()

game = whiteroom()
game

(原版 键盘

我想返回类 whiteroom。这是不可能的,或者没有正确完成。如果你能弄清楚如何返回一个类或如何将两个类“链接”在一起,以便 whiteroom 在 else 上重复,而其他房间(将是类)在调用时返回,那将是很棒的。

此外,我对 __init__ 超级不稳定,我仍然不确定它的目的是什么。每个人都一直告诉我它“初始化”,我确信它确实如此,但这似乎并没有帮助我的大脑。

原文由 Colton Allen 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 422
2 个回答

函数与类非常不同。看起来您采用了一个函数,只是将 def 更改为 class 。我想这 主要 适用于您的情况,但这不是课程应该进行的方式。

类包含函数(方法)和数据。例如,你有一个球:

 class Ball(object):
    # __init__ is a special method called whenever you try to make
    # an instance of a class. As you heard, it initializes the object.
    # Here, we'll initialize some of the data.
    def __init__(self):
        # Let's add some data to the [instance of the] class.
        self.position = (100, 100)
        self.velocity = (0, 0)

    # We can also add our own functions. When our ball bounces,
    # its vertical velocity will be negated. (no gravity here!)
    def bounce(self):
        self.velocity = (self.velocity[0], -self.velocity[1])

现在我们有一个 Ball 类。我们如何使用它?

 >>> ball1 = Ball()
>>> ball1
<Ball object at ...>

它看起来不是很有用。数据是有用的地方:

 >>> ball1.position
(100, 100)
>>> ball1.velocity
(0, 0)
>>> ball1.position = (200, 100)
>>> ball1.position
(200, 100)

好吧,很酷,但是与全局变量相比有什么优势呢?如果您有另一个 Ball 实例,它将保持独立:

 >>> ball2 = Ball()
>>> ball2.velocity = (5, 10)
>>> ball2.position
(100, 100)
>>> ball2.velocity
(5, 10)

并且 ball1 保持独立:

 >>> ball1.velocity
(0, 0)

现在我们定义的那个 bounce 方法(类中的函数)怎么样?

 >>> ball2.bounce()
>>> ball2.velocity
(5, -10)

bounce 方法导致它修改 velocity 数据本身。同样, ball1 没有被触及:

 >>> ball1.velocity

应用

一个球很整洁,但大多数人并没有模拟它。你在做游戏。让我们想想我们拥有什么样的东西:

  • 房间 是我们能拥有的最明显的东西。

那我们开个房间吧。房间有名字,所以我们将有一些数据来存储:

 class Room(object):
    # Note that we're taking an argument besides self, here.
    def __init__(self, name):
        self.name = name  # Set the room's name to the name we got.

让我们创建一个实例:

 >>> white_room = Room("White Room")
>>> white_room.name
'White Room'

漂亮。但是,如果您希望不同的房间具有不同的功能,那么这并不是那么有用,所以让我们创建一个 _子类_。 子类 继承其 超类 的所有功能,但您可以添加更多功能或覆盖超类的功能。

让我们考虑一下我们想对房间做什么:

我们想与房间互动。

我们该怎么做?

用户输入一行得到响应的文本。

它的响应方式取决于房间,所以让房间使用名为 interact 的方法来处理:

 class WhiteRoom(Room):  # A white room is a kind of room.
    def __init__(self):
        # All white rooms have names of 'White Room'.
        self.name = 'White Room'

    def interact(self, line):
        if 'test' in line:
            print "'Test' to you, too!"

现在让我们尝试与它交互:

 >>> white_room = WhiteRoom()  # WhiteRoom's __init__ doesn't take an argument (even though its superclass's __init__ does; we overrode the superclass's __init__)
>>> white_room.interact('test')
'Test' to you, too!

您的原始示例以在房间之间移动为特色。让我们使用一个名为 current_room 的全局变量来跟踪我们所在的房间。 1让我们也创建一个红色房间。

1. 这里除了全局变量还有更好的选择,但为了简单起见,我将使用一个。

 class RedRoom(Room):  # A red room is also a kind of room.
    def __init__(self):
        self.name = 'Red Room'

    def interact(self, line):
        global current_room, white_room
        if 'white' in line:
            # We could create a new WhiteRoom, but then it
            # would lose its data (if it had any) after moving
            # out of it and into it again.
            current_room = white_room

现在让我们试试看:

 >>> red_room = RedRoom()
>>> current_room = red_room
>>> current_room.name
'Red Room'
>>> current_room.interact('go to white room')
>>> current_room.name
'White Room'

读者练习: 将代码添加到 WhiteRoominteract 让你回到红色房间。

现在我们已经完成了所有工作,让我们把它们放在一起。有了我们新的 name 所有房间的数据,我们还可以在提示中显示当前房间!

 def play_game():
    global current_room
    while True:
        line = raw_input(current_room.name + '> ')
        current_room.interact(line)

您可能还想制作一个重置游戏的功能:

 def reset_game():
    global current_room, white_room, red_room
    white_room = WhiteRoom()
    red_room = RedRoom()
    current_room = white_room

将所有类定义和这些函数放入一个文件中,您可以像这样在提示符下播放它(假设它们在 mygame.py 中):

 >>> import mygame
>>> mygame.reset_game()
>>> mygame.play_game()
White Room> test
'Test' to you, too!
White Room> go to red room
Red Room> go to white room
White Room>

为了能够仅通过运行 Python 脚本来玩游戏,您可以在底部添加:

 def main():
    reset_game()
    play_game()

if __name__ == '__main__':  # If we're running as a script...
    main()

这是对类的基本介绍以及如何将其应用到您的情况。

原文由 icktoofay 发布,翻译遵循 CC BY-SA 3.0 许可协议

我相信您以前已经听过所有这些,但我会试一试。

类是一种将一堆函数和变量分组到一个对象中的方法。当您深入了解它时,这只是一种将所有内容组织成有意义的组的方法。让事情更容易理解、调试、扩展或维护是有好处的,但基本上它只是一种让你的心智模型中的东西更明确的方法。

您的代码看起来像是在尝试将整个程序编写在一个“对象”中(实际上,您只是编写了一个错误的函数)。

考虑一下这个。

想想你心目中的房间模型,房间里有门,里面有白板。门有颜色。此外,白板上可以写一些文字。为了简单起见,我们将把它留在那里。

对我来说,这暗示了 3 个不同的对象——一个有颜色字符串的门对象,一个有文本字符串的白板对象,以及一个有门和白板的房间对象。

考虑以下代码:

 class Door(object):
    def __init__(self, color):
        self.color = color

class Whiteboard(object):
    def __init__(self, default_text=''):
        self.text = ''
        self.write_text(default_text)

    def write_text(self, text):
        self.text += text

    def erase(self):
        self.text = ''

class Room(object):
    def __init__(self, doorcolor, whiteboardtext=''):
        self.whiteboard = Whiteboard(whiteboardtext)
        self.door = Door(doorcolor)

# make a room with a red door and no text on the whiteboard
room1 = Room('red')

# make a room with a blue door and 'yeah, whiteboard' on the whiteboard
room2 = Room('blue', 'yeah, whiteboard')

# make a room with a green door
room3 = Room('green')

# now I can play around with my 'rooms' and they keep track of everything internally

print 'room 1 door color: ' + room1.door.color
print 'room 2 door color: ' + room2.door.color

# all my rooms have a door and a whiteboard, but each one is different and self contained. For example
# if I write on room 1's whiteboard, it doesn't change anything about room 3s

print 'room1 whiteboard: ' + room1.whiteboard.text
print 'room2 whiteboard: ' + room2.whiteboard.text
print 'room3 whiteboard: ' + room3.whiteboard.text

print '-- changeing room 1 whiteboard text --'

room1.whiteboard.write_text('oop is really helpful')

print 'room1 whiteboard: ' + room1.whiteboard.text
print 'room2 whiteboard: ' + room2.whiteboard.text
print 'room3 whiteboard: ' + room3.whiteboard.text

init 函数是在您“初始化”类的新实例时调用的函数。在示例中,我制作了 3 个 Room 对象,每个对象都在内部创建了一个 Door 和 Whiteboard 对象。我传递给构造函数的参数 Room(parameter1, parameter2) 传递给 init 函数 - 你可以看到我正在使用它来设置门的颜色和可选的白板上的一些文本。另请注意,“属于”对象的变量被引用 self - 此引用是作为第一个参数传递给所有类函数的内容(稍后当您扩展类和时变得更加重要)其他更高级的东西)。

原文由 Collin Green 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题