基本方法链接
Basic method chaining
我找到了这个 method chaining in python,但即使有了它我还是无法理解 Python 中的方法链接。
这里的目标有两个:解决编码问题和理解方法链(考虑到我对可调用对象仍然不是 100% 有信心)。
下到问题定义。
我想要一个有两种方法的 class:一种设置对象的参数 = 'line',另一种覆盖 'bar'.
这是我目前得到的:
class foo():
def __init__(self, kind=None):
self.kind = kind
def __call__(self, kind=None):
return foo(kind=kind)
def my_print(self):
print (self.kind)
def line(self):
return self(kind='line')
def bar(self):
return self(kind='bar')
遗憾的是,使用这段代码我可以实现我的目标
a = foo()
a.bar().line().bar().bar().line().my_print()
但我想通过编写这段代码获得相同的结果
a = foo()
a.bar.line.bar.bar.line.my_print()
我该如何实现?我想我定义 __call__
方法的方式有问题。预先感谢您的帮助。
使用属性(描述符)。
class foo:
def __init__(self, kind=None):
self.kind = kind
def __call__(self, kind=None):
return foo(kind=kind)
def my_print(self):
print (self.kind)
@property
def line(self):
return self(kind='line')
@property
def bar(self):
return self(kind='bar')
但是请注意,您没有覆盖任何内容,修改不会就地生效(顺便说一句,这可以说是好的)。无论如何,对于大多数 real-world 情况,这看起来不是一个好的设计选择,因为在某些时候您的方法将需要参数。
方法链接只是能够将 .second_func()
添加到任何 .first_func()
return 中。通过确保所有可链接的方法 return self
,它很容易实现。 (注意这与__call()__
无关)。
class foo():
def __init__(self, kind=None):
self.kind = kind
def my_print(self):
print (self.kind)
return self
def line(self):
self.kind = 'line'
return self
def bar(self):
self.kind='bar'
return self
您可以通过忽略 returned 值以 non-chained 方式使用 foo
对象:
a = foo()
a.line()
a.my_print()
a.bar()
a.my_print()
assert a.kind == 'bar'
或者,由于现在每个函数 return 都是对象本身,您可以操作
直接在 returned 值上。您可以使用具有以下等效代码的方法链接:
b = foo()
b.line().my_print().bar().my_print()
assert b.kind == 'bar'
甚至:
c = foo().line().my_print().bar().my_print()
assert c.kind == 'bar'
摆脱 ()
调用语法的问题是一个完全独立于方法链的概念。如果您想要链属性,并让这些属性改变它们的对象,请使用 @property
装饰器。 (但是通过 属性 改变对象似乎很危险。最好使用一个方法并用动词命名它:例如 .set_line()
而不是 .line
。)
class foo():
def __init__(self, kind=None):
self.kind = kind
def my_print(self):
print (self.kind)
return self
@property
def line(self):
self.kind = 'line'
return self
@property
def bar(self):
self.kind='bar'
return self
a = foo()
a.line
a.my_print()
a.bar
a.my_print()
assert a.kind == 'bar'
b = foo()
b.line.my_print().bar.my_print()
assert b.kind == 'bar'
c = foo().line.my_print().bar.my_print()
assert c.kind == 'bar'
还有另一种有趣的实现方式
class Foo:
def __init__(self, kind=[]):
self.kind = kind
def __getattr__(self, attrs):
self.attrs = attrs
return Foo(self.kind + [attrs])
def __call__(self):
return self.kind[::-1][0]
my_obj = Foo()
print(my_obj.bar.line.bar.bar.line())
使用此代码你不必传递 .my_print()
但这里要注意的一件事是 Foo class 将把任何东西作为参数,就像我们尝试 print(my_obj.bar.line.bar.bar.circle())
它会return圈子。
您还可以编辑此代码以在调用任何函数时获取参数。
我找到了这个 method chaining in python,但即使有了它我还是无法理解 Python 中的方法链接。
这里的目标有两个:解决编码问题和理解方法链(考虑到我对可调用对象仍然不是 100% 有信心)。
下到问题定义。
我想要一个有两种方法的 class:一种设置对象的参数 = 'line',另一种覆盖 'bar'.
这是我目前得到的:
class foo():
def __init__(self, kind=None):
self.kind = kind
def __call__(self, kind=None):
return foo(kind=kind)
def my_print(self):
print (self.kind)
def line(self):
return self(kind='line')
def bar(self):
return self(kind='bar')
遗憾的是,使用这段代码我可以实现我的目标
a = foo()
a.bar().line().bar().bar().line().my_print()
但我想通过编写这段代码获得相同的结果
a = foo()
a.bar.line.bar.bar.line.my_print()
我该如何实现?我想我定义 __call__
方法的方式有问题。预先感谢您的帮助。
使用属性(描述符)。
class foo:
def __init__(self, kind=None):
self.kind = kind
def __call__(self, kind=None):
return foo(kind=kind)
def my_print(self):
print (self.kind)
@property
def line(self):
return self(kind='line')
@property
def bar(self):
return self(kind='bar')
但是请注意,您没有覆盖任何内容,修改不会就地生效(顺便说一句,这可以说是好的)。无论如何,对于大多数 real-world 情况,这看起来不是一个好的设计选择,因为在某些时候您的方法将需要参数。
方法链接只是能够将 .second_func()
添加到任何 .first_func()
return 中。通过确保所有可链接的方法 return self
,它很容易实现。 (注意这与__call()__
无关)。
class foo():
def __init__(self, kind=None):
self.kind = kind
def my_print(self):
print (self.kind)
return self
def line(self):
self.kind = 'line'
return self
def bar(self):
self.kind='bar'
return self
您可以通过忽略 returned 值以 non-chained 方式使用 foo
对象:
a = foo()
a.line()
a.my_print()
a.bar()
a.my_print()
assert a.kind == 'bar'
或者,由于现在每个函数 return 都是对象本身,您可以操作 直接在 returned 值上。您可以使用具有以下等效代码的方法链接:
b = foo()
b.line().my_print().bar().my_print()
assert b.kind == 'bar'
甚至:
c = foo().line().my_print().bar().my_print()
assert c.kind == 'bar'
摆脱 ()
调用语法的问题是一个完全独立于方法链的概念。如果您想要链属性,并让这些属性改变它们的对象,请使用 @property
装饰器。 (但是通过 属性 改变对象似乎很危险。最好使用一个方法并用动词命名它:例如 .set_line()
而不是 .line
。)
class foo():
def __init__(self, kind=None):
self.kind = kind
def my_print(self):
print (self.kind)
return self
@property
def line(self):
self.kind = 'line'
return self
@property
def bar(self):
self.kind='bar'
return self
a = foo()
a.line
a.my_print()
a.bar
a.my_print()
assert a.kind == 'bar'
b = foo()
b.line.my_print().bar.my_print()
assert b.kind == 'bar'
c = foo().line.my_print().bar.my_print()
assert c.kind == 'bar'
还有另一种有趣的实现方式
class Foo:
def __init__(self, kind=[]):
self.kind = kind
def __getattr__(self, attrs):
self.attrs = attrs
return Foo(self.kind + [attrs])
def __call__(self):
return self.kind[::-1][0]
my_obj = Foo()
print(my_obj.bar.line.bar.bar.line())
使用此代码你不必传递 .my_print()
但这里要注意的一件事是 Foo class 将把任何东西作为参数,就像我们尝试 print(my_obj.bar.line.bar.bar.circle())
它会return圈子。
您还可以编辑此代码以在调用任何函数时获取参数。