Python语言高级特性:创建Python对象的方法 #P008#

在这篇文章中,将大开脑洞,讨论不同的Python对象“创建”的方法。通过比较不同的实现方法,将会揭露很多被大家忽略的Python语言高级知识。准确来说,本篇文章创建对象的方法并不是真正的“创建”,而是通过不同的方式获取到类对象,然后进行调用创建对象。但是,本篇文章的讨论对于绝大多数读者来说依然非常有意义,可以接触到很多比较隐蔽的Python知识。

1 问题

在这篇文章中,我们会用到下面这个名为Point的类,这是一个最简单也最常见的类。

class Point(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    @classmethod
    def new_object(cls, x, y):
        return cls(x, y)

现在有一个问题,对于这个类定义,你能想到多少种创建对象的方法?

读者先不要看答案,在脑海里面想一下,看看自己能够想到多少种创建对象的方法。

笔者可以明确的告诉大家,有10种不同的方法。很多时候并不是因为我漏掉了什么重要的知识,而是因为我们思维定式,没办法打开脑洞。

2 答案

为了便于读者测试与学习,这里直接给出可以运行的代码,以便大家进行测试和验证。

from __future__ import print_function
import sys
import copy

class Point(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    @classmethod
    def new_object(cls, x, y):
        return cls(x, y)

    def __str__(self):
        return "{0}({1}, {2})".format(self.__class__.__name__, self.x, self.y)


def make_object(Class, *args, **kwargs):
    return Class(*args, **kwargs)


def main():
    point1 = Point(1, 2)
    point2 = eval("{}({}, {})".format("Point", 2, 4))
    point3 = getattr(sys.modules[__name__], "Point")(3, 6)
    point4 = globals()["Point"](4, 8)
    point5 = make_object(Point, 5, 10)
    point6 = copy.deepcopy(point5)
    point6.x = 6
    point6.y = 12
    point7 = point1.__class__(7, 14)
    point8 = Point.new_object(8, 16)
    point9 = type(point1)(9, 18)
    point10 = Point.new_object.__self__(10, 20)

    for i in range(1, 11):
        name = "point{0}".format(i)
        print(locals()[name])


if __name__ == '__main__':
    main()

运行上面的代码:

~$ python create_python_object.py 
Point(1, 2)
Point(2, 4)
Point(3, 6)
Point(4, 8)
Point(5, 10)
Point(6, 12)
Point(7, 14)
Point(8, 16)
Point(9, 18)
Point(10, 20)

3 解释说明

下面是对创建对象的10种方法的解释说明:

  • point1是按照传统的方式创建的,也是大家最常用的方式。这种方式也称之为静态方式,其他方式称之为动态方式。
  • 在创建point2、point3与point4时,我们把类名当做是普通的参数传递给相应的函数。point2调用了存在安全隐患的eval函数。在生产环境的程序中,千万不要使用这个函数。
  • point3与point4原理是一样的。在point3中,先通过sys.modules[__name__]获取当前模块的所有属性。在point4的创建中,直接使用globals函数获取当前模块中的属性。获取模块的所有属性以后,可以直接通过类的名称获取到Point这个类对象。获取到类对象以后,执行类调用,就创建了一个对象。
  • point5通过调用make_object函数创建对象。在这个例子中,我们将类作为一个普通的参数,传递给make_object函数。
  • 在创建point6时,我们通过copy.deepcopy函数复制了一个已经存在的对象,并通过修改对象属性的方式获得了一个新的对象。
  • point7涉及到的知识点是,我们可以通过object.__class__获取到对象的类。获取到类以后,再执行类调用,就又创建了一个新的对象。
  • point8也是比较容易想到的方式,point8是通过Python的类方法调用来创建一个对象。在类方法调用中,Python会自动将类传递给方法的第一个参数。
  • point9使用了Python内置的type函数,该函数并不是通过一个字符串返回变量的类型,而是返回一个“类对象”,类对象可以直接进行调用。
  • point10涉及到的知识点是,可以通过classmethod的__self__获取到classmethod的类,获取到类以后,再执行类调用,就又创建了一个新的对象。

4 结束语

在我们编写程序时,总是应该使用最简单的方式来创建类(第一种方法)。但是,这里讨论的创建对象的方法也不是没有用处。这里的这个例子,涉及到了模块、对象拷贝、globals函数、类方法、__class__属性等知识点。对于这段程序,如果大家想不到这么多创建对象的方法,完全不是问题。但是,如果大家不看解释说明,不能够看懂所有创建对象的方式,则说明对Python掌握还有遗漏。从这个角度来说,讨论创建Python对象的不同方法还是非常意义的,可以对Python知识进行查漏补缺。

作者介绍

赖明星,架构师、作家。现就职于腾讯,参与并主导下一代金融级数据库平台研发。有多年的 Python 开发经验和一线互联网实战经验,擅长 C、Python、Java、MySQL、Linux 等主流技术。国内知名的 Python 技术专家和 Python 技术的积极推广者,著有《Python Linux 系统管理与自动化运维》一书。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值