Thuộc tính trong hàm python là gì?

Tôi rất ngạc nhiên khi biết rằng các hàm và phương thức có thể được gán thuộc tính, tương tự như cách người ta có thể gán thuộc tính cho lớp, thể hiện của lớp và hầu hết các đối tượng khác

def do_thing(): 
  return
do_thing.whatever = "hi"

print(do_thing.whatever)
#> hi
Cái gì?

Vì lý do gì là điều này thậm chí có thể?

bạn có thể đang nghĩ

“Tất nhiên điều này hiệu quả. Chức năng là đối tượng. Tất cả mọi thứ là một đối tượng. Và do đó, điều hợp lý là các hàm có các thuộc tính có thể gán. Các lớp là các đối tượng. Các lớp có các thuộc tính có thể gán. Chức năng cũng là đối tượng. Do đó các chức năng cũng phải có các thuộc tính có thể gán. ”

Chà, chỉ vì một thứ gì đó là một đối tượng không có nghĩa nó là một thuộc tính được gán miễn phí cho tất cả. Trên thực tế, Python rõ ràng cấm gán thuộc tính trong một vài trường hợp phổ biến

Ví dụ: bạn không thể gán thuộc tính cho các chức năng tích hợp

print.some_data = "foo"
#> AttributeError: 'builtin_function_or_method' object has no attribute 'some_data'

Và bạn không thể gán thuộc tính cho các loại tích hợp

var = "stringy string"
var.some_data = "foo"
#> AttributeError: 'str' object has no attribute 'some_data'

Và vâng, cả hai đều là đối tượng

isinstance(print, object)
#> True
isinstance(var, object)
#> True

Đáng ngạc nhiên là Python cho phép gán thuộc tính cho các hàm và phương thức (không tích hợp sẵn). Và bạn có thể đặt bất cứ thứ gì bạn muốn vào đó. Kiểm tra nó ra

def do_thing():
  pass
do_thing.sneaky_func = eval
do_thing.sneaky_func("print('O_o')")
#> O_o
Tại sao

Điều này không phải lúc nào cũng đúng. Các chức năng ban đầu không hỗ trợ gán thuộc tính. Nhưng mặc dù không hỗ trợ gán thuộc tính, các chức năng không bao giờ hoàn toàn không có thuộc tính. Ngay cả trong những ngày đầu của Python, các hàm có một số thuộc tính, trong đó có một số thuộc tính có thể ghi—cụ thể là

print.some_data = "foo"
#> AttributeError: 'builtin_function_or_method' object has no attribute 'some_data'
0

Nếu bạn đã từng ghi lại mã của mình, thì có lẽ bạn đã quen thuộc với các chuỗi tài liệu. Docstrings là đường cú pháp cho phép một người viết tài liệu cho các mô-đun, lớp, phương thức và hàm bằng cách đặt một chuỗi ký tự nội tuyến ở đầu định nghĩa của đối tượng

def do_thing():
  """Here's some documentation"""
  return
help(do_thing)
#> Help on function do_thing in module __main__:
#> do_thing()
#>    Here's some documentation

Chuỗi tài liệu của một hàm được lưu trữ trong thuộc tính

print.some_data = "foo"
#> AttributeError: 'builtin_function_or_method' object has no attribute 'some_data'
0 của nó

________số 8_______

Vậy chuỗi tài liệu phải làm gì với các thuộc tính chức năng?

Trong những ngày đầu của Python, các kỹ sư đã bắt đầu chiếm quyền điều khiển chuỗi tài liệu cho các mục đích không mong muốn—không sử dụng chuỗi tài liệu cho tài liệu mà thay vào đó để lưu trữ thông tin có thể truy cập theo chương trình khác về chức năng

Ví dụ, John Aycock đã viết một hệ thống phân tích cú pháp thông minh để quyết định có nên áp dụng một phương thức cho một chuỗi mục tiêu hay không bằng cách đánh giá xem chuỗi mục tiêu đó có khớp với một biểu thức chính quy có trong chuỗi tài liệu của phương thức hay không.

Để đối phó với việc khai thác chuỗi tài liệu, Barry Warsaw đã đề xuất, một phần mở rộng cho ngôn ngữ Python bổ sung hỗ trợ cho các thuộc tính phương thức/hàm. Nó đã được phê duyệt và triển khai trong Python 2. 1+

Khi nào thì thích hợp để sử dụng các thuộc tính chức năng?

Theo tôi. hiếm khi

Nhiều Pythonistas có kinh nghiệm không biết rằng thậm chí có thể gán các thuộc tính chức năng. Nếu bạn đang làm công việc phát triển phần mềm hàng ngày, thì việc thiếu quen thuộc trong cộng đồng thường là dấu hiệu đỏ cho một tính năng ngôn ngữ

Điều đó đang được nói, có những lý do hợp lệ để người ta có thể lưu trữ siêu dữ liệu trên một chức năng

Các thuộc tính hàm rất hữu ích nếu bạn đang chuyển các hàm xung quanh và cần một cách để ghép thông tin vào các hàm đó để sử dụng sau này. Có lẽ bạn đang viết một hàm bậc cao hơn—một hàm lấy một hàm làm đối số. Bạn có thể muốn hàm bậc cao của mình xử lý hàm bậc thấp khác nhau tùy thuộc vào giá trị được lưu trữ trong một thuộc tính của hàm

def dog_feeder(food_type):
  print(f'feeding {food_type} to the dog')
dog_feeder.species = 'dog'

def cat_feeder(food_type):
  print(f'feeding {food_type} to the cat')
cat_feeder.species = 'cat'

def feed_pet(feed_func):
  # Higher order function that takes a feed function as argument
  if feed_func.species == 'dog':
    feed_func('dog food')
  elif feed_func.species == 'cat':
    pass

feed_pet(dog_feeder)
#> feeding dog food to the dog

feed_pet(cat_feeder)
#> 

Tôi nên lưu ý rằng trong Python 3. 4+, trình trang trí

print.some_data = "foo"
#> AttributeError: 'builtin_function_or_method' object has no attribute 'some_data'
2 phục vụ tốt hơn trường hợp sử dụng trên. Tôi sẽ nói về
print.some_data = "foo"
#> AttributeError: 'builtin_function_or_method' object has no attribute 'some_data'
3 trong một bài đăng trong tương lai. Nhưng quan điểm của tôi đứng. khi thực hiện lập trình bậc cao, các hàm mang dữ liệu về chính chúng có thể hữu ích

và tin nhắn của Paul Prescod tới danh sách gửi thư của python-dev mô tả một số trường hợp sử dụng khác

Ví dụ: người ta có thể muốn xác định các định dạng chuỗi tài liệu khác nhau để phù hợp với các IDE hoặc phương pháp tài liệu khác nhau

Tương tự như trình phân tích cú pháp của John Aycock. nếu bạn đang viết một lớp để duyệt cấu trúc dữ liệu và bạn muốn liên kết các loại nút cụ thể với các phương thức nhất định, thì danh sách các loại nút mà một phương thức hỗ trợ có thể được lưu trữ dưới dạng một thuộc tính của phương thức đó

Khi nào thì không thích hợp để sử dụng các thuộc tính chức năng?

Nếu bạn cần một kho lưu trữ dữ liệu nhanh chóng và tin rằng ký hiệu dấu chấm đẹp hơn dict[key]

def settings():
  return

settings.host = '0.0.0.0'
settings.port = 8080

app.run(host=settings.host, port=settings.port)

Nghiêm túc, đừng làm điều này. Nếu đoạn mã trên xuất hiện trên bàn của tôi để xem xét, tôi sẽ thẳng thắn vỗ lưng cho người kỹ sư đó vì đã thông minh, sau đó lịch sự yêu cầu họ bị tống vào trại cải tạo vì tội ác của mình

Nếu bạn cần lưu trữ dữ liệu, hãy sử dụng từ điển, lớp hoặc thậm chí là mô-đun. Bất cứ điều gì ngoại trừ một chức năng

Một lý do không phù hợp sâu sắc khác để tận dụng các thuộc tính hàm là bạn không hài lòng với hành vi có sẵn của lớp và muốn tạo các hàm có hành vi giống như lớp. Bạn có thể thực hiện điều đó với các thuộc tính hàm và một chút đệ quy thú vị

def Dog():
  def bark():
    print("bark bark")
  Dog.bark = bark
  return Dog

fido = Dog()
fido.bark()
#> bark bark

Xin đừng làm điều này

Phần kết luận

Tôi hy vọng bạn thích phần đi sâu vào các thuộc tính hàm Python này. Đây là một bài viết trong loạt bài về Python arcana mà tôi sẽ xuất bản trong vài tháng tới. Cần kiểm tra lại sớm để biết thêm

Thuộc tính chức năng là gì?

Các thuộc tính hàm là các tiện ích mở rộng được triển khai để nâng cao tính di động của các chương trình được phát triển bằng GNU C . Các thuộc tính có thể chỉ định cho các hàm cung cấp các cách rõ ràng để giúp trình biên dịch tối ưu hóa các lệnh gọi hàm và hướng dẫn trình biên dịch kiểm tra nhiều khía cạnh hơn của mã. Những người khác cung cấp chức năng bổ sung.

3 thuộc tính của Python là gì?

Các phương thức tĩnh, phương thức lớp và phương thức thể hiện tất cả đều thuộc về lớp. Chúng ta có thể gọi các thuộc tính thể hiện bằng cách sử dụng thuộc tính lớp bằng cách truyền các thể hiện của đối tượng trong phương thức. Tính năng này tiết kiệm bộ nhớ của chương trình Python.

Các loại thuộc tính 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.

Thuộc tính và phương thức trong Python là gì?

Một biến được lưu trữ trong một thể hiện hoặc lớp được gọi là một thuộc tính. Một hàm được lưu trữ trong một thể hiện hoặc lớp được gọi là một phương thức .