欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

初窥门径——通过游戏人物建模来窥探python的数据模型

程序员文章站 2022-07-08 10:54:27
目录Python进阶系列说明游戏人物建模游戏主角具有自己特质游戏主角的性质是不可变的namedtuple 的用法人物集合类属性范围确定建立人物模型建立人物模型管理类len的用法__getitem__用法Python进阶系列说明我一直的观点就是像玩一样学习,能达到最高的效率。就像人只有与环境产生一种和解,一种高贵的顺从的姿态,才能活的最舒服。我想让我的文章变得易读又不啰嗦,尽力写好这一专栏。一是希望帮助到其他Python开发者,二者也是为了自省。在您阅读的过程中,无论是语法上的错误,还是专业上的错误。...

一、 Python进阶系列说明

我一直的观点就是像玩一样学习,能达到最高的效率。就像人只有与环境产生一种和解,一种高贵的顺从的姿态,才能活的最舒服。

我想让我的文章变得易读又不啰嗦,尽力写好这一专栏。一是希望帮助到其他Python开发者,二者也是为了自省。

在您阅读的过程中,无论是语法上的错误,还是专业上的错误。如您阅读时遇到,在你嘲笑笔者之后也请不吝指正。

为了阅读的简洁,如无特别的说明。我们所说的编程思想,编程术语都指的是python。

这一专栏文章的参考文献主要来自以下几本书籍,如您对python较为感兴趣也建议您直接阅读原书。

  1. 《Python学习手册》
  2. 《流畅的Python》
  3. 《利用Python进行数据分析》

二、游戏人物建模

我们这个年代的人大都接触过几款网络游戏,我们来思考一下以我们为第一视角的网络游戏,在建模时需要具备哪些特性。结合我的经验来说,我认为应有以下特性。

1.游戏主角具有自己特质

就拿某下城这款游戏来说,我们在进行创建人物的时候。除了需要给他起名之外,还需要选择人物的性别,人物的职业。一些其他的游戏可能还要选择人物的年龄(孩童或者成人),游戏的门派等等。

那么这个模型就是最经典对象了,它是有自己的特性的。这点很好实现,最直接的方式就是通过类来实现,当然我们也可以通过字典来实现。

class Character:

    def __init__(self, name, gender, occupation):
        self.name = name
        self.gender = gender
        self.occupation = occupation

2.游戏主角的性质是不可变的

在游戏人物创建之后,性质大都是不可变的。最起码主要的性质是不可变的,比如性别和职业这些。除非游戏特殊提供,否则你很那进行改变。那么这个时候我们就要求性质是不可变的,这也很好实现。我们只需要把这几个属性变为不可变就行,这个时候我们上述所说的字典在建模中可能就行不通了。
而在类中实现这些,我们把对应的属性变为私有属性即可。

class Character:

    def __init__(self, name, gender, occupation):
        self.__name = name
        self.__gender = gender
        self.__occupation = occupation

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, value):
        print("不允许的改变")

初窥门径——通过游戏人物建模来窥探python的数据模型
这样就实现了我们的需求,但是不够简洁。绕了一大圈实现了需求可就是感觉不够优雅。而事实上python早已提供了类似的数据结构。

from collections import namedtuple
Character = namedtuple("Character",['name', 'gender', 'occupation'])

初窥门径——通过游戏人物建模来窥探python的数据模型
这样的实现就做到了更精简了一些,上面我们用到了namedtuple类型。他的后缀的tuple,我们不难联想到元组tuple。

3.namedtuple 的用法

事实上namedtuple是tuple的手足兄弟。显然namedtuple要更强大一点,他可以通过属性值获取而不必通过索引。构造一个namedtuple需要两个参数,分别是tuple的名字和其中域的名字。

比如在上例中,tuple的名字是“Character”,它包括三个域,分别是“name”、“gender”和“occupation”。

三、人物集合管理

我们在上述中已经实现了人物模型类,为了更好的管理每一个人物模型,我们则需要一个集合管理类。假设我们要设计三国的游戏建模,我们把人物模型的属性值确定好。

1.属性范围确定

country: 魏国、蜀国、吴国
occupation: 军师、武将、谋臣、文官

我们暂定三国人物有这两个属性,实际游戏设计可能会有更多属性,官职、性别等等,这里不过多设计。

2.建立人物模型

 Character = namedtuple("Character", ['country', 'occupation'])

3.建立人物模型管理类

class Character_Collect:
    countrys = ["魏国", "吴国", "蜀国"]
    occupations = ["军师", "武将", "谋臣"]
    def __init__(self):
        self.characters = [Character(cou, occ) for cou in self.countrys
                                               for occ in self.occupations]

初窥门径——通过游戏人物建模来窥探python的数据模型
这样我们就有了人物模型的集合了,我们想要有更灵活的操作来操作他们。比如我们想知道一共有多少个模型。

4.len的用法

我们尝试直接获取长度。
初窥门径——通过游戏人物建模来窥探python的数据模型
这个时候当然不行,错误显示这个对象没有len方法,那么我们就来创建一个len方法。

 def __len__(self):
        return len(self.characters)

初窥门径——通过游戏人物建模来窥探python的数据模型
我们通过在类中创建__len__ 对象就能实现len方法的调用。实际上,len(object)的本质还是调用object中的__len__方法
初窥门径——通过游戏人物建模来窥探python的数据模型
但是实际使用中很少有人会使用object.__len__方法
这时候你可能会说的,我们使用len(list,tuple) 是因为list和tuple的数据结构中也定义的有__len__方法吗?

其实不是的。python的内置对象是C语言体,和我们写的对象相比。这些c语言体有ob_size属性,代表这些对象的长度。在len(list)中,并不是调用list中的__len__ 方法而是直接调用ob_size属性,这样速度也大大提升了。

5.__getitem__用法

我们虽然已经构造了人物模型集合,但是对这个集合的操作并不那么方便。我们想通过索引的方式,取到模型集合里某一个模型。

实现依然比较简单。

def __getitem__(self, postions):
        return self.characters[postions]

我们在对象中实现了__getitem__方法,并返回一个可迭代对象其实上就是实例化的模型列表。
这时候就可以方便的操作该类了。
初窥门径——通过游戏人物建模来窥探python的数据模型
我们可以使用python中的序列对象的一切来操作该对象,事实上我们甚至可以使用choice方法随机取一一个模型,因为我们的对象是可迭代的,我们也可以使用for循环来遍历该对象。

6.__setitem__用法

现在我们已经实现了模型集合的取用,但是管理起来好像还是不够全面。如果我们的某个人物在某个版本取消了我们应该如何管理了,这时候我们就需要第__setitem__ 方法了

def __setitem__(self, position, value): 
	self.characters[position] = value

初窥门径——通过游戏人物建模来窥探python的数据模型
这样管理起来就更方便一些

四、魔术方法

魔术方法(magic method)是特殊方法的昵称。在python中,我们可以通过魔术方法做很多事情。我们上面用到的__setitem__等都是魔术方法。为了显示它的便捷性,我们可以用它做更多事情。

1. repr 方法

如果我们的的模型集合写成了工具类,同组的其他开发者也可能用到该模块。这时候他想打印看一下。
初窥门径——通过游戏人物建模来窥探python的数据模型
这样的交互就很不友好了。我们如何使这个模型类看起来更饱满一些呢?

其实也比较简单。

  def __repr__(self):
        return "这是Character_Collect(一个游戏人物模型的集合类)中的__repr__方法"

初窥门径——通过游戏人物建模来窥探python的数据模型
这个时候我们就可以打印出的的相关必要信息了

2.str 方法

除了__repr__ 方法外 str 方法同样也是十分常用的。

 def __str__(self):
        return "这是Character_Collect(一个游戏人物模型的集合类)中的__str__方法"

初窥门径——通过游戏人物建模来窥探python的数据模型
这时候就出现了一个问题,这个时候为什么打印的不再是__repr__ 返回的内容了呢,其实print函数输出的默认会从__str__函数返回的结果里去寻找,只有找不到该函数时才会从__repr__里寻找。

3.str 方法和 repr 方法的区别

其实__str__ 方法和__repr__方法对应的是str函数和repr函数,这两个函数在使用的时候没有太大的区别。但是既然名字称呼不同使用起来的区别还是有的。

区别一:
在没有__str__函数时如果使用print方法,或者str方法时。会优先去找repr函数,这样也就是说。如果方法里没有__str__方法,我们通过__repr__函数既可以实现repr()函数的内容,又可以打印__str__的内容。这样来用有利于实现输出的一致性。

区别二:
我们可以来看一下例子
初窥门径——通过游戏人物建模来窥探python的数据模型
当我们反复str的时候输出的始终是一个字符串,这点是正常的。也符合我们的认知。可是如果循环的使用repr则会略有不同,他会不断的在结果的外侧加字符串。

你可能说你这个没用,其实这个是有用的。

五、bool 之谜

你在使用Python的时候有没有过这样的困惑?

if "达达很帅气":
    print("这是对的")

这句话的执行结果是什么呢。
初窥门径——通过游戏人物建模来窥探python的数据模型
我们都知道if后面应该跟的是条件,可是跟了"达达"很帅气这一段字符串,就能走到条件体里呢,
难道真的是我比较帅吗?是也不是!

是是因为事实上我确实比较帅气。

但是却与本次程序的判断无关。判断的却不是我是否真的比较帅,而是任意的非空字符串都会走到条件体内部。
初窥门径——通过游戏人物建模来窥探python的数据模型
其实我们在正常开发过程中,经常会这样用。判断字符串是否非空,可是为何会如此呢。
初窥门径——通过游戏人物建模来窥探python的数据模型
原来这句话的布尔值为True,所以就能走到条件体内。

1.__bool__方法

回到我们上面的模型集合中
我们在类中加一实例方法

  def __bool__(self):
       return True

初窥门径——通过游戏人物建模来窥探python的数据模型
原来只要在对象中实现__bool__方法,这个对象就有了bool属性。那么我们上述中的字符串都实现了bool方法了吗?
并不一定,我们删除bool方法。这个时候为了显示方便,不如写一个新例子。

class verifi_bool:
    def __len__(self):
        return 1

初窥门径——通过游戏人物建模来窥探python的数据模型
这就奇怪了,这个类没有bool方法,为什么bool值还为True呢

2.python中bool的巧妙结合

class verifi_bool:
    def __len__(self):
        return 0

初窥门径——通过游戏人物建模来窥探python的数据模型
原来在使用bool函数时,函数会优先调用对象中的__bool__方法,如果实力中没有bool则会去调用__len__方法。
如果len大于0bool则为True否则为False
初窥门径——通过游戏人物建模来窥探python的数据模型
不得不说这是一个非常优雅的结合,这样对象之间的属性不再孤立,而是有机结合起来。为甚么要这样设计呢,因为Python 最好的品质之一是一致性。就像自然界很多东西一样,都是诙谐统一的。

本文地址:https://blog.csdn.net/weixin_44706915/article/details/110132698