Return 自己在 python
Return self in python
我有一个 class 表示对象。我有一堆方法可以修改这个对象状态,没有明显的 return 或明显没有任何 return。在 C# 中,我会将所有这些方法声明为 void
并且看不到其他方法。但是在 Python 中,我将使用所有方法 return self
来让自己能够像这样写出很棒的单行代码:
classname().method1().method2().method3()
这是 Pythonic,还是在 Python 中可以接受?
这是一个示例,它演示了一个可能是好的技术的场景
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()
在这种情况下,您可以创建一个对象,其中执行操作的顺序严格由函数调用的顺序决定,这可能会使代码更具可读性(但也更长)。
对于通过方法构建状态的 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)
请注意,在许多情况下它不会 return self
;它将return 克隆 当前对象的某个方面进行了更改。这样你就可以创建基于共享基础的 divergent 链; base = instance.method1().method2()
,然后 foo = base.method3()
和 bar = base.method4()
。
在上面的示例中,Query
对象 return 由 Query.join()
或 Query.filter()
调用编辑的不是同一实例,而是具有过滤器的新实例或加入申请。
它使用 Generative
base class 作为基础;所以使用的模式不是 return self
:
def method(self):
clone = self._generate()
clone.foo = 'bar'
return clone
通过使用 a decorator:
进一步简化了 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'
所有 @_generative
-decorated 方法所要做的就是在副本上进行更改,装饰器负责生成副本,将方法绑定到副本而不是原始方法,并且 return代您转给来电者。
这是一封来自 Guido van Rossum(Python 编程语言的作者)关于这个主题的邮件:https://mail.python.org/pipermail/python-dev/2003-October/038855.html
I'd like to explain once more why I'm so adamant that sort() shouldn't
return 'self'.
This comes from a coding style (popular in various other languages, I
believe especially Lisp revels in it) where a series of side effects
on a single object can be chained like this:
x.compress().chop(y).sort(z)
which would be the same as
x.compress()
x.chop(y)
x.sort(z)
I find the chaining form a threat to readability; it requires that the
reader must be intimately familiar with each of the methods. The
second form makes it clear that each of these calls acts on the same
object, and so even if you don't know the class and its methods very
well, you can understand that the second and third call are applied to
x (and that all calls are made for their side-effects), and not to
something else.
I'd like to reserve chaining for operations that return new values,
like string processing operations:
y = x.rstrip("\n").split(":").lower()
There are a few standard library modules that encourage chaining of
side-effect calls (pstat comes to mind). There shouldn't be any new
ones; pstat slipped through my filter when it was weak.
如果您愿意,可以在此处使用装饰器。对于查看您的代码以查看界面的人来说,它会脱颖而出,并且您不必从每个函数中显式 return self
(如果您有多个退出点,这可能会很烦人)。
import functools
def fluent(func):
@functools.wraps(func)
def wrapped(*args, **kwargs):
# Assume it's a method.
self = args[0]
func(*args, **kwargs)
return self
return wrapped
class Foo(object):
@fluent
def bar(self):
print("bar")
@fluent
def baz(self, value):
print("baz: {}".format(value))
foo = Foo()
foo.bar().baz(10)
打印:
bar
baz: 10
我有一个 class 表示对象。我有一堆方法可以修改这个对象状态,没有明显的 return 或明显没有任何 return。在 C# 中,我会将所有这些方法声明为 void
并且看不到其他方法。但是在 Python 中,我将使用所有方法 return self
来让自己能够像这样写出很棒的单行代码:
classname().method1().method2().method3()
这是 Pythonic,还是在 Python 中可以接受?
这是一个示例,它演示了一个可能是好的技术的场景
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()
在这种情况下,您可以创建一个对象,其中执行操作的顺序严格由函数调用的顺序决定,这可能会使代码更具可读性(但也更长)。
对于通过方法构建状态的 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)
请注意,在许多情况下它不会 return self
;它将return 克隆 当前对象的某个方面进行了更改。这样你就可以创建基于共享基础的 divergent 链; base = instance.method1().method2()
,然后 foo = base.method3()
和 bar = base.method4()
。
在上面的示例中,Query
对象 return 由 Query.join()
或 Query.filter()
调用编辑的不是同一实例,而是具有过滤器的新实例或加入申请。
它使用 Generative
base class 作为基础;所以使用的模式不是 return self
:
def method(self):
clone = self._generate()
clone.foo = 'bar'
return clone
通过使用 a decorator:
进一步简化了 SQLAlchemydef _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'
所有 @_generative
-decorated 方法所要做的就是在副本上进行更改,装饰器负责生成副本,将方法绑定到副本而不是原始方法,并且 return代您转给来电者。
这是一封来自 Guido van Rossum(Python 编程语言的作者)关于这个主题的邮件:https://mail.python.org/pipermail/python-dev/2003-October/038855.html
I'd like to explain once more why I'm so adamant that sort() shouldn't return 'self'.
This comes from a coding style (popular in various other languages, I believe especially Lisp revels in it) where a series of side effects on a single object can be chained like this:
x.compress().chop(y).sort(z)
which would be the same as
x.compress()
x.chop(y)
x.sort(z)
I find the chaining form a threat to readability; it requires that the reader must be intimately familiar with each of the methods. The second form makes it clear that each of these calls acts on the same object, and so even if you don't know the class and its methods very well, you can understand that the second and third call are applied to x (and that all calls are made for their side-effects), and not to something else.
I'd like to reserve chaining for operations that return new values, like string processing operations:
y = x.rstrip("\n").split(":").lower()
There are a few standard library modules that encourage chaining of side-effect calls (pstat comes to mind). There shouldn't be any new ones; pstat slipped through my filter when it was weak.
如果您愿意,可以在此处使用装饰器。对于查看您的代码以查看界面的人来说,它会脱颖而出,并且您不必从每个函数中显式 return self
(如果您有多个退出点,这可能会很烦人)。
import functools
def fluent(func):
@functools.wraps(func)
def wrapped(*args, **kwargs):
# Assume it's a method.
self = args[0]
func(*args, **kwargs)
return self
return wrapped
class Foo(object):
@fluent
def bar(self):
print("bar")
@fluent
def baz(self, value):
print("baz: {}".format(value))
foo = Foo()
foo.bar().baz(10)
打印:
bar
baz: 10