Ví dụ đối tượng miễn phí Python

Mỗi khi bạn tạo một thể hiện của một lớp trong Python, bạn đang sử dụng hết một số bộ nhớ – bao gồm cả chi phí thực tế có thể lớn hơn dữ liệu mà bạn quan tâm. Tạo một triệu đối tượng và bạn có chi phí gấp một triệu lần

Và chi phí đó có thể tăng lên, ngăn cản bạn chạy chương trình của mình hoặc tăng số tiền bạn chi cho việc cung cấp phần cứng

Vì vậy, hãy xem chi phí thực sự lớn như thế nào (xem trước. nó lớn. ) và những gì bạn có thể làm về nó

Không chú ý đến từ điển đằng sau bức màn

Trong Python, đằng sau hậu trường, mọi phiên bản của một lớp bình thường lưu trữ các thuộc tính của nó trong từ điển

Do đó, việc sử dụng bộ nhớ cho một đối tượng bình thường có ba nguồn

  1. Chi phí thông thường của bất kỳ đối tượng Python nào, có thể là cá thể, số nguyên hoặc những gì bạn có, cộng với chi phí của một từ điển trống
  2. Chi phí lưu trữ các mục trong từ điển
  3. Dữ liệu thực tế được thêm vào dưới dạng thuộc tính

Ví dụ

from random import random

class Point:
    def __init__(self, x):
        self.x = x


objects = []
for _ in range(1000000):
    r = random()
    point = Point(r)
    objects.append(point)

Chúng ta có thể hình dung mức sử dụng bộ nhớ cao nhất


Và chúng ta có thể thấy mức sử dụng bộ nhớ của ba loại đó, cộng thêm loại thứ tư

  1. Point đối tượng nói chung. 30% bộ nhớ
  2. Thêm một thuộc tính vào từ điển của Point. 55% bộ nhớ
  3. Các số dấu phẩy động. 11% bộ nhớ
  4. Danh sách lưu trữ các đối tượng Point. 4% bộ nhớ

Về cơ bản, mức sử dụng bộ nhớ cao ít nhất gấp 10 lần so với thông tin thực tế mà chúng tôi quan tâm, mục 3, các số dấu phẩy động ngẫu nhiên

Giải pháp số 1. Tạm biệt, từ điển

Có một từ điển cho mọi đối tượng sẽ có ý nghĩa nếu bạn muốn thêm các thuộc tính tùy ý vào bất kỳ đối tượng cụ thể nào. Hầu hết thời gian chúng tôi không muốn làm điều đó. có một tập hợp các thuộc tính nhất định mà chúng tôi biết một lớp sẽ có, và đó là nó

Nhập __slots__. Bằng cách đặt thuộc tính này trên một lớp, với một danh sách các chuỗi cho biết danh sách các thuộc tính

  1. Chỉ những thuộc tính đó mới được phép
  2. Quan trọng hơn đối với mục đích của chúng tôi, Python sẽ không tạo từ điển cho mọi đối tượng

Tất cả những gì chúng ta phải làm là thêm một dòng mã

from random import random

class Point:
    __slots__ = ["x"]  # <-- allowed attributes
    def __init__(self, x):
        self.x = x


objects = []
for _ in range(1000000):
    r = random()
    point = Point(r)
    objects.append(point)

Bây giờ, chúng ta có thể đo mức sử dụng bộ nhớ


Chi phí cho từ điển hiện đã biến mất và mức sử dụng bộ nhớ đã giảm 60%, từ 207 MB xuống còn 86 MB. Không tệ cho một dòng mã

Giải pháp số 2. Loại bỏ các đối tượng

Một cách tiếp cận vấn đề khác là lưu ý rằng việc lưu trữ danh sách hàng triệu đối tượng giống hệt nhau là khá lãng phí, đặc biệt nếu các thao tác sẽ xảy ra trên các nhóm đối tượng. Vì vậy, thay vì tạo một đối tượng cho mỗi điểm, tại sao không chỉ tạo một danh sách cho mỗi thuộc tính?

from random import random

points = {
    "x": [],
    # "y": [],
    # "z": []
    # etc.
}

for _ in range(1000000):
    r = random()
    points["x"].append(r)

Mức sử dụng bộ nhớ hiện giảm xuống còn 30 MB, giảm 85% so với 206 MB ban đầu


Tiền thưởng, giải pháp thậm chí còn tốt hơn. Pandas thay vì dict-of-lists

Tại thời điểm này, hầu hết chi phí hoạt động là do chi phí có một đối tượng Python trên mỗi số dấu phẩy động

Vì vậy, bạn có thể giảm mức sử dụng bộ nhớ hơn nữa, xuống còn khoảng 8 MB, bằng cách sử dụng Khung dữ liệu Pandas để lưu trữ thông tin. nó sẽ sử dụng các mảng NumPy để lưu trữ các số bên trong một cách hiệu quả

cách tiếp cận khác

Nói chung, lưu trữ quá nhiều đối tượng Python cùng một lúc sẽ gây lãng phí bộ nhớ. Như mọi khi, các giải pháp có thể bao gồm nén, tạo khối hoặc lập chỉ mục

  • Các giải pháp tôi đề cập trong bài viết này tập trung vào việc nén. cùng một thông tin được lưu trữ với ít chi phí hơn
  • Nếu bạn không cần lưu trữ tất cả dữ liệu trong bộ nhớ cùng một lúc, bạn có thể xử lý dữ liệu theo lô, chẳng hạn bằng cách trả lại dữ liệu qua trình tạo
  • Cuối cùng, bạn có thể cố gắng chỉ tải dữ liệu mà bạn thực sự quan tâm bằng cách sử dụng lập chỉ mục

Tìm hiểu thêm các kỹ thuật để giảm mức sử dụng bộ nhớ—đọc phần còn lại của hướng dẫn Bộ dữ liệu lớn hơn bộ nhớ dành cho Python


Bài viết tiếp theo. Ước tính và lập mô hình yêu cầu bộ nhớ để xử lý dữ liệu
Bài viết trước. Chi phí bộ nhớ lớn. Các số trong Python và cách NumPy hỗ trợ


Xử lý dữ liệu quá chậm?

Bạn có thể nhận được kết quả nhanh hơn từ quy trình khoa học dữ liệu của mình—và cũng nhận lại được một số tiền—nếu bạn có thể tìm ra lý do tại sao mã của mình chạy chậm

Xác định các nút thắt cổ chai về hiệu suất và ngốn bộ nhớ trong khoa học dữ liệu sản xuất của bạn Các công việc Python với Sciagraph, trình lược tả luôn bật cho các công việc sản xuất hàng loạt

Tìm hiểu các kỹ năng kỹ thuật phần mềm Python thực tế mà bạn có thể sử dụng trong công việc của mình

Đăng ký nhận bản tin của tôi và tham gia cùng hơn 6500 nhà phát triển Python và nhà khoa học dữ liệu học các công cụ và kỹ thuật thực tế, từ hiệu suất Python đến đóng gói Docker, với một bài viết mới miễn phí trong hộp thư đến của bạn mỗi tuần

Bạn có thể tạo đối tượng Python mà không có lớp không?

Chúng ta đã biết rằng một đối tượng là nơi chứa một số dữ liệu và các phương thức hoạt động trên dữ liệu đó. Trong Python, một đối tượng được tạo từ một lớp. Để tạo một đối tượng, trước tiên bạn phải định nghĩa một lớp .

__ del __ trong Python là gì?

Trong Python, phương thức __del__() được gọi là phương thức hủy diệt . Nó được gọi sau khi bộ sưu tập rác của một đối tượng xảy ra, xảy ra sau khi tất cả các tham chiếu đến mục đó đã bị hủy.

Làm cách nào để khởi tạo các đối tượng trong Python?

Khởi tạo đối tượng Python . Chúng tôi sử dụng điều này để điền vào các giá trị cho các thuộc tính khi chúng tôi tạo một đối tượng. Ở đây, __init__() có hai thuộc tính ngoài 'self'- ​​màu sắc và hình dạng. Sau đó, chúng tôi chuyển các đối số tương ứng cho các đối số này tại thời điểm tạo đối tượng

__ mới __ trong Python là gì?

Python __new__() là phương thức khởi tạo kiểm soát việc tạo phiên bản mới . Nó được gọi đầu tiên và nó trả về một thể hiện của lớp mới. Python __init__() là phương thức khởi tạo để thiết lập các thuộc tính (i. e. , trạng thái) của phiên bản mới được tạo. Nó được gọi sau khi tạo và không trả về gì cả, tôi. e. , Không có.