Hãy bắt đầu với trang trí Python.
Trình trang trí Python là một hàm giúp thêm một số chức năng bổ sung vào một hàm đã được xác định.
Trong Python, mọi thứ đều là một đối tượng. Các hàm trong Python là các đối tượng hạng nhất, có nghĩa là chúng có thể được tham chiếu bởi một biến, được thêm vào danh sách, được truyền dưới dạng đối số cho hàm khác, v.v.
Hãy xem xét đoạn mã sau.
def decorator_func(fun):
def wrapper_func():
print("Wrapper function started")
fun()
print("Given function decorated")
# Wrapper function add something to the passed function and decorator
# returns the wrapper function
return wrapper_func
def say_bye():
print("bye!!")
say_bye = decorator_func(say_bye)
say_bye()
# Output:
# Wrapper function started
# bye
# Given function decorated
Ở đây, chúng ta có thể nói rằng hàm trang trí đã sửa đổi hàm say_hello của chúng ta và thêm một số dòng mã bổ sung trong đó.
Cú pháp Python cho trang trí
def decorator_func(fun):
def wrapper_func():
print("Wrapper function started")
fun()
print("Given function decorated")
# Wrapper function add something to the passed function and decorator
# returns the wrapper function
return wrapper_func
@decorator_func
def say_bye():
print("bye!!")
say_bye()
Chúng ta hãy kết luận tất cả mọi thứ hơn với một kịch bản trường hợp, nhưng trước đó hãy nói về một số điều tiên quyết.
Getters và setters được sử dụng trong nhiều ngôn ngữ lập trình hướng đối tượng để đảm bảo nguyên tắc đóng gói dữ liệu (được xem như là gói dữ liệu với các phương thức hoạt động trên các dữ liệu này.)
Các phương thức này tất nhiên là getter để lấy dữ liệu và setter để thay đổi dữ liệu.
Theo nguyên tắc này, các thuộc tính của một lớp được đặt ở chế độ riêng tư để ẩn và bảo vệ chúng khỏi các mã khác.
Yup, @property về cơ bản là một cách pythonic để sử dụng getters và setters.
Python có một khái niệm tuyệt vời gọi là property làm cho cuộc sống của một lập trình viên hướng đối tượng đơn giản hơn nhiều.
Hãy để chúng tôi giả định rằng bạn quyết định tạo ra một lớp có thể lưu trữ nhiệt độ ở độ Celsius.
class Celsius:
def __init__(self, temperature = 0):
self.set_temperature(temperature)
def to_fahrenheit(self):
return (self.get_temperature() * 1.8) + 32
def get_temperature(self):
return self._temperature
def set_temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
self._temperature = value
Mã tái cấu trúc, đây là cách chúng ta có thể đạt được bằng tài sản.
Trong Python, property () là một hàm dựng sẵn để tạo và trả về một đối tượng thuộc tính.
Một đối tượng thuộc tính có ba phương thức, getter (), setter () và xóa ().
class Celsius:
def __init__(self, temperature = 0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
def get_temperature(self):
print("Getting value")
return self.temperature
def set_temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
print("Setting value")
self.temperature = value
temperature = property(get_temperature,set_temperature)
Đây,
temperature = property(get_temperature,set_temperature)
có thể đã bị phá vỡ như,
# make empty property
temperature = property()
# assign fget
temperature = temperature.getter(get_temperature)
# assign fset
temperature = temperature.setter(set_temperature)
Điểm cần lưu ý:
- get_tem Nhiệt độ vẫn là một tài sản thay vì một phương thức.
Bây giờ bạn có thể truy cập giá trị của nhiệt độ bằng cách viết.
C = Celsius()
C.temperature
# instead of writing C.get_temperature()
Chúng ta có thể tiếp tục và không xác định tên get_tem Nhiệt độ và set_tem Nhiệt độ vì chúng không cần thiết và gây ô nhiễm không gian tên lớp.
Cách pythonic để đối phó với vấn đề trên là sử dụng @property .
class Celsius:
def __init__(self, temperature = 0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
@property
def temperature(self):
print("Getting value")
return self.temperature
@temperature.setter
def temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
print("Setting value")
self.temperature = value
Điểm cần lưu ý -
- Một phương thức được sử dụng để nhận giá trị được trang trí bằng "@property".
- Phương thức có chức năng như setter được trang trí bằng "@ nhiệt độ.setter", nếu hàm được gọi là "x", chúng ta sẽ phải trang trí nó bằng "@ x.setter".
- Chúng tôi đã viết "hai" phương thức có cùng tên và một số tham số khác nhau "def nhiệt độ (tự)" và "nhiệt độ def (tự, x)".
Như bạn có thể thấy, mã chắc chắn là ít thanh lịch.
Bây giờ, hãy nói về một scenerio thực tế ngoài đời thực.
Giả sử bạn đã thiết kế một lớp như sau:
class OurClass:
def __init__(self, a):
self.x = a
y = OurClass(10)
print(y.x)
Bây giờ, hãy giả sử thêm rằng lớp của chúng tôi đã trở nên phổ biến trong số các khách hàng và họ bắt đầu sử dụng nó trong các chương trình của họ, Họ đã thực hiện tất cả các loại bài tập cho đối tượng.
Và Một ngày định mệnh, một khách hàng đáng tin cậy đã đến với chúng tôi và cho rằng "x" phải có giá trị từ 0 đến 1000, đây thực sự là một kịch bản khủng khiếp!
Do thuộc tính dễ dàng: Chúng tôi tạo một phiên bản thuộc tính của "x".
class OurClass:
def __init__(self,x):
self.x = x
@property
def x(self):
return self.__x
@x.setter
def x(self, x):
if x < 0:
self.__x = 0
elif x > 1000:
self.__x = 1000
else:
self.__x = x
Điều này thật tuyệt vời phải không: Bạn có thể bắt đầu với việc triển khai đơn giản nhất có thể tưởng tượng được và bạn có thể tự do di chuyển sang phiên bản thuộc tính mà không phải thay đổi giao diện! Vì vậy, các thuộc tính không chỉ là sự thay thế cho getters và setter!
Bạn có thể kiểm tra việc thực hiện này tại đây