Python3入门到精通——一切皆对象与魔法函数

作者: Daniel Meng

GitHub: LibertyDream

博客:明月轩

本系列教程采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议

Java 有类(class)和对象(object)的分别,函数、方法更是独一档。但在 Python 中,对不起,即使是包、模块,它们都是对象,Python 比 Java 在对象化上更彻底,这是其一。

其二,既然都是对象,那么函数、类就可以当作对象使用,主要有四点:

  1. 能赋值给变量
In [1]:
def obj_func(name):
    print('call me %s' % name)

var_obj = obj_func
var_obj('Daniel Meng')
call me Daniel Meng
In [2]:
class Obj_Class(object):

    def __init__(self, name):
        print('I am %s' % name)

class_var_obj = Obj_Class
class_var_obj('Daniel Meng')
I am Daniel Meng
Out[2]:
<__main__.Obj_Class at 0x1967c314550>
  1. 可以添加到集合对象中
In [3]:
obj_lst = ['a', class_var_obj, var_obj]
obj_lst
Out[3]:
['a', __main__.Obj_Class, <function __main__.obj_func(name)>]
  1. 可以当作参数传给函数
In [4]:
def another_call_me(some_func, name):
    some_func(name)

another_call_me(obj_func, 'Daniel Meng')
call me Daniel Meng
  1. 可以作为函数返回值
In [5]:
def out_func(name):
    local_name = name
    def inner_func():
        print("Don't call me %s" % local_name)
    return inner_func

var_obj = out_func('Daniel Meng')
var_obj()
Don't call me Daniel Meng

type、object 和 class 的关系

type生成class,包括基础的str,list以及我们创建的类,所有类都有基类,顶级基类object是例外,其基类为空,type继承自objectobjecttype的一个实例,type作为一个对象,是自己创建了自己(指向自身的指针)

In [6]:
str_obj = 'abc'
type(str_obj)
Out[6]:
str
In [7]:
type(str)
Out[7]:
type
In [8]:
class MyClass:
    pass

class_obj = MyClass()
type(class_obj)
Out[8]:
__main__.MyClass
In [9]:
type(MyClass)
Out[9]:
type
In [10]:
type(type) # 指向自己的指针,自己创建自己
Out[10]:
type
In [11]:
print('str 父类:%s' % str.__base__)
print('MyClass 父类:%s' % MyClass.__base__)
print('type 父类:%s' % type.__base__)
str 父类:<class 'object'>
MyClass 父类:<class 'object'>
type 父类:<class 'object'>

回头看常见内置类型

Python 中一切皆对象,这里回顾一下对象的三个基本特征——类型(type),身份(id)和值

In [12]:
name = 'Daniel Meng' # 赋值
In [13]:
type(name) # 类型是字符串
Out[13]:
str
In [14]:
id(name) # 指向内存位置的编号
Out[14]:
1745840344304

从对象角度,会发现 Python 中的内置类型比已知和想象中的要丰富的多。

  • None(全局唯一)
  • 数值类型
    • int
    • float
    • complex
    • bool
  • 迭代类型
  • 序列类型(可迭代)
    • list
    • array
    • range
    • tuple
    • str
    • bytes,memoryview
  • 映射(dict)
  • 集合
    • set
    • frozenset
  • 上下文管理类型(with)
  • 其他
    • 模块
    • class 和实例
    • 函数
    • 方法
    • 代码(没错,代码也会变成对象>_<)
    • object
    • type
    • ellipsis
    • notimplemented

魔法函数

Python 中的魔法函数格式为__FunctionName__,前后双下滑线,中间函数名。魔法函数是 Python 内部定义好的,用于增强函数、类的功能且独立于二者

In [15]:
class Class(object):

    def __init__(self, student_lst):  # 魔法函数,初始化对象
        self.student_lst = student_lst

    def __getitem__(self,item):  # 魔法函数,尝试一次访问 0,1,2…… 号成员
        return self.student_lst[item]
In [16]:
demo_class = Class(['Tom','Jerry','Mark'])

for stu in demo_class:
    print(stu)
Tom
Jerry
Mark

正是通过各种各样的魔法函数以及魔法函数的组合、嵌套,Python 才能灵活构建出行为表现各异的数据模型。相应的,如果想要对象具有某种特性,比如可迭代,可获取长度,都要事先实现某些魔法函数才行

Python 中的魔法函数大体归类如下

  • 数学运算型
    • 一元运算
    • 二元运算
    • 算术运算
    • 反向运算
    • 增量赋值运算
    • 位运算
    • 反向位运算
    • 增量位运算
  • 非数学运算型
    • 字符串表示
    • 集合、序列相关
    • 迭代相关
    • 可调用
    • with 上下文管理器
    • 数值转换
    • 元类相关
    • 属性相关
    • 属性描述符
    • 协程

具体内容涉及到相关章节时会细谈,下面列出了部分重要的魔法函数及相关说明

Initialization and Construction Description
__new__(cls, other) To get called in an object's instantiation.
__init__(self, other) To get called by the __new__ method.
__del__(self) Destructor method.
Unary operators and functions Description
__pos__(self) To get called for unary positive e.g. +someobject.
__neg__(self) To get called for unary negative e.g. -someobject.
__abs__(self) To get called by built-in abs() function.
__invert__(self) To get called for inversion using the ~ operator.
__round__(self,n) To get called by built-in round() function.
__floor__(self) To get called by built-in math.floor() function.
__ceil__(self) To get called by built-in math.ceil() function.
__trunc__(self) To get called by built-in math.trunc() function.
Augmented Assignment Description
__iadd__(self, other) To get called on addition with assignment e.g. a +=b.
__isub__(self, other) To get called on subtraction with assignment e.g. a -=b.
__imul__(self, other) To get called on multiplication with assignment e.g. a *=b.
__ifloordiv__(self, other) To get called on integer division with assignment e.g. a //=b.
__idiv__(self, other) To get called on division with assignment e.g. a /=b.
__itruediv__(self, other) To get called on true division with assignment
__imod__(self, other) To get called on modulo with assignment e.g. a%=b.
__ipow__(self, other) To get called on exponentswith assignment e.g. a **=b.
__ilshift__(self, other) To get called on left bitwise shift with assignment e.g. a<<=b.
__irshift__(self, other) To get called on right bitwise shift with assignment e.g. a >>=b.
__iand__(self, other) To get called on bitwise AND with assignment e.g. a&=b.
__ior__(self, other) To get called on bitwise OR with assignment e.g. a|=b.
__ixor__(self, other) To get called on bitwise XOR with assignment e.g. a ^=b.
Type Conversion Magic Methods Description
__int__(self) To get called by built-int int() method to convert a type to an int.
__float__(self) To get called by built-int float() method to convert a type to float.
__complex__(self) To get called by built-int complex() method to convert a type to complex.
__oct__(self) To get called by built-int oct() method to convert a type to octal.
__hex__(self) To get called by built-int hex() method to convert a type to hexadecimal.
__index__(self) To get called on type conversion to an int when the object is used in a slice expression.
__trunc__(self) To get called from math.trunc() method.
String Magic Methods Description
__str__(self) To get called by built-int str() method to return a string representation of a type.
__repr__(self) To get called by built-int repr() method to return a machine readable representation of a type.
__unicode__(self) To get called by built-int unicode() method to return an unicode string of a type.
__format__(self, formatstr) To get called by built-int string.format() method to return a new style of string.
__hash__(self) To get called by built-int hash() method to return an integer.
__nonzero__(self) To get called by built-int bool() method to return True or False.
__dir__(self) To get called by built-int dir() method to return a list of attributes of a class.
__sizeof__(self) To get called by built-int sys.getsizeof() method to return the size of an object.
Attribute Magic Methods Description
__getattr__(self, name) Is called when the accessing attribute of a class that does not exist.
__setattr__(self, name, value) Is called when assigning a value to the attribute of a class.
__delattr__(self, name) Is called when deleting an attribute of a class.
Operator Magic Methods Description
__add__(self, other) To get called on add operation using + operator
__sub__(self, other) To get called on subtraction operation using - operator.
__mul__(self, other) To get called on multiplication operation using * operator.
__floordiv__(self, other) To get called on floor division operation using // operator.
__div__(self, other) To get called on division operation using / operator.
__mod__(self, other) To get called on modulo operation using % operator.
__pow__(self, other[, modulo]) To get called on calculating the power using ** operator.
__lt__(self, other) To get called on comparison using < operator.
__le__(self, other) To get called on comparison using <= operator.
__eq__(self, other) To get called on comparison using == operator.
__ne__(self, other) To get called on comparison using != operator.
__ge__(self, other) To get called on comparison using >= operator.

理解魔法函数,对于写出高性能 Python 程序有巨大帮助。比如说对字符串的两个魔法函数__str____repr__。前者是对象字符串格式化时调用的,后者是开发环境下调用的

In [17]:
class StrClass(object):
    def __init__(self, strings):
        self.str = strings

    def __str__(self):
        return ','.join(self.str)

    def __repr__(self):
        return '_'.join(self.str)

sample_str = StrClass(['am','is','are'])
In [18]:
sample_str  # 调用 obj.__repr__(),一般开发环境下终端上不会有输出结果
Out[18]:
am_is_are
In [19]:
print(sample_str)  # 调用 obj.__str__()
am,is,are

再比如__len__,当我们使用len()方法时,会自动寻找对象下的__len__。但对于原生内置类型 list、set 等,因为是用 C 实现的,运行时 Cpython 解释器会取巧直接访问 C 程序中内部维护的变量值,从而实现高效访问