写点什么

翻译:《实用的 Python 编程》04_03_Special_methods

用户头像
codists
关注
发布于: 2021 年 03 月 09 日
翻译:《实用的Python编程》04_03_Special_methods

目录 | [上一节 (4.2 继承)]| [下一节 (4.4 异常)]


4.3 特殊方法


可以通过特殊方法(或者称为"魔术"方法(magic method))自定义 Python 行为的各部分。本节介绍特殊方法的思想。此外,还将讨论动态属性访问和绑定方法。


简介


类可以定义特殊方法。特殊方法对于 Python 解释器而言具有特殊的意义。特殊方法总是以双下划线 __ 开头和结尾,例如 __init__


class Stock(object):    def __init__(self):        ...    def __repr__(self):        ...
复制代码


虽然有很多特殊方法,但是我们只研究几个具体的例子。


字符串转换的特殊方法


对象有两种字符串表示形式。


>>> from datetime import date>>> d = date(2012, 12, 21)>>> print(d)2012-12-21>>> ddatetime.date(2012, 12, 21)>>>
复制代码


str() 函数用于创建格式良好的、可打印的输出:


>>> str(d)'2012-12-21'>>>
复制代码


repr() 函数用于创建详细的、面向程序员的输出。


>>> repr(d)'datetime.date(2012, 12, 21)'>>>
复制代码


str()repr() 函数都是使用类中定义的特殊方法生成要显示的字符串。


class Date(object):    def __init__(self, year, month, day):        self.year = year        self.month = month        self.day = day
# Used with `str()` def __str__(self): return f'{self.year}-{self.month}-{self.day}'
# Used with `repr()` def __repr__(self): return f'Date({self.year},{self.month},{self.day})'
复制代码


*注意:按照惯例,__repr__() 返回一个字符串,当该字符串被传递给 eval() 函数,将会重新创建底层对象(译注:eval(repr(obj)) == obj)。如果不行,则使用某种易于阅读的表现形式。*


数学操作的特殊方法


数学运算符涉及的特殊方法如下:


a + b       a.__add__(b)a - b       a.__sub__(b)a * b       a.__mul__(b)a / b       a.__truediv__(b)a // b      a.__floordiv__(b)a % b       a.__mod__(b)a << b      a.__lshift__(b)a >> b      a.__rshift__(b)a & b       a.__and__(b)a | b       a.__or__(b)a ^ b       a.__xor__(b)a ** b      a.__pow__(b)-a          a.__neg__()~a          a.__invert__()abs(a)      a.__abs__()
复制代码


元素访问的特殊方法


这些是实现容器的特殊方法:


len(x)      x.__len__()x[a]        x.__getitem__(a)x[a] = v    x.__setitem__(a,v)del x[a]    x.__delitem__(a)
复制代码


你可以在类中使用这些特殊方法。


class Sequence:    def __len__(self):        ...    def __getitem__(self,a):        ...    def __setitem__(self,a,v):        ...    def __delitem__(self,a):        ...
复制代码


方法调用


调用方法有两个步骤。


​ 1、查找:. 运算符


​ 2、方法调用: () 运算符


>>> s = Stock('GOOG',100,490.10)>>> c = s.cost  # Lookup>>> c<bound method Stock.cost of <Stock object at 0x590d0>>>>> c()         # Method call49010.0>>>
复制代码


绑定方法


尚未被函数调用运算符 () 调用的方法称为绑定方法( 译注:bound method,如果直译应该译作“绑定的方法”,但是,就像“类方法”一样,可以省略“的”这个字,译为“绑定方法”,绑定在这里不是动词,而应理解为形容词“绑定的”)。它对自己生成的实例进行操作:


>>> s = Stock('GOOG', 100, 490.10)>>> s<Stock object at 0x590d0>>>> c = s.cost>>> c<bound method Stock.cost of <Stock object at 0x590d0>>>>> c()49010.0>>>
复制代码


如果使用绑定方法时有些大意,那么容易导致错误。示例:


>>> s = Stock('GOOG', 100, 490.10)>>> print('Cost : %0.2f' % s.cost)Traceback (most recent call last):  File "<stdin>", line 1, in <module>TypeError: float argument required>>>
复制代码


或者:


f = open(filename, 'w')...f.close     # Oops, Didn't do anything at all. `f` still open.
复制代码


在这两种情形中,错误都是由忘记尾部括号引起的。例如:s.cost() or f.close()


属性访问


还有一种访问、操作和管理属性的替代方法。


getattr(obj, 'name')          # Same as obj.namesetattr(obj, 'name', value)   # Same as obj.name = valuedelattr(obj, 'name')          # Same as del obj.namehasattr(obj, 'name')          # Tests if attribute exists
复制代码


示例:


if hasattr(obj, 'x'):    x = getattr(obj, 'x'):else:    x = None
复制代码


*注意: getattr() 函数的默认参数非常有用。*


x = getattr(obj, 'x', None)
复制代码


练习


练习 4.9:更好的输出


请修改 stock.py 文件中定义的 Stock 对象,以便 repr() 方法生成更有用的输出。示例:


>>> goog = Stock('GOOG', 100, 490.1)>>> googStock('GOOG', 100, 490.1)>>>
复制代码


修改完成后,请查看读取股票投资组合时会发生什么,以及生成什么样的结果。示例:


>>> import report>>> portfolio = report.read_portfolio('Data/portfolio.csv')>>> portfolio... see what the output is ...>>>
复制代码


练习 4.10:使用 getattr() 的例子


getattr() 是读取属性的另一种机制。可以使用它编写极其灵活的代码。首先,请尝试以下示例:


>>> import stock>>> s = stock.Stock('GOOG', 100, 490.1)>>> columns = ['name', 'shares']>>> for colname in columns:        print(colname, '=', getattr(s, colname))
name = GOOGshares = 100>>>
复制代码


仔细观察会发现输出数据完全由 columns 变量中列出的属性名决定。


tableformat.py 文件中,使用该思想将其扩展为通用函数 print_table()print_table()打印一个表格,显示用户指定的任意对象的属性。与早期的 print_report() 函数一样,print_table() 方法还应接受一个 TableFormatter 实例来控制输出格式。它们的工作方式如下:


>>> import report>>> portfolio = report.read_portfolio('Data/portfolio.csv')>>> from tableformat import create_formatter, print_table>>> formatter = create_formatter('txt')>>> print_table(portfolio, ['name','shares'], formatter)      name     shares---------- ----------        AA        100       IBM         50       CAT        150      MSFT        200        GE         95      MSFT         50       IBM        100
>>> print_table(portfolio, ['name','shares','price'], formatter) name shares price---------- ---------- ---------- AA 100 32.2 IBM 50 91.1 CAT 150 83.44 MSFT 200 51.23 GE 95 40.37 MSFT 50 65.1 IBM 100 70.44>>>
复制代码


目录 | [上一节 (4.2 继承)]| [下一节 (4.4 异常)]


注:完整翻译见 https://github.com/codists/practical-python-zh


发布于: 2021 年 03 月 09 日阅读数: 13
用户头像

codists

关注

公众号:编程人 2021.01.14 加入

Life is short, You need Python

评论

发布
暂无评论
翻译:《实用的Python编程》04_03_Special_methods