__ Getattribute __ trong python là gì?

Hôm nọ, tôi đang dạy lập trình meta Python cho một đồng nghiệp. Tôi nghĩ rằng đó là một cách hay để tìm hiểu về các hàm bậc cao vì lập trình meta sử dụng rộng rãi các bao đóng, trình tạo hàm, trình trang trí… Tôi đang cố gắng thực hiện một cuộc thăm dò khái niệm về trình kết nối REST rất chung chung. Đây là nỗ lực đầu tiên (và sai) của tôi

class RESTConn(object):

  def __init__(self, entry_point):
    self.entry_point = entry_point

  def method_builder(self, method_name):
    verb, _, collection = method_name.split('_', 2)
    def do_verb(payload=None, **kwargs):
      uri = self.make_uri(collection)
      querystring = self.make_querystring(kwargs)
      print verb.upper(), self.combine(uri, querystring)
      if payload:
        print payload

    return do_verb

  def make_uri(self, collection):
    return '/'.join([self.entry_point, collection])

  def make_querystring(self, kwargs):
    return '&'.join(['='.join(pair) for pair in kwargs.iteritems()])

  def combine(self, uri, querystring):
    if querystring:
      return '&'.join([uri, querystring])

    return uri

  def __getattribute__(self, name):
    if not hasattr(self, name):
      method = self.method_builder(name)
      setattr(self, name, method)

    return super(RESTConn, self).__getattribute__(name)

Hãy thử ví dụ này bằng cách khởi tạo một trình kết nối mới và thử gọi một cái gì đó như

c = RESTConn('unoyunodiez.com')
c.get_from_articles()

Chương trình rơi vào một đệ quy vô hạn và không làm gì trước khi gặp sự cố. Tại sao?

Có ba vấn đề ở đây. Đầu tiên và quan trọng nhất là sử dụng __getattribute__(), thứ hai là sử dụng hasattr() và thứ ba là tự truy cập. method_builder()

Phương thức của đối tượng __getattribute__() được sử dụng để truy xuất một thuộc tính từ một thể hiện. Nó ghi lại mọi nỗ lực truy cập một thuộc tính thể hiện bằng cách sử dụng ký hiệu dấu chấm hoặc hàm tích hợp getattr(). Trừ khi nó bị ghi đè, biểu thức cũ được dịch thành đối tượng. __getattribute__(bản thân, ‘get_from_article’). Việc triển khai mặc định xem xét không gian tên của cá thể, sau đó xem xét không gian tên của lớp, sau đó vào từng không gian tên của cơ sở, v.v. Cuối cùng, nếu không tìm thấy, triển khai mặc định sẽ gọi phương thức dự phòng __getattr__() của cá thể và nó làm tăng ngoại lệ AttributeError làm triển khai mặc định

Bản thân đây không phải là vấn đề nhưng nếu bạn đủ chú ý, bạn sẽ nhận thấy chúng tôi đang cố gắng tạo phương thức mới chỉ khi đối tượng chưa có phương thức. Về mặt ngữ nghĩa, nó giống như ghi đè __getattr__() vì nó chỉ được gọi khi không tìm thấy thuộc tính. Vì vậy, ngay cả khi chúng tôi không thể giải thích lỗi đệ quy vô hạn, chúng tôi có thể sửa lớp bằng cách thay thế

  def __getattribute__(self, name):
    if not hasattr(self, name):
      method = self.method_builder(name)
      setattr(self, name, method)

    return super(RESTConn, self).__getattribute__(name)

với

  def __getattr__(self, name):
    method = self.method_builder(name)
    setattr(self, name, method)
    return getattr(self, name)

Vì vậy, sự khác biệt giữa __getattribute__() và __getattr__() là cái đầu tiên được gọi vô điều kiện khi một thuộc tính đang được truy xuất từ ​​một thể hiện trong khi cái thứ hai chỉ được gọi khi không tìm thấy thuộc tính

Nhưng, còn đệ quy vô hạn thì sao?

Ok, tôi đã nói vấn đề là sử dụng __getattribute__, hasattr() và self. method_builder() nhưng vấn đề thực sự là sử dụng hasattr() và self. method_builder() bên trong __getattribute__(). Theo tài liệu Python hasattr(self, name) được triển khai bằng cách thử getattr(self, name) và bắt ngoại lệ. Nếu một ngoại lệ bị bắt, thì hasattr() trả về Sai. Nhưng sử dụng getattr() là một nỗ lực để truy cập thuộc tính thể hiện nên __getattribute__() được gọi lại. Điều này dẫn đến một cuộc gọi khác tới hasattr() sử dụng getattr(), đây là một nỗ lực khác để tìm và thuộc tính và nó gọi __getattribute__() gọi hasattr() sử dụng getattr() và cứ tiếp tục như vậy… cho đến khi một ngoại lệ RuntimeError được . Vì vậy, tất cả hasattr() trả về Sai và chương trình có thể tiếp tục với câu lệnh tiếp theo

Tuyên bố tiếp theo thậm chí còn nguy hiểm hơn. Nó cố gắng truy cập ‘method_builder’ từ instance self nên __getattribute__() được gọi lại, bao gồm việc gọi lại hasattr() và sau đó chuyển sang lần thử tiếp theo để truy cập ‘method_builder’. Bạn có thể thấy những gì tiếp theo?

Vì vậy, cách chính xác để thực hiện điều này bằng cách sử dụng __getattribute__() thay vì __getattr__() là gì?

  def __getattribute__(self, name):
    try:
      method = super(RESTConn, self).__getattribute__(name)
    except AttributeError:
      method = super(RESTConn, self).__getattribute__('method_builder')(name)
      setattr(self, name, method)

    return method

Như bạn thấy, trước tiên chúng tôi cố gắng truy xuất phương thức bằng cách gọi cài đặt mặc định của __getattribute__(). Nếu không tìm thấy, chúng ta sẽ xây dựng một phương thức mới bằng cách gọi ‘method_builder’ mà không gọi __getattribute__() của RESTConn và tránh đệ quy vô hạn. Cuối cùng, chúng tôi trả lại phương thức. Đơn giản, một khi bạn biết __getattribute__ đang thực sự làm gì. ,)

Và đó là tất cả. Bạn có thể đọc thêm về quy trình truy xuất thuộc tính trong mô hình dữ liệu Python. Do kết quả của nghiên cứu nhỏ này, tôi đã cập nhật các bài thuyết trình của mình về siêu lập trình trong Python và các bài viết trước đây của tôi bằng tiếng Tây Ban Nha

Getattribute được sử dụng để làm gì trong Python?

Hàm getattr() của Python được sử dụng để lấy giá trị thuộc tính của đối tượng và nếu không tìm thấy thuộc tính của đối tượng đó thì giá trị mặc định .

Sự khác biệt giữa Getattribute và Getattr là gì?

getattribute. Được sử dụng để lấy một thuộc tính từ một thể hiện. Nó ghi lại mọi nỗ lực truy cập một thuộc tính thể hiện bằng cách sử dụng ký hiệu dấu chấm hoặc hàm tích hợp getattr(). getattr. Được thực thi dưới dạng tài nguyên cuối cùng khi không tìm thấy thuộc tính trong một đối tượng

Các loại thuộc tính khác nhau trong Python là gì?

Có hai loại tên thuộc tính hợp lệ. các thuộc tính và phương thức dữ liệu . Một loại tham chiếu thuộc tính thể hiện khác là một phương thức. Một phương thức là một hàm “thuộc về” một đối tượng. (Trong Python, thuật ngữ phương thức không phải là duy nhất đối với các thể hiện của lớp. các loại đối tượng khác cũng có thể có các phương thức.