Phi*_*p B 26 python method-chaining
我有一个代表对象的类.我有一堆方法可以修改这个对象状态,没有明显的返回或显然没有任何返回.在C#中,我会将所有这些方法声明为void并且看不到其他选择.但是在Python中,我将要制作所有方法return self,让自己能够编写如下所示的真棒单行:
classname().method1().method2().method3()
Run Code Online (Sandbox Code Playgroud)
这是Pythonic,还是Python中可以接受的?
Que*_*ker 27
以下是来自Guido van Rossum(Python编程语言的作者)的关于此主题的邮件:https://mail.python.org/pipermail/python-dev/2003-October/038855.html
我想再次解释为什么我坚持认为sort()不应该返回'self'.
这来自于一种编码风格(在其他各种语言中很流行,我相信Lisp特别喜欢它),其中对单个对象的一系列副作用可以链接如下:
x.compress().斩(Y)的.sort(z)的
这将是相同的
x.compress()x.chop(y)x.sort(z)
我发现链接形式对可读性构成威胁; 它要求读者必须非常熟悉每种方法.第二种形式清楚地表明这些调用中的每一个都作用于同一个对象,因此即使您不熟悉该类及其方法,您也可以理解第二个和第三个调用应用于x(并且所有的电话都是为了他们的副作用而做的,而不是其他的.
我想为返回新值的操作保留链接,比如字符串处理操作:
y = x.rstrip("\n").split(":").lower()
有一些标准库模块鼓励链接副作用调用(pstat浮现在脑海中).不应该有任何新的; 当它很弱时,pstat穿过我的过滤器.
Mar*_*ers 14
对于通过方法构建状态的API,这是一个很好的主意.SQLAlchemy使用它可以产生很好的效果,例如:
>>> from sqlalchemy.orm import aliased
>>> adalias1 = aliased(Address)
>>> adalias2 = aliased(Address)
>>> for username, email1, email2 in \
... session.query(User.name, adalias1.email_address, adalias2.email_address).\
... join(adalias1, User.addresses).\
... join(adalias2, User.addresses).\
... filter(adalias1.email_address=='jack@google.com').\
... filter(adalias2.email_address=='j25@yahoo.com'):
... print(username, email1, email2)
Run Code Online (Sandbox Code Playgroud)
请注意,self在许多情况下它不会返回; 它将返回当前对象的克隆,并更改某个方面.这样,您就可以基于共享库创建不同的链; base = instance.method1().method2(),然后foo = base.method3()和bar = base.method4().
在上面的示例中,或者调用Query返回的对象不是同一个实例,而是应用了过滤器或连接的新实例.Query.join()Query.filter()
它使用Generative基类来构建; 所以return self使用的模式不是:
def method(self):
clone = self._generate()
clone.foo = 'bar'
return clone
Run Code Online (Sandbox Code Playgroud)
哪个SQLAlchemy使用装饰器进一步简化:
def _generative(func):
@wraps(func)
def decorator(self, *args, **kw):
new_self = self._generate()
func(new_self, *args, **kw)
return new_self
return decorator
class FooBar(GenerativeBase):
@_generative
def method(self):
self.foo = 'bar'
Run Code Online (Sandbox Code Playgroud)
所有 - @_generative解决方法所要做的就是对副本进行更改,装饰器负责生成副本,将方法绑定到副本而不是原始副本,并将其返回给调用者.
Ban*_*ski 12
这是一个(愚蠢的)示例,演示了一个好的技术
class A:
def __init__(self, x):
self.x = x
def add(self, y):
self.x += y
return self
def multiply(self, y)
self.x *= y
return self
def get(self):
return self.x
a = A(0)
print a.add(5).mulitply(2).get()
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您可以创建一个对象,其中执行操作的顺序严格按函数调用的顺序确定,这可能使代码更具可读性(但也更长)
| 归档时间: |
|
| 查看次数: |
9831 次 |
| 最近记录: |