Tương đương Python của phương thức method_missing
của Ruby là gì? Tôi đã thử sử dụng __getattr__
nhưng móc này cũng áp dụng cho các trường. Tôi chỉ muốn chặn các lời gọi phương thức. Cách Python để làm điều đó là gì?Python tương đương với 'method_missing' của Ruby '
Trả lời
Không có sự khác biệt về Python giữa các thuộc tính và phương thức. Phương pháp chỉ là một thuộc tính, có loại chỉ là instancemethod
, điều đó xảy ra là có thể gọi (hỗ trợ __call__
).
Nếu bạn muốn thực hiện điều này, phương pháp __getattr__
của bạn sẽ trả về một hàm (lambda
hoặc def
thông thường, bất kỳ bộ nào bạn cần) và có thể kiểm tra điều gì đó sau cuộc gọi.
Python không phân biệt giữa các phương pháp và thuộc tính (a.k.a. "biến mẫu") theo cách Ruby thực hiện. Các phương thức và các thuộc tính đối tượng khác được tra cứu chính xác theo cùng một cách trong Python - thậm chí không Python biết sự khác biệt ở giai đoạn tra cứu. Cho đến khi thuộc tính được tìm thấy, nó chỉ là một chuỗi.
Vì vậy, nếu bạn đang yêu cầu một cách để đảm bảo rằng __getattr__
là chỉ được gọi là phương pháp, tôi e rằng bạn có thể sẽ không tìm thấy giải pháp thanh lịch. Nhưng thật dễ dàng để chỉ đơn giản trả lại một hàm (hoặc thậm chí là một nhãn hiệu mới dynamically bound method) từ __getattr__
.
Đối với lý do tương tự bạn sẽ sử dụng 'method_missing' trong Ruby hoặc' doesNotUnderstand' trong Smalltalk. – missingfaktor
Tôi hiểu tại sao bạn muốn sử dụng '__getattr__'.Tôi chỉ không hiểu tại sao bạn "chỉ muốn chặn các lời gọi phương thức". – senderle
Thiết kế của tôi không yêu cầu chặn truy cập trường, nhưng nó không có vẻ là một trở ngại lớn. Tôi tìm thấy giải pháp được cung cấp bởi @Emil đủ tốt cho các yêu cầu của tôi. – missingfaktor
Mặc dù tôi không khuyên bạn nên dùng nó !!!!!!!!!!!!!!!!!!!!!
loại sắp đến gần hơn để triển khai hành vi gọi phương thức đặc biệt cho mỗi tên không tương ứng với thuộc tính/phương pháp có thể gọi. Tất nhiên họ vẫn không thực sự có các không gian tên riêng biệt nên có thể cảm thấy hơi lạ. Nó hoạt động bằng cách ghi đè __getattribute__
hoạt động ở mức thấp hơn sau đó __getattr__
nó cố gắng tìm nạp thuộc tính nếu nó không trả về một phương thức đặc biệt được gọi để gọi với tên mà bạn gọi, nếu nó thành công nếu nó được gọi nếu không kết thúc tốt đẹp kết quả với một đối tượng proxy hoạt động gần như chính xác theo cùng một cách, ngoại trừ nó thực hiện cuộc gọi với phương pháp đặc biệt của bạn.
Nó không cho phép bạn truy cập đối tượng gọi vì tôi không thể nghĩ ra cách tốt để làm điều đó mà không có bộ nhớ bị rò rỉ (đối tượng gọi) nếu nó đã là thuộc tính không thể gọi mà bạn lưu trữ (suy nghĩ duy nhất tôi có thể nghĩ đến là bắt đầu một chuỗi mới xóa nó sau một phút, do đó bạn có thể gọi nó là trừ khi bạn đang sử dụng nó trong một đóng cửa mà sẽ không được hỗ trợ trong trường hợp đó).
Chỉnh sửa: Tôi quên có thể gọi có thể có một số mặt tích cực sai.
phụ thuộc vào thư viện http://pypi.python.org/pypi/ProxyTypes
from peak.util.proxies import ObjectWrapper
from functools import partial
def m(name, *args, **kwargs):
print(name,repr(args),repr(kwargs))
class CallProxy(ObjectWrapper):
def __init__(self, obj, m, method_name):
ObjectWrapper.__init__(self, obj)
object.__setattr__(self, "_method_name", method_name)
object.__setattr__(self, "_m", m)
def __call__(self, *args, **kwargs):
return self._m(self._method_name, *args,**kwargs)
class Y(object):
def __init__(self):
self.x = [3]
def __getattribute__(self, name):
try:
val = object.__getattribute__(self, name)
if not callable(val):
return CallProxy(val, m, name)
else:
return val
except AttributeError:
return partial(m, name)
In [2]: y=Y()
In [3]: y.x
Out[3]: [3]
In [4]: y.z
Out[4]: <functools.partial at 0x2667890>
In [5]: y.zz([12])
('zz', '([12],)', '{}')
In [6]: y.x.append(5)
In [7]: y.x
Out[7]: [3, 5]
In [8]: y.x(1,2,3,key="no")
('x', '(2, 3)', "{'key': 'no'}")
Bạn có thể thực hiện một missing_method như tính năng theo cách dưới đây:
https://gist.github.com/gterzian/6400170
import unittest
from functools import partial
class MethodMissing:
def method_missing(self, name, *args, **kwargs):
'''please implement'''
raise NotImplementedError('please implement a "method_missing" method')
def __getattr__(self, name):
return partial(self.method_missing, name)
class Wrapper(object, MethodMissing):
def __init__(self, item):
self.item = item
def method_missing(self, name, *args, **kwargs):
if name in dir(self.item):
method = getattr(self.item, name)
if callable(method):
return method(*args, **kwargs)
else:
raise AttributeError(' %s has not method named "%s" ' % (self.item, name))
class Item(object):
def __init__(self, name):
self.name = name
def test(self, string):
return string + ' was passed on'
class EmptyWrapper(object, MethodMissing):
'''not implementing a missing_method'''
pass
class TestWrapper(unittest.TestCase):
def setUp(self):
self.item = Item('test')
self.wrapper = Wrapper(self.item)
self.empty_wrapper = EmptyWrapper()
def test_proxy_method_call(self):
string = self.wrapper.test('message')
self.assertEqual(string, 'message was passed on')
def test_normal_attribute_not_proxied(self,):
with self.assertRaises(AttributeError):
self.wrapper.name
self.wrapper.name()
def test_empty_wrapper_raises_error(self,):
with self.assertRaises(NotImplementedError):
self.empty_wrapper.test('message')
if __name__ == '__main__':
unittest.main()
Cảm ơn. Tôi tìm thấy [this] (http://venodesigns.net/2010/11/02/emulating-rubys-method_missing-in-python/) trên một chút googling. – missingfaktor
Để tham khảo, liên kết được đề cập xung quanh sự mơ hồ bằng cách xác định danh sách tên thuộc tính cần được coi là phương pháp (có vẻ như nó đánh bại mục đích, vì bạn chỉ có thể _define_ từng phương thức đó và ủy quyền cho một bài). –