如何链接功能?

How to chain functions?

我正在尝试了解链式函数的机制,例如

>>> 'hello'.upper()
'HELLO'

(链条可以更长,我现在脑子里没有很好的例子 - 比如 'hello'.upper().reverse().take_every_second_character().rot13()

这个功能是如何实现的?每个函数必须返回什么(并被下一个函数拦截(=用作参数?)),考虑到一个人可以在某处打破链条并仍然获得输出?以上面虚构的例子为例:

>>> 'hello'
'hello'

>>> 'hello'.upper()
'HELLO'

>>> 'hello'.upper().reverse()
'OLLEH'

等等

'hello' 是一个 str 对象。

str class 具有 return 字符串转换的方法(如 upper()reverse() 等)。

您可以扩展 str class 来创建您自己的方法。

>>> import inspect
>>> from pprint import pprint
>>> 
>>> str
<class 'str'>
>>> pprint(inspect.getmembers(str))
[('__add__', <slot wrapper '__add__' of 'str' objects>),
 ('__class__', <class 'type'>),
 ('__contains__', <slot wrapper '__contains__' of 'str' objects>),
 ('__delattr__', <slot wrapper '__delattr__' of 'object' objects>),
 ('__dir__', <method '__dir__' of 'object' objects>),
 ('__doc__',
  "str(object='') -> str\n"
  'str(bytes_or_buffer[, encoding[, errors]]) -> str\n'
  '\n'
  'Create a new string object from the given object. If encoding or\n'
  'errors is specified, then the object must expose a data buffer\n'
  'that will be decoded using the given encoding and error handler.\n'
  'Otherwise, returns the result of object.__str__() (if defined)\n'
  'or repr(object).\n'
  'encoding defaults to sys.getdefaultencoding().\n'
  "errors defaults to 'strict'."),
 ('__eq__', <slot wrapper '__eq__' of 'str' objects>),
 ('__format__', <method '__format__' of 'str' objects>),
 ('__ge__', <slot wrapper '__ge__' of 'str' objects>),
 ('__getattribute__', <slot wrapper '__getattribute__' of 'str' objects>),
 ('__getitem__', <slot wrapper '__getitem__' of 'str' objects>),
 ('__getnewargs__', <method '__getnewargs__' of 'str' objects>),
 ('__gt__', <slot wrapper '__gt__' of 'str' objects>),
 ('__hash__', <slot wrapper '__hash__' of 'str' objects>),
 ('__init__', <slot wrapper '__init__' of 'object' objects>),
 ('__init_subclass__',
  <built-in method __init_subclass__ of type object at 0x7f9d596539c0>),
 ('__iter__', <slot wrapper '__iter__' of 'str' objects>),
 ('__le__', <slot wrapper '__le__' of 'str' objects>),
 ('__len__', <slot wrapper '__len__' of 'str' objects>),
 ('__lt__', <slot wrapper '__lt__' of 'str' objects>),
 ('__mod__', <slot wrapper '__mod__' of 'str' objects>),
 ('__mul__', <slot wrapper '__mul__' of 'str' objects>),
 ('__ne__', <slot wrapper '__ne__' of 'str' objects>),
 ('__new__', <built-in method __new__ of type object at 0x7f9d596539c0>),
 ('__reduce__', <method '__reduce__' of 'object' objects>),
 ('__reduce_ex__', <method '__reduce_ex__' of 'object' objects>),
 ('__repr__', <slot wrapper '__repr__' of 'str' objects>),
 ('__rmod__', <slot wrapper '__rmod__' of 'str' objects>),
 ('__rmul__', <slot wrapper '__rmul__' of 'str' objects>),
 ('__setattr__', <slot wrapper '__setattr__' of 'object' objects>),
 ('__sizeof__', <method '__sizeof__' of 'str' objects>),
 ('__str__', <slot wrapper '__str__' of 'str' objects>),
 ('__subclasshook__',
  <built-in method __subclasshook__ of type object at 0x7f9d596539c0>),
 ('capitalize', <method 'capitalize' of 'str' objects>),
 ('casefold', <method 'casefold' of 'str' objects>),
 ('center', <method 'center' of 'str' objects>),
 ('count', <method 'count' of 'str' objects>),
 ('encode', <method 'encode' of 'str' objects>),
 ('endswith', <method 'endswith' of 'str' objects>),
 ('expandtabs', <method 'expandtabs' of 'str' objects>),
 ('find', <method 'find' of 'str' objects>),
 ('format', <method 'format' of 'str' objects>),
 ('format_map', <method 'format_map' of 'str' objects>),
 ('index', <method 'index' of 'str' objects>),
 ('isalnum', <method 'isalnum' of 'str' objects>),
 ('isalpha', <method 'isalpha' of 'str' objects>),
 ('isascii', <method 'isascii' of 'str' objects>),
 ('isdecimal', <method 'isdecimal' of 'str' objects>),
 ('isdigit', <method 'isdigit' of 'str' objects>),
 ('isidentifier', <method 'isidentifier' of 'str' objects>),
 ('islower', <method 'islower' of 'str' objects>),
 ('isnumeric', <method 'isnumeric' of 'str' objects>),
 ('isprintable', <method 'isprintable' of 'str' objects>),
 ('isspace', <method 'isspace' of 'str' objects>),
 ('istitle', <method 'istitle' of 'str' objects>),
 ('isupper', <method 'isupper' of 'str' objects>),
 ('join', <method 'join' of 'str' objects>),
 ('ljust', <method 'ljust' of 'str' objects>),
 ('lower', <method 'lower' of 'str' objects>),
 ('lstrip', <method 'lstrip' of 'str' objects>),
 ('maketrans', <built-in method maketrans of type object at 0x7f9d596539c0>),
 ('partition', <method 'partition' of 'str' objects>),
 ('replace', <method 'replace' of 'str' objects>),
 ('rfind', <method 'rfind' of 'str' objects>),
 ('rindex', <method 'rindex' of 'str' objects>),
 ('rjust', <method 'rjust' of 'str' objects>),
 ('rpartition', <method 'rpartition' of 'str' objects>),
 ('rsplit', <method 'rsplit' of 'str' objects>),
 ('rstrip', <method 'rstrip' of 'str' objects>),
 ('split', <method 'split' of 'str' objects>),
 ('splitlines', <method 'splitlines' of 'str' objects>),
 ('startswith', <method 'startswith' of 'str' objects>),
 ('strip', <method 'strip' of 'str' objects>),
 ('swapcase', <method 'swapcase' of 'str' objects>),
 ('title', <method 'title' of 'str' objects>),
 ('translate', <method 'translate' of 'str' objects>),
 ('upper', <method 'upper' of 'str' objects>),
 ('zfill', <method 'zfill' of 'str' objects>)]

假设这些函数都存在并且 return 适当的类型。

res = 'hello'
res.upper().reverse().take_every_second_character().rot13()

相当于说:

res = 'hello'
((((res.upper()).reverse()).take_every_second_character()).rot13())

res = 'hello'.upper()
res = res.reverse()
res = res.take_every_second_character()
res.rot13()

你不能"break the chain"(如果失败,意味着一个错误,那么除非你捕获它,否则将抛出一个错误)。