Câu hỏi Python lớp trang trí phương pháp với các đối số tự?


Làm thế nào để vượt qua một trường lớp để một trang trí trên một phương pháp lớp như một đối số? Những gì tôi muốn làm là một cái gì đó như:

class Client(object):
    def __init__(self, url):
        self.url = url

    @check_authorization("some_attr", self.url)
    def get(self):
        do_work()

Nó phàn nàn rằng bản thân không tồn tại khi truyền self.url cho người trang trí. Có cách nào để giái quyết vấn đề này không?


76
2017-07-30 23:30


gốc


Đó có phải là một trang trí tùy chỉnh mà bạn có quyền kiểm soát hay một trang mà bạn không thể thay đổi? - Joel Cornett
Đó là trang trí của tôi, vì vậy tôi có toàn quyền kiểm soát nó - Mark
Nó được gọi trước khi init tôi nghĩ là vấn đề ... - Joran Beasley
Vấn đề là bản thân không tồn tại ở thời gian định nghĩa hàm. Bạn cần phải biến nó thành một phần chức năng. - Antimony


Các câu trả lời:


Vâng. Thay vì truyền vào thuộc tính instance tại thời gian định nghĩa lớp, hãy kiểm tra nó tại thời gian chạy:

def check_authorization(f):
    def wrapper(*args):
        print args[0].url
        return f(*args)
    return wrapper

class Client(object):
    def __init__(self, url):
        self.url = url

    @check_authorization
    def get(self):
        print 'get'

>>> Client('http://www.google.com').get()
http://www.google.com
get

Trình trang trí chặn các đối số phương thức; đối số đầu tiên là cá thể, vì vậy nó đọc thuộc tính của nó. Bạn có thể chuyển tên thuộc tính dưới dạng chuỗi cho trình trang trí và sử dụng getattr nếu bạn không muốn hardcode tên thuộc tính:

def check_authorization(attribute):
    def _check_authorization(f):
        def wrapper(self, *args):
            print getattr(self, attribute)
            return f(self, *args)
        return wrapper
    return _check_authorization

113
2017-07-30 23:38





from re import search
from functools import wraps

def is_match(_lambda, pattern):
    def wrapper(f):
        @wraps(f)
        def wrapped(self, *f_args, **f_kwargs):
            if callable(_lambda) and search(pattern, (_lambda(self) or '')): 
                f(self, *f_args, **f_kwargs)
        return wrapped
    return wrapper

class MyTest(object):

    def __init__(self):
        self.name = 'foo'
        self.surname = 'bar'

    @is_match(lambda x: x.name, 'foo')
    @is_match(lambda x: x.surname, 'foo')
    def my_rule(self):
        print 'my_rule : ok'

    @is_match(lambda x: x.name, 'foo')
    @is_match(lambda x: x.surname, 'bar')
    def my_rule2(self):
        print 'my_rule2 : ok'



test = MyTest()
test.my_rule()
test.my_rule2()

ouput:   my_rule2: ok


21
2018-05-03 11:52



Cảm ơn bạn rất nhiều! Đây sẽ là câu trả lời được chấp nhận. Tôi đã rách tóc ra cố gắng tìm ra những người trang trí cho các phương pháp lớp học. - benshepherd
@raphael Trong thiết lập này tôi dường như không thể truy cập _lambda hoặc mẫu. Làm thế nào tôi có thể khắc phục điều đó. - Jonathan
@ Raphael: Làm thế nào tôi có thể làm tương tự cho một classmethod, vì ở đây tất cả các phương pháp là phương pháp dụ. - Apurva Kunkulol


Một ví dụ ngắn gọn hơn có thể như sau:

#/usr/bin/env python3
from functools import wraps

def wrapper(method):
    @wraps(method)
    def _impl(self, *method_args, **method_kwargs):
        return method(self, *method_args, **method_kwargs) + "!"
    return _impl

class Foo:
    @wrapper
    def bar(self, word):
        return word

f = Foo()
result = f.bar("kitty")
print(result)

Mà sẽ in:

kitty!

15
2018-04-29 18:13





Bạn không thể. Không có self trong thân thể lớp, bởi vì không có cá thể nào tồn tại. Bạn sẽ cần phải vượt qua nó, nói rằng, một str có chứa tên thuộc tính để tra cứu trên cá thể, mà hàm trả về có thể làm hoặc sử dụng một phương thức hoàn toàn khác.


2
2017-07-30 23:38