Python - 类和OOP基础知识

Col*_*len 16 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
Run Code Online (Sandbox Code Playgroud)

(原始键盘)

我想返回班级whiteroom.这是不可能的,或者没有正确完成.如果你可以清理如何返回一个类或如何将两个类"链接"在一起,以便whiteroom在else上重复,而其他房间(可能是类)将在调用时返回,这将是非常棒的.

我也非常不稳定__init__,我仍然不确定它的目的是什么.每个人都在告诉我它"初始化",我确信它确实如此,但这似乎并没有帮助我的大脑.

ick*_*fay 45

功能与类非常不同.它看起来像你花了功能,只是改变了defclass.我想这主要适用于你的情况,但不是应该如何进行课程.

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

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])
Run Code Online (Sandbox Code Playgroud)

现在我们Ball上课了.我们怎么用呢?

>>> ball1 = Ball()
>>> ball1
<Ball object at ...>
Run Code Online (Sandbox Code Playgroud)

它看起来不太有用.数据是有用的地方:

>>> ball1.position
(100, 100)
>>> ball1.velocity
(0, 0)
>>> ball1.position = (200, 100)
>>> ball1.position
(200, 100)
Run Code Online (Sandbox Code Playgroud)

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

>>> ball2 = Ball()
>>> ball2.velocity = (5, 10)
>>> ball2.position
(100, 100)
>>> ball2.velocity
(5, 10)
Run Code Online (Sandbox Code Playgroud)

ball1保持独立:

>>> ball1.velocity
(0, 0)
Run Code Online (Sandbox Code Playgroud)

bounce我们定义的那个方法(类中的函数)呢?

>>> ball2.bounce()
>>> ball2.velocity
(5, -10)
Run Code Online (Sandbox Code Playgroud)

bounce方法使其修改velocity自身的数据.再次,ball1没有被触及:

>>> ball1.velocity
Run Code Online (Sandbox Code Playgroud)

应用

球是整齐的,但大多数人都没有模拟.你正在制作游戏.让我们想一想我们有什么样的东西:

  • 房间是我们可以拥有的最明显的东西.

所以让我们做一个房间.房间有名字,所以我们会有一些数据存储:

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.
Run Code Online (Sandbox Code Playgroud)

让我们来做一个例子:

>>> white_room = Room("White Room")
>>> white_room.name
'White Room'
Run Code Online (Sandbox Code Playgroud)

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

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

我们想与房间互动.

我们该怎么做?

用户键入一行响应的文本.

它的响应方式取决于房间,所以让我们用一个叫做的方法来处理房间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!"
Run Code Online (Sandbox Code Playgroud)

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

>>> 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!
Run Code Online (Sandbox Code Playgroud)

您的原始示例在房间之间移动.让我们使用一个全局变量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
Run Code Online (Sandbox Code Playgroud)

现在让我们试试:

>>> red_room = RedRoom()
>>> current_room = red_room
>>> current_room.name
'Red Room'
>>> current_room.interact('go to white room')
>>> current_room.name
'White Room'
Run Code Online (Sandbox Code Playgroud)

读者练习:添加代码WhiteRoominteract,可以让你回到红厅.

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

def play_game():
    global current_room
    while True:
        line = raw_input(current_room.name + '> ')
        current_room.interact(line)
Run Code Online (Sandbox Code Playgroud)

您可能还想创建一个重置游戏的功能:

def reset_game():
    global current_room, white_room, red_room
    white_room = WhiteRoom()
    red_room = RedRoom()
    current_room = white_room
Run Code Online (Sandbox Code Playgroud)

将所有类定义和这些函数放入一个文件中,你可以在这样的提示符下播放它(假设它们在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>
Run Code Online (Sandbox Code Playgroud)

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

def main():
    reset_game()
    play_game()

if __name__ == '__main__':  # If we're running as a script...
    main()
Run Code Online (Sandbox Code Playgroud)

这是对课程的基本介绍以及如何将其应用到您的情况中.

  • @Niklas:是的; 游戏状态真的应该*在课堂上; 然而,我试图让它变得尽可能简单,我觉得让游戏状态成为一个类可能会让我的回答更加混乱.其次,也许这些东西中的一些不应该是类,但考虑到我试图演示如何使用类,我认为使用它们是合理的.此外,我认为有人可以考虑将其他方法和数据添加到类中. (3认同)
  • 那个'球`不应该是一个阶级.经验法则:如果它只有两个方法,其中一个是`__init__`,你应该使用一个函数和`functools.partial`来将函数绑定到一些数据.与此处介绍的其他课程相同.Python不是Java!我在这里看到的唯一*应该*是一个类是游戏本身,你使用模块全局状态代替? (2认同)

Col*_*een 5

我相信你以前听过这一切,但我会试一试.

类是将一堆函数和变量组合到单个对象中的一种方法.当你完全了解它时,这只是一种将所有内容组织成有意义的组的方法.为了使事情更容易理解,调试,扩展或维护,有一些好处,但基本上它只是一种在心智模型中做出更多定义的方法.

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

请考虑这一点.

想想你的房间的心理模型,它们有门,里面有白板.门有颜色.此外,白板上可以写一些文字.我们将它留在那里简单.

对我来说,这表明了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
Run Code Online (Sandbox Code Playgroud)

INIT功能是当你初始化'类的新实例什么被调用.在示例中,我正在制作3个Room对象,每个对象在内部创建一个Door和Whiteboard对象.我传递给构造函数的参数Room(parameter1, parameter2)传递给init函数 - 你可以看到我用它来设置门颜色和白板上的一些文本.还要注意参与"属于"对象的变量self- 这个引用作为第一个参数传递给所有类函数(后来当你扩展类和其他更高级的东西时变得更加重要).