Các thuộc tính của ngôn ngữ kịch bản python là gì?

Một lớp Python được tạo bởi một định nghĩa lớp, có một không gian tên được liên kết, hỗ trợ tham chiếu thuộc tính và có thể gọi được

      class name[[expr[,expr]*]]:
          suite
    

Định nghĩa lớp là một câu lệnh thực thi và như vậy có thể được sử dụng bất cứ khi nào một câu lệnh thực thi có thể xảy ra. Khi được thực thi, mỗi expr được đánh giá và phải đánh giá cho một lớp; . giả định là các câu lệnh trong bộ sẽ tạo các ràng buộc trong không gian tên này, do đó, thông thường các câu lệnh trong bộ là các phép gán và định nghĩa hàm. Sau khi thực thi bộ phần mềm, tên được liên kết với lớp mới trong không gian tên [gọi] bên ngoài và không gian tên mới của định nghĩa lớp được liên kết với đối tượng lớp

Các lớp có năm thuộc tính được xác định trước

AttributeTypeRead/WriteDescrip__dict__dictionaryR/WKhông gian tên lớp. __name__ stringR/OTên khác của lớp. __bases__ Bộ lớp/Các lớp mà lớp này kế thừa. __doc__string OR NoneR/WChuỗi tài liệu lớp học. __module__stringR/WTên của mô-đun trong đó lớp này được định nghĩa

Cách sử dụng đơn giản nhất của các lớp là các loại tích Descartes đơn giản, e. g. , các bản ghi của Pascal hoặc các cấu trúc của C

      class foo:
          a, b, c = 0, "bar", [1,2]
    

Khởi tạo các lớp

Một lớp được khởi tạo bằng cách gọi đối tượng lớp

      i = foo[]
      print i.a, i.b, i.c
    

Ở trên, tôi là một thể hiện của lớp foo. Các vị trí a, b và c của phiên bản có thể được sửa đổi bằng cách gán

      i.a = 12
      i.new = "yikes"        # dynamic attribute creation!
    

Lưu ý rằng các vị trí mới, không được xác định khi lớp được xác định, có thể được tạo theo ý muốn chỉ bằng cách gán. Thật vậy, khi làm việc tương tác, một định nghĩa lớp trống thường rất hữu ích.

      class foo: pass
      foo.a = 1
      foo.b = 2
    

Thuộc tính sơ thẩm

Các trường hợp có hai thuộc tính được xác định trước

AttributeTypeRead/WriteDescrip__dict__dictionaryR/WTên đối tượng space__class__classR/WLớp của đối tượng này

Thuộc tính lớp so với thuộc tính sơ thẩm

Điều quan trọng là phải hiểu sự khác biệt giữa các thuộc tính lớp và thể hiện, đặc biệt là khi các thuộc tính lớp có thể truy cập thông qua các thể hiện

Một thuộc tính được định nghĩa trong lớp, hoặc bằng văn bản trong định nghĩa lớp hoặc sau đó bằng cách gán cho một tham chiếu thuộc tính của lớp, là một thuộc tính lớp. Nó được lưu trữ trong không gian tên của lớp [__dict__ của nó]

Một thuộc tính được xác định trong thể hiện, bằng cách gán, là một thuộc tính thể hiện và được lưu trữ trong không gian tên của thể hiện -- ngay cả khi có một thuộc tính lớp có cùng tên. Việc gán thông qua cá thể dẫn đến một thuộc tính cá thể che khuất thuộc tính lớp

      class foo:
          a = 1
      i = foo[]
      foo.a => 1
      i.a => 1
      i.a = "inst"
      foo.a => 1
      i.a => "inst"
    

Có thể sửa đổi một thuộc tính lớp từ một thể hiện, nhưng bạn cần khai thác sự tiết lộ của Python về các không gian tên tương ứng

      foo.a => 1
      i.__class__.__dict__[a] = "class"
      foo.a => "class"
      i.a => "inst"
    

Khi một thuộc tính của một thể hiện được tham chiếu thông qua toán tử dấu chấm, trước tiên Python sẽ kiểm tra không gian tên thể hiện, sau đó, nếu thuộc tính không bị ràng buộc, nó sẽ kiểm tra không gian tên của lớp. Đây là thuật toán tra cứu thuộc tính thể hiện được thể hiện bằng Python [N. B. đây là phiên bản đơn giản hóa của thuật toán thực;

      def instlookup[inst, name]:
          # simplified algorithm...
          if inst.__dict__.has_key[name]:
              return inst.__dict__[name]
          else:
              return inst.__class__.__dict__[name]
    

Lưu ý cách chức năng này sẽ đưa ra một ngoại lệ AttributeError nếu thuộc tính không được xác định trong thể hiện cũng như lớp. giống như con trăn

Giả sử chúng ta có điểm Descartes

________số 8

và một chức năng để tính toán khoảng cách của điểm đến gốc

      def distanceToOrigin[p]:
          from math import floor, sqrt
          return floor[sqrt[p[0]**2 + p[1]**2]]
    

Bây giờ trong chương trình của chúng ta, khi thao tác với các điểm, chúng ta chỉ cần gọi hàm

      class foo:
          a, b, c = 0, "bar", [1,2]
    
0

Bây giờ, giả sử chúng ta giới thiệu một loại điểm mới, điểm Manhattan

      class foo:
          a, b, c = 0, "bar", [1,2]
    
1

trong đó có một chức năng khoảng cách khác nhau. Chúng tôi ngay lập tức muốn đổi tên chức năng khoảng cách đầu tiên của mình

      class foo:
          a, b, c = 0, "bar", [1,2]
    
2

để chúng ta có thể xác định phiên bản Manhattan

      class foo:
          a, b, c = 0, "bar", [1,2]
    
3

Điều này minh họa một vấn đề không gian tên. chúng ta nên lưu trữ các hàm Descartes và Manhattan trong các không gian tên khác nhau. Chúng tôi có thể sử dụng các mô-đun của Python cho việc này [cartesian. distanceToOrigin, manhattan. distanceToOrigin], nhưng chúng tôi vẫn gặp sự cố. Làm thế nào để chúng ta biết điểm nào là điểm nào?

      class foo:
          a, b, c = 0, "bar", [1,2]
    
4

[tất nhiên, vì các thuộc tính của đối tượng của chúng tôi được xác định theo vị trí, bây giờ chúng tôi cần mã hóa lại các hàm khoảng cách của mình. nhưng đó không phải là vấn đề chúng tôi đang xem xét. ] và tệ hơn, chúng ta cần viết mã kiểm tra loại ở mọi nơi chúng ta sử dụng điểm

      class foo:
          a, b, c = 0, "bar", [1,2]
    
5

Để giải quyết vấn đề này, chúng tôi có thể viết một hàm distanceToOrigin chung để chúng tôi có thể giữ điều kiện ở một nơi, nhưng chúng tôi vẫn gặp sự cố phải cập nhật điều kiện đó mỗi khi chúng tôi thêm một loại điểm mới. Và nếu tác giả của loại điểm mới không phải là tác giả của hàm chung, thì đó có thể là một vấn đề [tác giả của loại điểm mới có thể thậm chí không biết tất cả các hàm thao tác điểm chung ngoài kia, mỗi . Giải pháp là liên kết các chức năng thao tác từng loại đối tượng với chính đối tượng đó. Các chức năng như vậy được gọi là các phương thức của đối tượng

      class foo:
          a, b, c = 0, "bar", [1,2]
    
6

Bây giờ để tìm khoảng cách đến gốc tọa độ cho bất kỳ loại điểm pt nào, chúng ta không cần điều kiện nữa. mỗi điểm biết cách tính khoảng cách của chính nó. điểm[2][điểm]

      class foo:
          a, b, c = 0, "bar", [1,2]
    
7

Nếu đối tượng mang các chức năng riêng của nó, thì chúng ta không cần điều kiện, cũng như thông tin loại [ít nhất, không phải cho mục đích này] và tác giả của một loại điểm mới không cần thay đổi chức năng chung của người khác

      class foo:
          a, b, c = 0, "bar", [1,2]
    
8

Đây là ý tưởng cơ bản của lập trình hướng đối tượng

Một trong những vấn đề lớn nhất với trình diễn này là việc sử dụng các bộ dữ liệu và lập chỉ mục theo vị trí của chúng. Rõ ràng việc sử dụng từ điển sẽ là một cải tiến lớn

      class foo:
          a, b, c = 0, "bar", [1,2]
    
9

nhưng sử dụng từ điển không cung cấp cho chúng tôi bất kỳ cơ sở tạo khuôn mẫu nào. với từ điển, đối với mỗi điểm chúng tôi xác định, chúng tôi cần sao chép theo định nghĩa của distanceToOrigin. Những gì chúng tôi muốn là các bản ghi của Pascal hoặc các cấu trúc của C và Python có tương đương với những thứ này trong các lớp của nó

      i = foo[]
      print i.a, i.b, i.c
    
0

Điều này tốt hơn rất nhiều, nhưng thật khó chịu khi luôn phải truyền đối tượng cho các phương thức của nó, đặc biệt vì các đối tượng là hạng nhất và có thể là giá trị của các biểu thức phức tạp, e. g

      i = foo[]
      print i.a, i.b, i.c
    
1

Điều này sẽ rất dễ xảy ra lỗi và có khả năng không hiệu quả [do đánh giá lại] đến mức nó sẽ yêu cầu chúng ta luôn gán các biểu thức đối tượng phức tạp cho các biến cục bộ, vì vậy Python sẽ giúp chúng ta giải quyết một chút cú pháp. nếu bạn định nghĩa một hàm trong một lớp, giả định rằng bạn dự định hàm này là một phương thức của lớp và do đó khi bạn gọi một hàm như vậy, Python sẽ ngầm chuyển vào thể hiện dưới dạng tham số đầu tiên. vì vậy cách chính xác để gọi phương thức distanceToOrigin chỉ đơn giản là

      i = foo[]
      print i.a, i.b, i.c
    
2

Bản thân

Thông thường trong Python đặt tên cho tham số đầu tiên của một phương thức là self, e. g

      i = foo[]
      print i.a, i.b, i.c
    
3

Tên này không bắt buộc, nhưng mã của bạn sẽ trông rất lạ đối với các hacker Python khác nếu bạn sử dụng tên khác

Python cho phép bạn tùy chỉnh các đối tượng của mình bằng cách xác định một số phương thức có tên đặc biệt

Phương pháp __init__

      i = foo[]
      print i.a, i.b, i.c
    
4

Các tham số giống như các chức năng thông thường và hỗ trợ tất cả các biến thể. vị trí, mặc định, từ khóa, v.v. Khi một lớp có phương thức __init__, bạn truyền tham số cho lớp khi khởi tạo nó và phương thức __init__ sẽ được gọi với các tham số này. Thông thường, phương thức sẽ đặt các biến thể hiện khác nhau thông qua self

      i = foo[]
      print i.a, i.b, i.c
    
5

Phương pháp __del__

      i = foo[]
      print i.a, i.b, i.c
    
6

Một phương thức __del__ được gọi khi một đối tượng bị xóa, đó là khi bộ thu gom rác quyết định rằng chúng không còn tham chiếu đến một đối tượng nữa. Lưu ý rằng điều này không nhất thiết phải xảy ra khi đối tượng bị xóa rõ ràng bằng câu lệnh del. Phương thức __del__ nhận chính xác một tham số, self. Do sự kỳ lạ trong triển khai C của Python hiện tại, các ngoại lệ bị bỏ qua trong các phương thức __del__. thay vào đó, một lỗi sẽ được in thành lỗi tiêu chuẩn

Phương pháp __repr__

      i = foo[]
      print i.a, i.b, i.c
    
7

Phương thức __repr__ nhận chính xác một tham số, chính nó và phải trả về một chuỗi. Chuỗi này được dự định là một đại diện của đối tượng, phù hợp để hiển thị cho lập trình viên, chẳng hạn như khi làm việc trong trình thông dịch tương tác. __repr__ sẽ được gọi bất cứ khi nào hàm dựng sẵn repr được áp dụng cho một đối tượng;

__str__ Phương pháp

      i = foo[]
      print i.a, i.b, i.c
    
8

Phương thức __str__ hoàn toàn giống như __repr__ ngoại trừ việc nó được gọi khi hàm str dựng sẵn được áp dụng cho một đối tượng; . Nói chung, chuỗi do __str__ trả về dành cho người dùng ứng dụng nhìn thấy, trong khi chuỗi do __repr__ trả về dành cho lập trình viên xem, như trong quá trình gỡ lỗi và phát triển. nhưng không có quy tắc cứng và nhanh về điều này. Tốt nhất bạn chỉ nên suy nghĩ, __str__ cho %s, __repr__ cho trích dẫn ngược

Sử dụng các lớp để định nghĩa các đối tượng cung cấp một cơ sở tạo khuôn mẫu. các thuộc tính và phương thức của lớp chỉ cần được xác định một lần và sau đó bạn có thể khởi tạo bất kỳ số lượng đối tượng nào, tất cả đều chia sẻ cùng một phương thức

Nhưng chúng ta có thể hưởng lợi từ nhiều cơ hội chia sẻ hơn. Rất nhiều lần các lớp của các đối tượng liên quan chỉ khác nhau một chút. Xem xét các định nghĩa đầy đủ về hai loại điểm của chúng tôi

      i = foo[]
      print i.a, i.b, i.c
    
9

Cả hai lớp này đều có chung phương thức __init__, tuy nhiên chúng ta phải viết mã hai lần. Chúng ta có thể giải quyết vấn đề này bằng cách trừu tượng hóa phương thức phổ biến thành một lớp mới, tổng quát hơn được gọi là điểm

      i.a = 12
      i.new = "yikes"        # dynamic attribute creation!
    
0

Bây giờ chúng ta có thể xác định lại cartesian và manhattan và chỉ định rằng chúng kế thừa từ điểm

      i.a = 12
      i.new = "yikes"        # dynamic attribute creation!
    
1

Chúng ta có thể định nghĩa tất cả các hành vi chung cho tất cả các loại điểm trong lớp điểm, sau đó xác định bất kỳ số lớp con nào của điểm kế thừa từ nó. Chúng ta có thể đi xa hơn và định nghĩa các lớp con của cartesian hoặc manhattan nếu điều đó phù hợp

Trong một số ngôn ngữ hướng đối tượng [e. g. , Java], điểm sẽ là một lớp trừu tượng. nói cách khác, một lớp chỉ được sử dụng để kế thừa và không được khởi tạo trực tiếp. Python không tạo ra sự khác biệt này. nếu bạn muốn khởi tạo điểm, hãy tiếp tục

Hãy xem lại cú pháp định nghĩa lớp

      class name[[expr[,expr]*]]:
          suite
    

Như đã đề cập trước đó, mỗi expr, nếu được cung cấp, phải đánh giá một lớp và bây giờ chúng ta biết tại sao. chúng được gọi là các lớp cơ sở và là các lớp mà lớp mới kế thừa từ. Nếu nhiều lớp cơ sở được đưa ra, lớp mới sẽ kế thừa từ tất cả chúng. cái này gọi là đa thừa kế. Xem phần tiếp theo để biết giải thích về cách hoạt động của tham chiếu thuộc tính khi có nhiều kế thừa

Tham chiếu thuộc tính chi tiết

Bây giờ chúng ta có thể giải thích chi tiết tham chiếu thuộc tính lớp và cá thể

Khi tìm kiếm một thuộc tính thông qua một đối tượng lớp C, trước tiên Python tìm kiếm không gian tên của lớp [C. __dict__];

Khi tìm kiếm một thuộc tính thông qua một đối tượng thể hiện i, trước tiên Python tìm kiếm không gian tên của thể hiện [i. __dict__]; . __class__] như được mô tả trong đoạn trước

Dưới đây là các thuật toán hoàn chỉnh để tra cứu thuộc tính lớp và tra cứu thuộc tính thể hiện. Mỗi hàm này trả về 2-tuple có phần tử đầu tiên là giá trị thực cho biết sự thành công của tra cứu và phần tử thứ hai của nó là giá trị của thuộc tính, nếu tra cứu thành công hoặc Không có nếu không

      i.a = 12
      i.new = "yikes"        # dynamic attribute creation!
    
3

Một số ngôn ngữ định hướng B&D ngăn truy cập vào các thuộc tính của một lớp hoặc cá thể, ý tưởng là nếu tác giả của lớp không định nghĩa một phương thức để thao tác một thuộc tính, thì người dùng của cá thể đó không có quyền kiểm tra hoặc thay đổi . Như bạn có thể đã đoán, Python không áp dụng cách tiếp cận này. Cú pháp tham chiếu thuộc tính có thể được sử dụng để truy cập hầu hết các thuộc tính lớp và phiên bản, và các thuộc tính __dict__ cung cấp toàn bộ chương trình. Giả định là bạn biết mình đang làm gì, và nếu bạn muốn tự bắn vào chân mình, đó là chuyện của bạn

Điều đó nói rằng, Python không hỗ trợ xáo trộn tên. nếu một phương thức hoặc tên thuộc tính khác bắt đầu bằng hai dấu gạch dưới ở đầu [e. g. , __secret], Python thay đổi tên một cách kỳ diệu để các tham chiếu đến thuộc tính này được thực hiện theo cách thông thường sẽ không thành công

      i.a = 12
      i.new = "yikes"        # dynamic attribute creation!
    
4

Sự bảo vệ này hoàn toàn mang tính chất tư vấn, tuy nhiên. nếu chúng ta kiểm tra không gian tên lớp, chúng ta có thể thấy Python đang làm gì

      i.a = 12
      i.new = "yikes"        # dynamic attribute creation!
    
5

Tên phương thức đã được thay đổi hoặc đọc sai thành _foo__secret. tôi. e. , bắt đầu bằng dấu gạch dưới và tên lớp. Vì đây là hành vi được ghi lại, nên bạn có thể sử dụng tên này, trực tiếp thông qua __dict__ hoặc chỉ thông qua tham chiếu thuộc tính [foo. _foo__secret], để truy cập thuộc tính

Một thuộc tính quan trọng khác của ngôn ngữ lập trình hướng đối tượng là tính đa hình. khả năng sử dụng cùng một cú pháp cho các đối tượng thuộc các loại khác nhau. [Nói đúng ra, đây là đa hình ad-hoc. ] Ví dụ: trong Python, toán tử dấu ngoặc vuông được sử dụng để thực hiện lập chỉ mục cho các loại trình tự khác nhau [danh sách[3], dict["foo"]]; . g. dấu ngoặc vuông để lập chỉ mục

Tùy chỉnh tham chiếu thuộc tính

Chúng ta sẽ bắt đầu bằng cách chỉ ra cách ghi đè hành vi của toán tử dấu chấm, tham chiếu thuộc tính trong các lớp và cá thể. Bằng cách tùy chỉnh tham chiếu thuộc tính, một đối tượng có thể thực hiện một hành động tùy ý bất cứ khi nào một trong các thuộc tính của nó được tham chiếu, chẳng hạn như kiểm tra kiểu

Phương pháp __getattr__

      i.a = 12
      i.new = "yikes"        # dynamic attribute creation!
    
6

Phương thức này, nếu được xác định, được gọi khi tra cứu thuộc tính không thành công. Ví dụ, hãy xem xét những điều sau đây

      i.a = 12
      i.new = "yikes"        # dynamic attribute creation!
    
7

Vì thuộc tính a là thuộc tính lớp của thể hiện i và thuộc tính b là thuộc tính thể hiện của i, nên phương thức __getattr__ không được gọi khi một trong hai thuộc tính này được truy cập

      i.a = 12
      i.new = "yikes"        # dynamic attribute creation!
    
8

Nhưng nếu chúng ta cố gắng truy cập một thuộc tính không xác định, giả sử c, __getattr__ được gọi, với tên thuộc tính là một tham số

      i.a = 12
      i.new = "yikes"        # dynamic attribute creation!
    
9

Lưu ý rằng __getattr__ sẽ không được gọi nếu tra cứu thuộc tính thành công thông qua kế thừa

Phương thức __getattr__ sẽ trả về một giá trị [thuộc bất kỳ loại nào] hoặc tăng ngoại lệ AttributeError

Phương thức __setattr__

      class foo: pass
      foo.a = 1
      foo.b = 2
    
0

__setattr__ được gọi bất cứ khi nào thử gán thuộc tính, bất kể thuộc tính đó đã được liên kết trong thể hiện hay lớp hay chưa. Điều này xảy ra thay vì cơ chế lưu trữ giá trị bình thường trong từ điển cá thể. Phương pháp này có thể được sử dụng, ví dụ, để thực hiện kiểm tra kiểu trên một giá trị trước khi gán nó

Phương thức __setattr__ không nên cố gắng gán giá trị cho một thuộc tính theo cách thông thường, tôi. e. , bản thân. tên = giá trị, vì điều này sẽ dẫn đến vô số lệnh gọi đệ quy tới __setattr__;

Thuộc tính trong ngôn ngữ lập trình Python là gì?

Để đưa ra định nghĩa cơ bản cho cả hai thuật ngữ, các thuộc tính của lớp là các biến lớp được kế thừa bởi mọi đối tượng của lớp . Giá trị của các thuộc tính lớp vẫn giữ nguyên cho mọi đối tượng mới. Giống như bạn sẽ thấy trong các ví dụ trong phần này, các thuộc tính của lớp được định nghĩa bên ngoài hàm __init__[].

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à thuộc tính trong Python là gì?

Các thuộc tính được mô tả bởi các biến dữ liệu, ví dụ như tên, tuổi, chiều cao, v.v. Thuộc tính là loại thuộc tính đặc biệt có các phương thức getter, setter và delete như các phương thức __get__, __set__ và __delete__

Ba thuộc tính chính của đối tượng Python là gì?

Giải thích. .
loại đối tượng
giá trị của một đối tượng
id của một đối tượng

Chủ Đề