Python 2.7.x - 尝试了解OOP和类

时间:2013-11-29 16:08:10

标签: python oop

我打算组织并缩短后续版本,但为了记住6个月后的具体细微差别,我按时间顺序排除了它。

from random import *

class Card:
    def __init__(self):
        self.rank = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
        self.suit = ['s', 'h', 'c', 'd']
        self.card = choice(rank) + choice(suit)

上面的代码在IDLE中运行。但是当我做>>> c = Card()[enter],我得到了下面的追溯。

Traceback (most recent call last):
  File "<pyshell#18>", line 1, in <module>
    c = Card()
  File "C:\Current\MY_PYTHON\Py_OOP_progs\scrap2.py", line 7, in __init__
    self.card = choice(rank) + choice(suit)
NameError: global name 'rank' is not defined

这是为什么?如果我将其更改为包含'return self.card',我也会获得几乎相同的追溯; '退卡;或者“返回”到类定义的末尾。如果我删除'自我'。来自变量(rank,suit和card)的前缀,然后它运行,我可以做&gt;&gt;&gt; c =卡()[输入];但是当我尝试做&gt;&gt;&gt; c.card [enter],我得到另一个追溯:

Traceback (most recent call last):
  File "<pyshell#24>", line 1, in <module>
    c.card
AttributeError: Card instance has no attribute 'card'

...这是我期望得到的,这也是我最初为rank,suit和card实例变量添加'self'前缀的原因。我想要得到的效果是,当我做&gt;&gt;&gt; c = Card()[enter],将c的卡实例变量设置为具有两个随机值:随机排名和随机诉讼,如原始代码所示。然后,我应该能够实例化52个Card()实例并在程序中稍后打印出来。这样做的传统方法是什么?注意 - 代码背后没有特别的含义 - 它几乎是任意的。我还没有完成OOP学习曲线,因此我没有阅读更多材料,而是认为如果我直接问我的错误,那么课程将更具互动性和难忘性。是否在代码中定义了一个必要的方法?

另外(只是一个猜测),除了获得更多实践经验编码类示例等之外,阅读python中“名称空间”和“范围”这两个区域可能是最相关的,以帮助我理解缺点上面的代码?

更多的实验(事后)与上述问题相关......代码:

from random import *

class Card:
    rank = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
    suit = ['s', 'h', 'c', 'd']
    card = choice(rank) + choice(suit)

...运行正常,但实例化Card(),&gt;&gt;&gt;之后的事实除外c.card [enter]每次都会给出相同的值。我终于得到了一些工作。以下代码:

class Card:
    global rank
    global suit
    rank = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
    suit = ['s', 'h', 'c', 'd']

    def make_Card(self):
        card = choice(rank) + choice(suit)
        print card
运行并允许我这样做:

>>> c = Card()
>>> c.make_Card()
5h
>>> c.make_Card()
4h
>>> c.make_Card()
2s
但是,我不知道。在最后一段代码中,我碰巧偶然发现了一种常规方法吗,因为我记得(模糊地)经常阅读有关声明全局变量的内容,在某些情况下设计很糟糕吗?

3 个答案:

答案 0 :(得分:2)

第一个选项位于下一个代码部分:

from random import *

class Card:
    def __init__(self):
        self.rank = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
        self.suit = ['s', 'h', 'c', 'd']
        self.card = choice(rank) + choice(suit)   

改为:

self.card = choice(self.rank) + choice(self.suit)   

由于变量ranksuit在您说self.card = choice(rank) + choice(suit)时不存在,但self.rankself.suit确实存在

另一种选择是:

class Card:
    def __init__(self):
        rank = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
        suit = ['s', 'h', 'c', 'd']
        card = choice(rank) + choice(suit)   
        self.rank = rank
        self.suit = suit
        self.card = card

但我想第一个选择是pythonic

答案 1 :(得分:2)

您似乎在混淆O-O问题和Python语法问题。

你的队伍和职业不是对象;他们属于这个阶级;这是一个OO评论。

使用self语法引用成员变量(这就是使用self参数定义成员方法的原因):

class Card(object):
   """variables that are the same for all
   Card instances"""
   ranks = ['2', ..., 'A']
   suits = ['s', 'h', 'c', 'd']

   def __init__(self):
      self.rank = choice(Card.ranks)
      self.suit = choice(Cart.suits)

   def card(self):
      return self.rank + self.suit

   def __repr__(self):
      """standard method to 'print' this object"""
      return self.card()

请注意数据成员如何不丢失信息:检查两张卡是否来自同一套装是没有问题的:在rank + suit解决方案中,您必须拆分self.card和记得拿第二个项目,你只需要card.suit这个设计。

现在您可以创建这样的卡片:

>>> c1 = Card()
>>> c2 = Card()
>>> cards = [ Card() for _ in xrange(0, 10) ]

玩得开心。

答案 2 :(得分:1)

存储在类实例中的任何变量都需要self.前缀才能访问该变量。没有它,Python只在本地命名空间中查找,然后在全局命名空间中查找。在IDLE中,你可能以交互方式定义了一个rank或suit变量,类实例在全局命名空间中找到它。

解决问题:

from random import *

class Card:
    def __init__(self):
        self.rank = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
        self.suit = ['s', 'h', 'c', 'd']
        # Access the instance's rank and suit. 
        self.card = choice(self.rank) + choice(self.suit)