Hướng dẫn how do you represent a point in python? - làm thế nào để bạn đại diện cho một điểm trong python?

7.1. Lập trình hướng đối tượng¶Object-oriented programming¶

Python là ngôn ngữ lập trình hướng đối tượng, có nghĩa là nó cung cấp các tính năng hỗ trợ lập trình hướng đối tượng (OOP).object-oriented programming language, which means that it provides features that support object-oriented programming ( OOP).

Show

Lập trình hướng đối tượng có nguồn gốc từ những năm 1960, nhưng đến giữa những năm 1980, nó trở thành mô hình lập trình chính được sử dụng trong việc tạo ra phần mềm mới. Nó được phát triển như một cách để xử lý kích thước và độ phức tạp tăng nhanh của các hệ thống phần mềm và để giúp việc sửa đổi các hệ thống lớn và phức tạp này theo thời gian dễ dàng hơn.

Cho đến nay chúng tôi đã viết các chương trình bằng cách sử dụng một mô hình lập trình thủ tục. Trong lập trình thủ tục, trọng tâm là viết các chức năng hoặc thủ tục hoạt động trên dữ liệu. Trong lập trình hướng đối tượng, trọng tâm là việc tạo các đối tượng chứa cả dữ liệu và chức năng cùng nhau.objects which contain both data and functionality together.

7.2. Các loại hợp chất do người dùng xác địnhUser-defined compound types¶

Bây giờ chúng tôi sẽ giới thiệu một từ khóa Python mới, lớp, về bản chất xác định một loại dữ liệu mới. Chúng tôi đã sử dụng một số loại tích hợp Python, trong suốt cuốn sách này, giờ đây chúng tôi đã sẵn sàng để tạo loại do người dùng định nghĩa:

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1.class, which in essence defines a new data type. We have been using several of Python’s built-in types throughout this book, we are now ready to create our own user-defined type: the
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1.

Hãy xem xét khái niệm của một điểm toán học. Trong hai chiều, một điểm là hai số (tọa độ) được coi là một đối tượng. Trong ký hiệu toán học, các điểm thường được viết theo dấu ngoặc đơn với dấu phẩy ngăn cách tọa độ. Ví dụ,

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
2 đại diện cho nguồn gốc và
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
3 đại diện cho điểm
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
4 đơn vị ở bên phải và
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
5 đơn vị tăng từ gốc.

Một cách tự nhiên để thể hiện một điểm trong Python là với hai giá trị số. Sau đó, câu hỏi là làm thế nào để nhóm hai giá trị này thành một đối tượng ghép. Giải pháp nhanh chóng và bẩn là sử dụng danh sách hoặc tuple, và đối với một số ứng dụng có thể là lựa chọn tốt nhất.

Một giải pháp thay thế là xác định một loại hợp chất do người dùng xác định mới, được gọi là một lớp. Cách tiếp cận này liên quan đến nỗ lực hơn một chút, nhưng nó có những lợi thế sẽ sớm rõ ràng.class. This approach involves a bit more effort, but it has advantages that will be apparent soon.

Một định nghĩa lớp trông như thế này:

Các định nghĩa của lớp có thể xuất hiện ở bất cứ đâu trong một chương trình, nhưng chúng thường ở gần đầu (sau các câu lệnh

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
6). Các quy tắc cú pháp cho một định nghĩa lớp giống như đối với các câu lệnh ghép khác. Có một tiêu đề bắt đầu bằng từ khóa,
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
7, theo sau là tên của lớp và kết thúc bằng một dấu hai chấm.

Định nghĩa này tạo ra một lớp mới gọi là

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1. Tuyên bố vượt qua không có hiệu lực; Nó chỉ cần thiết bởi vì một tuyên bố ghép phải có một cái gì đó trong cơ thể của nó. Một tài liệu có thể phục vụ cùng một mục đích:pass statement has no effect; it is only necessary because a compound statement must have something in its body. A docstring could serve the same purpose:

class Point:
    "Point class for storing mathematical points."

Bằng cách tạo lớp

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1, chúng tôi đã tạo một loại mới, còn được gọi là
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1. Các thành viên của loại này được gọi là các thể hiện của loại hoặc đối tượng. Tạo một thể hiện mới được gọi là khởi tạo và được thực hiện bằng cách gọi lớp. Các lớp, như các chức năng, có thể gọi được và chúng tôi khởi tạo một đối tượng
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1 bằng cách gọi lớp
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1:instances of the type or objects. Creating a new instance is called instantiation, and is accomplished by calling the class. Classes, like functions, are callable, and we instantiate a
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1 object by calling the
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1 class:

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>

Biến

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

    def distance_from_origin(self):
        return ((self.x ** 2) + (self.y ** 2)) ** 0.5
3 được gán một tham chiếu đến một đối tượng
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1 mới.

Có thể hữu ích khi nghĩ về một lớp như một nhà máy để tạo ra các đối tượng, vì vậy lớp

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1 của chúng tôi là một nhà máy để tạo điểm. Bản thân lớp học không phải là một ví dụ của một điểm, nhưng nó chứa máy móc để thực hiện các trường hợp điểm.

7.3. Thuộc tính¶Attributes¶

Giống như các đối tượng trong thế giới thực, các trường hợp đối tượng có cả hình thức và chức năng. Biểu mẫu bao gồm các yếu tố dữ liệu có trong trường hợp.

Chúng ta có thể thêm các thành phần dữ liệu mới vào một thể hiện bằng ký hiệu DOT:dot notation:

Cú pháp này tương tự như cú pháp để chọn một biến từ một mô -đun, chẳng hạn như

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

    def distance_from_origin(self):
        return ((self.x ** 2) + (self.y ** 2)) ** 0.5
6 hoặc
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def distance_from_origin(self):
        return ((self.x ** 2) + (self.y ** 2)) ** 0.5
7. Cả hai mô -đun và phiên bản đều tạo ra các không gian tên của riêng chúng và cú pháp để truy cập các tên có trong mỗi tên, được gọi là thuộc tính, là như nhau. Trong trường hợp này, thuộc tính chúng tôi đang chọn là một mục dữ liệu từ một thể hiện.attributes, is the same. In this case the attribute we are selecting is a data item from an instance.

Biểu đồ trạng thái sau đây cho thấy kết quả của các bài tập sau:

Hướng dẫn how do you represent a point in python? - làm thế nào để bạn đại diện cho một điểm trong python?

Biến

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

    def distance_from_origin(self):
        return ((self.x ** 2) + (self.y ** 2)) ** 0.5
3 đề cập đến một đối tượng điểm, chứa hai thuộc tính. Mỗi thuộc tính đề cập đến một số.

Chúng ta có thể đọc giá trị của một thuộc tính bằng cách sử dụng cùng một cú pháp:

>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3

Biểu thức

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

    def distance_from_origin(self):
        return ((self.x ** 2) + (self.y ** 2)) ** 0.5
9 có nghĩa là, Đi đến đối tượng
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def distance_from_origin(self):
        return ((self.x ** 2) + (self.y ** 2)) ** 0.5
3 đề cập đến và nhận giá trị của
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
4. Trong trường hợp này, chúng tôi gán giá trị đó cho một biến có tên
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
4. Không có xung đột giữa biến
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
4 và thuộc tính
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
4. Mục đích của ký hiệu DOT là xác định biến nào bạn đang đề cập đến rõ ràng.

Bạn có thể sử dụng ký hiệu DOT như một phần của bất kỳ biểu thức nào, vì vậy các câu sau đây là hợp pháp:

print('({0}, {1})'.format(p.x, p.y))
distance_squared = p.x * p.x + p.y * p.y

Dòng đầu ra đầu ra

>>> p = Point(3, 4)
>>> p.x
3
>>> p.y
4
>>> p.distance_from_origin()
5.0
>>> q = Point(5, 12)
>>> q.x
5
>>> q.y
12
>>> q.distance_from_origin()
13.0
>>> r = Point(0, 0)
>>> r.x
0
>>> r.y
0
>>> r.distance_from_origin()
0.0
5; Dòng thứ hai tính toán giá trị 25.

7.4. Phương pháp khởi tạo và ________ 76¶The initialization method and >>> p = Point(3, 4) >>> p.x 3 >>> p.y 4 >>> p.distance_from_origin() 5.0 >>> q = Point(5, 12) >>> q.x 5 >>> q.y 12 >>> q.distance_from_origin() 13.0 >>> r = Point(0, 0) >>> r.x 0 >>> r.y 0 >>> r.distance_from_origin() 0.0 6¶

Vì lớp

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1 của chúng tôi nhằm thể hiện hai điểm toán học hai chiều, tất cả các trường hợp điểm phải có các thuộc tính
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
4 và
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
5, nhưng điều đó chưa được như vậy với các đối tượng
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1 của chúng tôi.

>>> p2 = Point()
>>> p2.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Point' object has no attribute 'x'
>>>

Để giải quyết vấn đề này, chúng tôi thêm một phương thức khởi tạo vào lớp của chúng tôi.initialization method to our class.

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

Một phương pháp hoạt động giống như một hàm nhưng nó là một phần của một đối tượng. Giống như một thuộc tính dữ liệu, nó được truy cập bằng ký hiệu DOT.method behaves like a function but it is part of an object. Like a data attribute it is accessed using dot notation.

Phương thức khởi tạo là một phương thức đặc biệt được gọi tự động khi một đối tượng được tạo bằng cách gọi lớp. Tên của phương pháp này là

def print_point(p):
    print('({0}, {1})'.format(p.x, p.y))
1 (hai ký tự dấu gạch dưới, theo sau là
def print_point(p):
    print('({0}, {1})'.format(p.x, p.y))
2, và sau đó là hai dấu gạch dưới). Tên này phải được sử dụng để biến một phương thức thành một phương thức khởi tạo trong Python.

Không có xung đột giữa thuộc tính

def print_point(p):
    print('({0}, {1})'.format(p.x, p.y))
3 và tham số
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
4. Ký hiệu DOT chỉ định biến mà chúng tôi đang đề cập đến.

Hãy để thêm một phương pháp khác,

def print_point(p):
    print('({0}, {1})'.format(p.x, p.y))
5, để xem cách tốt hơn cách thức hoạt động:

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

    def distance_from_origin(self):
        return ((self.x ** 2) + (self.y ** 2)) ** 0.5

Hãy để tạo ra một vài trường hợp điểm, nhìn vào các thuộc tính của chúng và gọi phương thức mới của chúng tôi trên chúng:

>>> p = Point(3, 4)
>>> p.x
3
>>> p.y
4
>>> p.distance_from_origin()
5.0
>>> q = Point(5, 12)
>>> q.x
5
>>> q.y
12
>>> q.distance_from_origin()
13.0
>>> r = Point(0, 0)
>>> r.x
0
>>> r.y
0
>>> r.distance_from_origin()
0.0

Khi xác định một phương thức, tham số đầu tiên đề cập đến thể hiện được tạo. Đó là thông lệ để đặt tên cho tham số này tự. Trong phiên ví dụ ở trên, tham số

>>> p = Point(3, 4)
>>> p.x
3
>>> p.y
4
>>> p.distance_from_origin()
5.0
>>> q = Point(5, 12)
>>> q.x
5
>>> q.y
12
>>> q.distance_from_origin()
13.0
>>> r = Point(0, 0)
>>> r.x
0
>>> r.y
0
>>> r.distance_from_origin()
0.0
6 đề cập đến các trường hợp
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def distance_from_origin(self):
        return ((self.x ** 2) + (self.y ** 2)) ** 0.5
3,
def print_point(p):
    print('({0}, {1})'.format(p.x, p.y))
8 và
def print_point(p):
    print('({0}, {1})'.format(p.x, p.y))
9 tương ứng.self. In the example session above, the
>>> p = Point(3, 4)
>>> p.x
3
>>> p.y
4
>>> p.distance_from_origin()
5.0
>>> q = Point(5, 12)
>>> q.x
5
>>> q.y
12
>>> q.distance_from_origin()
13.0
>>> r = Point(0, 0)
>>> r.x
0
>>> r.y
0
>>> r.distance_from_origin()
0.0
6 parameter refers to the instances
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def distance_from_origin(self):
        return ((self.x ** 2) + (self.y ** 2)) ** 0.5
3,
def print_point(p):
    print('({0}, {1})'.format(p.x, p.y))
8, and
def print_point(p):
    print('({0}, {1})'.format(p.x, p.y))
9 respectively.

7.5. Các thể hiện dưới dạng tham sốInstances as parameters¶

Bạn có thể chuyển một thể hiện dưới dạng tham số cho một hàm theo cách thông thường. Ví dụ:

def print_point(p):
    print('({0}, {1})'.format(p.x, p.y))

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

    def distance_from_origin(self):
        return ((self.x ** 2) + (self.y ** 2)) ** 0.5

    def print_point(self):
        print('({0}, {1})'.format(self.x, self.y))
0 lấy một điểm làm đối số và hiển thị nó ở định dạng tiêu chuẩn. Nếu bạn gọi
class Point:
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    def distance_from_origin(self):
        return ((self.x ** 2) + (self.y ** 2)) ** 0.5

    def print_point(self):
        print('({0}, {1})'.format(self.x, self.y))
1 với điểm
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def distance_from_origin(self):
        return ((self.x ** 2) + (self.y ** 2)) ** 0.5
3 như được định nghĩa trước đó, đầu ra là
>>> p = Point(3, 4)
>>> p.x
3
>>> p.y
4
>>> p.distance_from_origin()
5.0
>>> q = Point(5, 12)
>>> q.x
5
>>> q.y
12
>>> q.distance_from_origin()
13.0
>>> r = Point(0, 0)
>>> r.x
0
>>> r.y
0
>>> r.distance_from_origin()
0.0
5.

Để chuyển đổi

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

    def distance_from_origin(self):
        return ((self.x ** 2) + (self.y ** 2)) ** 0.5

    def print_point(self):
        print('({0}, {1})'.format(self.x, self.y))
0 thành phương thức, hãy làm như sau:

  1. Thụt ý định định nghĩa chức năng sao cho nó ở bên trong định nghĩa lớp.

  2. Đổi tên tham số thành

    >>> p = Point(3, 4)
    >>> p.x
    3
    >>> p.y
    4
    >>> p.distance_from_origin()
    5.0
    >>> q = Point(5, 12)
    >>> q.x
    5
    >>> q.y
    12
    >>> q.distance_from_origin()
    13.0
    >>> r = Point(0, 0)
    >>> r.x
    0
    >>> r.y
    0
    >>> r.distance_from_origin()
    0.0
    
    6.

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

    def distance_from_origin(self):
        return ((self.x ** 2) + (self.y ** 2)) ** 0.5

    def print_point(self):
        print('({0}, {1})'.format(self.x, self.y))

Bây giờ chúng ta có thể gọi phương thức bằng cách sử dụng ký hiệu DOT.

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
0

Đối tượng mà phương thức được gọi được gán cho tham số đầu tiên, vì vậy trong trường hợp này

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

    def distance_from_origin(self):
        return ((self.x ** 2) + (self.y ** 2)) ** 0.5
3 được gán cho tham số
>>> p = Point(3, 4)
>>> p.x
3
>>> p.y
4
>>> p.distance_from_origin()
5.0
>>> q = Point(5, 12)
>>> q.x
5
>>> q.y
12
>>> q.distance_from_origin()
13.0
>>> r = Point(0, 0)
>>> r.x
0
>>> r.y
0
>>> r.distance_from_origin()
0.0
6. Theo quy ước, tham số đầu tiên của phương thức được gọi là
>>> p = Point(3, 4)
>>> p.x
3
>>> p.y
4
>>> p.distance_from_origin()
5.0
>>> q = Point(5, 12)
>>> q.x
5
>>> q.y
12
>>> q.distance_from_origin()
13.0
>>> r = Point(0, 0)
>>> r.x
0
>>> r.y
0
>>> r.distance_from_origin()
0.0
6. Lý do cho điều này là một chút phức tạp, nhưng nó dựa trên một phép ẩn dụ hữu ích.

Cú pháp cho một cuộc gọi chức năng,

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

    def distance_from_origin(self):
        return ((self.x ** 2) + (self.y ** 2)) ** 0.5

    def print_point(self):
        print('({0}, {1})'.format(self.x, self.y))
1, cho thấy rằng hàm là tác nhân hoạt động. Nó nói một cái gì đó như, hey
class Point:
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    def distance_from_origin(self):
        return ((self.x ** 2) + (self.y ** 2)) ** 0.5

    def print_point(self):
        print('({0}, {1})'.format(self.x, self.y))
0! Ở đây, một đối tượng để bạn in.

Trong lập trình hướng đối tượng, các đối tượng là các tác nhân hoạt động. Một lời cầu khẩn như

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
01 nói Hey
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def distance_from_origin(self):
        return ((self.x ** 2) + (self.y ** 2)) ** 0.5
3! Hãy in chính mình!

Sự thay đổi trong quan điểm này có thể lịch sự hơn, nhưng không rõ ràng là nó hữu ích. Trong các ví dụ chúng ta đã thấy cho đến nay, nó có thể không. Nhưng đôi khi chuyển trách nhiệm từ các chức năng vào các đối tượng giúp bạn có thể viết các chức năng linh hoạt hơn và giúp việc duy trì và sử dụng lại mã dễ dàng hơn.

7.6. Các tính năng hướng đối tượngObject-oriented features¶

Không dễ để xác định lập trình hướng đối tượng, nhưng chúng tôi đã thấy một số đặc điểm của nó:

  1. Các chương trình được tạo thành từ các định nghĩa lớp có chứa các thuộc tính có thể là dữ liệu (biến thể hiện) hoặc hành vi (phương thức).

  2. Mỗi định nghĩa đối tượng tương ứng với một số đối tượng hoặc khái niệm trong thế giới thực và các hàm hoạt động trên đối tượng đó tương ứng với các cách các đối tượng trong thế giới thực tương tác.

  3. Hầu hết các tính toán được thể hiện dưới dạng hoạt động trên các đối tượng.

Ví dụ, lớp

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1 tương ứng với khái niệm toán học của một điểm.

7.7. Thời gian¶Time¶

Như một ví dụ khác về loại do người dùng xác định, chúng tôi sẽ xác định một lớp gọi là

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
04 ghi lại thời gian trong ngày. Vì thời gian sẽ cần nhiều giờ, phút và các thuộc tính thứ hai, chúng tôi sẽ bắt đầu với một phương thức khởi tạo tương tự như phương pháp chúng tôi tạo cho các điểm.

Định nghĩa lớp trông như thế này:

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
1

Khi chúng tôi gọi lớp

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
04, các đối số chúng tôi cung cấp được chuyển đến
def print_point(p):
    print('({0}, {1})'.format(p.x, p.y))
2:

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
2

Dưới đây là phương thức

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
07 cho các đối tượng
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
04 của chúng tôi sử dụng chuỗi hình thành để hiển thị phút và giây với hai chữ số.

Để tiết kiệm không gian, chúng tôi sẽ bỏ phương thức khởi tạo, nhưng bạn nên bao gồm nó:

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
3

mà bây giờ chúng ta có thể gọi các trường hợp theo thời gian theo cách thông thường:

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
4

7.8. Đối số tùy chọnOptional arguments¶

Chúng tôi đã thấy các chức năng tích hợp có một số lượng đối số khác nhau. Ví dụ,

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
09 có thể mất hai, ba hoặc bốn đối số.

Có thể viết các chức năng do người dùng xác định với danh sách đối số tùy chọn. Ví dụ: chúng tôi có thể nâng cấp phiên bản

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
10 của riêng mình để làm điều tương tự như
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
09.

Đây là phiên bản gốc:

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
5

Đây là phiên bản mới và được cải tiến:

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
6

Tham số thứ ba,

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
12, là tùy chọn vì giá trị mặc định,
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
13, được cung cấp. Nếu chúng tôi gọi
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
10 chỉ với hai đối số, chúng tôi sử dụng giá trị mặc định và bắt đầu từ đầu chuỗi:

Nếu chúng tôi cung cấp tham số thứ ba, nó sẽ ghi đè mặc định:overrides the default:

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
7

Chúng tôi có thể viết lại phương thức khởi tạo của mình cho lớp

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
04 để
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
16,
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
17 và
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
18 là mỗi đối số tùy chọn.

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
8

Khi chúng ta khởi tạo một đối tượng

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
04, chúng ta có thể truyền các giá trị cho ba tham số, như chúng ta đã làm với

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
9

Vì các tham số hiện là tùy chọn, tuy nhiên, chúng ta có thể bỏ qua chúng:

>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
0

Hoặc chỉ cung cấp tham số đầu tiên:

>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
1

Hoặc hai tham số đầu tiên:

>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
2

Cuối cùng, chúng tôi có thể cung cấp một tập hợp con của các tham số bằng cách đặt tên chúng một cách rõ ràng:

>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
3

7.9. Một phương pháp khác¶Another method¶

Hãy để thêm một phương thức

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
20, điều này tăng một thể hiện thời gian theo một số giây nhất định. Để tiết kiệm không gian, chúng tôi sẽ tiếp tục bỏ qua các phương thức được xác định trước đó, nhưng bạn phải luôn giữ chúng trong phiên bản của mình:

>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
4

Bây giờ chúng ta có thể gọi

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
20 trên một trường hợp thời gian.

>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
5

Một lần nữa, đối tượng mà phương thức được gọi được gán cho tham số đầu tiên,

>>> p = Point(3, 4)
>>> p.x
3
>>> p.y
4
>>> p.distance_from_origin()
5.0
>>> q = Point(5, 12)
>>> q.x
5
>>> q.y
12
>>> q.distance_from_origin()
13.0
>>> r = Point(0, 0)
>>> r.x
0
>>> r.y
0
>>> r.distance_from_origin()
0.0
6. Tham số thứ hai,
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
18 nhận được giá trị
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
24.

7.10. Một ví dụ với hai ____ 104S¶An example with two >>> type(Point) <class 'type'> >>> p = Point() >>> type(p) <class '__main__.Point'> 04s¶

Hãy để thêm một phương thức Boolen,

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
26, mất hai trường hợp thời gian và trả về
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
27 khi phương pháp đầu tiên là theo trình tự thời gian sau lần thứ hai.

Chúng ta chỉ có thể chuyển đổi một trong các tham số thành

>>> p = Point(3, 4)
>>> p.x
3
>>> p.y
4
>>> p.distance_from_origin()
5.0
>>> q = Point(5, 12)
>>> q.x
5
>>> q.y
12
>>> q.distance_from_origin()
13.0
>>> r = Point(0, 0)
>>> r.x
0
>>> r.y
0
>>> r.distance_from_origin()
0.0
6; cái khác chúng tôi sẽ gọi
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
29 và nó sẽ phải là một tham số của phương thức.

>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
6

Chúng tôi gọi phương thức này trên một đối tượng và chuyển sang đối tượng khác như một đối số:

>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
7

Bạn gần như có thể đọc lời mời như tiếng Anh: Nếu Time1 là sau thời gian2, thì

7.10.1. Các chức năng và sửa đổi thuần túy (một lần nữa)Pure functions and modifiers (again)¶

Trong một vài phần tiếp theo, chúng tôi sẽ viết hai phiên bản của một hàm gọi là

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
30, tính toán tổng của hai
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
04S. Họ sẽ chứng minh hai loại chức năng: các chức năng và sửa đổi thuần túy, mà trước tiên chúng tôi gặp phải trong chương chức năng.Functions chapter.

Sau đây là phiên bản sơ bộ của

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
30:

>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
8

Hàm tạo ra một đối tượng

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
04 mới, khởi tạo các thuộc tính của nó và trả về một tham chiếu đến đối tượng mới. Điều này được gọi là hàm thuần túy vì nó không sửa đổi bất kỳ đối tượng nào được truyền cho nó dưới dạng tham số và nó không có tác dụng phụ, chẳng hạn như hiển thị giá trị hoặc nhận đầu vào của người dùng.pure function because it does not modify any of the objects passed to it as parameters and it has no side effects, such as displaying a value or getting user input.

Dưới đây là một ví dụ về cách sử dụng chức năng này. Chúng tôi sẽ tạo hai đối tượng

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
04:
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
35, chứa thời gian hiện tại; và
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
36, trong đó chứa lượng thời gian cần thiết để một thợ làm bánh mì làm bánh mì. Sau đó, chúng tôi sẽ sử dụng
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
30 để tìm ra khi nào bánh mì sẽ được thực hiện. Nếu bạn đã viết xong
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
07, hãy nhìn về phía trước trước khi bạn thử điều này:

>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
9

Đầu ra của chương trình này là

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
39, điều này là chính xác. Mặt khác, có những trường hợp kết quả không chính xác. Bạn có thể nghĩ về một?

Vấn đề là chức năng này không giải quyết các trường hợp trong đó số giây hoặc phút tăng lên đến hơn sáu mươi. Khi điều đó xảy ra, chúng ta phải mang thêm giây vào cột phút hoặc thêm phút vào cột giờ.

Ở đây, một phiên bản sửa chữa thứ hai của chức năng:

print('({0}, {1})'.format(p.x, p.y))
distance_squared = p.x * p.x + p.y * p.y
0

Mặc dù chức năng này là chính xác, nó bắt đầu trở nên lớn. Sau đó, chúng tôi sẽ đề xuất một cách tiếp cận thay thế mang lại mã ngắn hơn.

7.10.2. Người sửa đổiModifiers¶

Có những lúc nó hữu ích cho một hàm để sửa đổi một hoặc nhiều đối tượng mà nó nhận được là tham số. Thông thường, người gọi giữ một tham chiếu đến các đối tượng mà nó đi qua, do đó, bất kỳ thay đổi nào mà hàm thực hiện đều có thể nhìn thấy cho người gọi. Các chức năng hoạt động theo cách này được gọi là sửa đổi.modifiers.

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
20, trong đó thêm một số giây nhất định vào đối tượng
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
04, sẽ được viết một cách tự nhiên nhất là một công cụ sửa đổi. Một bản nháp thô của chức năng trông như thế này:

print('({0}, {1})'.format(p.x, p.y))
distance_squared = p.x * p.x + p.y * p.y
1

Dòng đầu tiên thực hiện hoạt động cơ bản; Phần còn lại liên quan đến các trường hợp đặc biệt mà chúng tôi đã thấy trước đây.

Chức năng này có đúng không? Điều gì xảy ra nếu tham số

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
18 lớn hơn nhiều so với sáu mươi? Trong trường hợp đó, nó không đủ để mang theo một lần; Chúng ta phải tiếp tục làm điều đó cho đến khi
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
18 ít hơn sáu mươi. Một giải pháp là thay thế các câu lệnh
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
44 bằng các câu lệnh
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
45:

print('({0}, {1})'.format(p.x, p.y))
distance_squared = p.x * p.x + p.y * p.y
2

Hàm này bây giờ là chính xác, nhưng nó không phải là giải pháp hiệu quả nhất.

7.11. Phát triển nguyên mẫu so với kế hoạchPrototype development versus planning¶

Cho đến nay trong chương này, chúng tôi đã sử dụng một cách tiếp cận để phát triển chương trình mà chúng tôi sẽ gọi là phát triển nguyên mẫu. Chúng tôi đã viết một bản nháp thô (hoặc nguyên mẫu) thực hiện tính toán cơ bản và sau đó thử nghiệm nó trên một vài trường hợp, sửa lỗi khi chúng tôi tìm thấy chúng.prototype development. We wrote a rough draft (or prototype) that performed the basic calculation and then tested it on a few cases, correcting flaws as we found them.

Mặc dù cách tiếp cận này có thể có hiệu quả, nhưng nó có thể dẫn đến mã phức tạp không cần thiết - vì nó liên quan đến nhiều trường hợp đặc biệt - và không đáng tin cậy - vì khó có thể biết nếu chúng tôi đã tìm thấy tất cả các lỗi.

Một giải pháp thay thế được lên kế hoạch phát triển, trong đó cái nhìn sâu sắc cấp cao về vấn đề có thể giúp chương trình dễ dàng hơn nhiều. Trong trường hợp này, cái nhìn sâu sắc là một đối tượng

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
04 thực sự là một số ba chữ số trong cơ sở 60! Thành phần
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
47 là cột, thành phần
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
48 là cột Sixties và thành phần
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
49 là cột ba mươi sáu trăm.planned development, in which high-level insight into the problem can make the programming much easier. In this case, the insight is that a
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
04 object is really a three-digit number in base 60! The
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
47 component is the ones column, the
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
48 component is the sixties column, and the
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
49 component is the thirty-six hundreds column.

Khi chúng tôi viết

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
30 và
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
20, chúng tôi đã thực hiện bổ sung trong cơ sở 60, đó là lý do tại sao chúng tôi phải mang từ cột này sang cột tiếp theo.

Quan sát này cho thấy một cách tiếp cận khác cho toàn bộ vấn đề - chúng ta có thể chuyển đổi đối tượng

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
04 thành một số duy nhất và tận dụng thực tế là máy tính biết cách thực hiện số học với các số. Hàm sau đây chuyển đổi đối tượng
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
04 thành một số nguyên:

print('({0}, {1})'.format(p.x, p.y))
distance_squared = p.x * p.x + p.y * p.y
3

Bây giờ, tất cả những gì chúng ta cần là một cách để chuyển đổi từ một số nguyên sang đối tượng

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
04:

print('({0}, {1})'.format(p.x, p.y))
distance_squared = p.x * p.x + p.y * p.y
4

Bạn có thể phải suy nghĩ một chút để thuyết phục bản thân rằng kỹ thuật này để chuyển đổi từ cơ sở này sang cơ sở khác là chính xác. Giả sử bạn bị thuyết phục, bạn có thể sử dụng các chức năng này để viết lại

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
30:

print('({0}, {1})'.format(p.x, p.y))
distance_squared = p.x * p.x + p.y * p.y
5

Phiên bản này ngắn hơn nhiều so với bản gốc và việc chứng minh rằng nó là chính xác hơn nhiều (giả sử, như thường lệ, các chức năng mà nó gọi là chính xác).

7.12. Sự khái quát¶Generalization¶

Trong một số cách, việc chuyển đổi từ cơ sở 60 thành cơ sở 10 và trở lại khó hơn là chỉ xử lý thời gian. Chuyển đổi cơ sở là trừu tượng hơn; Trực giác của chúng tôi để đối phó với thời gian là tốt hơn.

Nhưng nếu chúng ta có cái nhìn sâu sắc để coi thời gian là số 60 và đầu tư viết các chức năng chuyển đổi (

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
56 và
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
57), chúng ta sẽ có một chương trình ngắn hơn, dễ đọc và gỡ lỗi hơn và đáng tin cậy hơn.

Nó cũng dễ dàng hơn để thêm các tính năng sau này. Ví dụ, hãy tưởng tượng trừ hai

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
04 để tìm thời gian giữa chúng. Cách tiếp cận ngây thơ sẽ là thực hiện phép trừ với vay. Sử dụng các chức năng chuyển đổi sẽ dễ dàng hơn và nhiều khả năng là chính xác.

Trớ trêu thay, đôi khi làm cho một vấn đề khó khăn hơn (hoặc tổng quát hơn) làm cho nó dễ dàng hơn (bởi vì có ít trường hợp đặc biệt hơn và ít cơ hội hơn cho lỗi).

7.13. Thuật toánAlgorithms¶

Khi bạn viết một giải pháp chung cho một lớp các vấn đề, trái ngược với một giải pháp cụ thể cho một vấn đề duy nhất, bạn đã viết một thuật toán. Chúng tôi đã đề cập đến từ này trước đây nhưng không định nghĩa nó một cách cẩn thận. Không dễ để xác định, vì vậy chúng tôi sẽ thử một vài cách tiếp cận.algorithm. We mentioned this word before but did not define it carefully. It is not easy to define, so we will try a couple of approaches.

Đầu tiên, hãy xem xét một cái gì đó không phải là một thuật toán. Khi bạn học cách nhân các số một chữ số, có lẽ bạn đã ghi nhớ bảng nhân. Trong thực tế, bạn đã ghi nhớ 100 giải pháp cụ thể. Loại kiến ​​thức đó không phải là thuật toán.

Nhưng nếu bạn lười biếng, có lẽ bạn đã lừa dối bằng cách học một vài thủ thuật. Ví dụ: để tìm sản phẩm của

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
59 và 9, bạn có thể viết
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
60 dưới dạng chữ số đầu tiên và
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
61 là chữ số thứ hai. Thủ thuật này là một giải pháp chung để nhân bất kỳ số một chữ số nào với 9. Đó là một thuật toán!

Tương tự, các kỹ thuật bạn đã học để bổ sung với việc mang theo, trừ với vay và phân chia dài đều là tất cả các thuật toán. Một trong những đặc điểm của thuật toán là chúng không yêu cầu bất kỳ trí thông minh nào để thực hiện. Chúng là các quy trình cơ học trong đó mỗi bước theo sau từ cuối cùng theo một bộ quy tắc đơn giản.

Theo tôi, thật đáng xấu hổ khi con người dành quá nhiều thời gian cho trường học để thực hiện các thuật toán, theo nghĩa đen, không đòi hỏi trí thông minh.

Mặt khác, quá trình thiết kế các thuật toán là thú vị, thách thức trí tuệ và là một phần trung tâm của những gì chúng ta gọi là lập trình.

Một số điều mà mọi người làm một cách tự nhiên, không gặp khó khăn hoặc suy nghĩ có ý thức, là khó nhất để diễn đạt thuật toán. Hiểu ngôn ngữ tự nhiên là một ví dụ tốt. Tất cả chúng ta đều làm điều đó, nhưng cho đến nay không ai có thể giải thích cách chúng ta làm điều đó, ít nhất là không ở dạng thuật toán.

7.14. Điểm được xem xét lạiPoints revisited¶

Hãy để viết lại lớp

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1 theo kiểu hướng đối tượng hơn:

print('({0}, {1})'.format(p.x, p.y))
distance_squared = p.x * p.x + p.y * p.y
6

Phương thức tiếp theo,

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
63, trả về một biểu diễn chuỗi của đối tượng
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1. Nếu một lớp cung cấp một phương thức có tên
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
63, nó sẽ ghi đè hành vi mặc định của hàm
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
66 tích hợp Python.

print('({0}, {1})'.format(p.x, p.y))
distance_squared = p.x * p.x + p.y * p.y
7

In một đối tượng

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1 hoàn toàn gọi
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
63 trên đối tượng, do đó, xác định
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
63 cũng thay đổi hành vi của
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
70:

print('({0}, {1})'.format(p.x, p.y))
distance_squared = p.x * p.x + p.y * p.y
8

Khi chúng tôi viết một lớp mới, chúng tôi hầu như luôn bắt đầu bằng cách viết

def print_point(p):
    print('({0}, {1})'.format(p.x, p.y))
1, điều này giúp dễ dàng khởi tạo các đối tượng và
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
63, hầu như luôn hữu ích cho việc gỡ lỗi.

7.15. Người vận hành quá tảiOperator overloading¶

Một số ngôn ngữ cho phép thay đổi định nghĩa của các toán tử tích hợp khi chúng được áp dụng cho các loại do người dùng xác định. Tính năng này được gọi là quá tải toán tử. Nó đặc biệt hữu ích khi xác định các loại toán học mới.operator overloading. It is especially useful when defining new mathematical types.

Ví dụ: để ghi đè người vận hành bổ sung

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
73, chúng tôi cung cấp một phương thức có tên
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
74:

print('({0}, {1})'.format(p.x, p.y))
distance_squared = p.x * p.x + p.y * p.y
9

Như thường lệ, tham số đầu tiên là đối tượng mà phương thức được gọi. Tham số thứ hai được đặt tên thuận tiện

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
29 để phân biệt nó với
>>> p = Point(3, 4)
>>> p.x
3
>>> p.y
4
>>> p.distance_from_origin()
5.0
>>> q = Point(5, 12)
>>> q.x
5
>>> q.y
12
>>> q.distance_from_origin()
13.0
>>> r = Point(0, 0)
>>> r.x
0
>>> r.y
0
>>> r.distance_from_origin()
0.0
6. Để thêm hai
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1, chúng tôi tạo và trả về một
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1 mới chứa tổng tọa độ
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
4 và tổng của tọa độ
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
5.

Bây giờ, khi chúng tôi áp dụng toán tử

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
73 cho các đối tượng
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1, Python sẽ gọi
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
74:

>>> p2 = Point()
>>> p2.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Point' object has no attribute 'x'
>>>
0

Biểu thức

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
84 tương đương với
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
85, nhưng rõ ràng thanh lịch hơn. Là một bài tập, thêm một phương thức
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
86 làm quá tải toán tử trừ và thử nó. Có một số cách để ghi đè hành vi của toán tử nhân: bằng cách xác định một phương thức có tên
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
87 hoặc
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
88 hoặc cả hai.

Nếu toán hạng bên trái của

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
89 là
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1, Python sẽ gọi
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
87, giả định rằng toán hạng khác cũng là một
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1. Nó tính toán sản phẩm DOT của hai điểm, được xác định theo các quy tắc của đại số tuyến tính:dot product of the two points, defined according to the rules of linear algebra:

>>> p2 = Point()
>>> p2.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Point' object has no attribute 'x'
>>>
1

Nếu toán hạng bên trái của

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
89 là loại nguyên thủy và toán hạng bên phải là
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1, Python sẽ gọi
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
88, thực hiện phép nhân vô hướng:scalar multiplication:

>>> p2 = Point()
>>> p2.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Point' object has no attribute 'x'
>>>
2

Kết quả là một

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1 mới có tọa độ là bội số của tọa độ ban đầu. Nếu
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
29 là một loại không thể nhân với số điểm nổi, thì
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
88 sẽ gây ra lỗi.

Ví dụ này cho thấy cả hai loại nhân:

>>> p2 = Point()
>>> p2.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Point' object has no attribute 'x'
>>>
3

Điều gì xảy ra nếu chúng ta cố gắng đánh giá

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
99? Vì tham số đầu tiên là
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1, Python gọi
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
87 với
>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
02 làm đối số thứ hai. Bên trong
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
87, chương trình cố gắng truy cập tọa độ
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
4 của
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
29, không thành công vì số nguyên không có thuộc tính:

>>> p2 = Point()
>>> p2.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Point' object has no attribute 'x'
>>>
4

Thật không may, thông báo lỗi là một chút mờ đục. Ví dụ này cho thấy một số khó khăn của lập trình hướng đối tượng. Đôi khi nó đủ khó chỉ để tìm ra mã nào đang chạy.

Để biết ví dụ đầy đủ hơn về quá tải toán tử, xem Phụ lục (quá tải tham chiếu).

7.16. Sự đa hìnhPolymorphism¶

Hầu hết các phương pháp chúng tôi đã viết chỉ hoạt động cho một loại cụ thể. Khi bạn tạo một đối tượng mới, bạn viết các phương thức hoạt động trên loại đó.

Nhưng có một số hoạt động nhất định mà bạn sẽ muốn áp dụng cho nhiều loại, chẳng hạn như các hoạt động số học trong các phần trước. Nếu nhiều loại hỗ trợ cùng một bộ hoạt động, bạn có thể viết các chức năng hoạt động trên bất kỳ loại nào trong số đó.

Ví dụ: hoạt động

>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
06 (phổ biến trong đại số tuyến tính) có ba tham số; Nó nhân hai đầu tiên và sau đó thêm phần ba. Chúng ta có thể viết nó bằng Python như thế này:

>>> p2 = Point()
>>> p2.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Point' object has no attribute 'x'
>>>
5

Phương pháp này sẽ hoạt động cho bất kỳ giá trị nào của

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
4 và
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
5 có thể được nhân lên và cho bất kỳ giá trị nào của
>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
09 có thể được thêm vào sản phẩm.

Chúng ta có thể gọi nó với các giá trị số:

Hoặc với

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

>>> p2 = Point()
>>> p2.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Point' object has no attribute 'x'
>>>
6

Trong trường hợp đầu tiên,

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1 được nhân với vô hướng và sau đó được thêm vào một
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1 khác. Trong trường hợp thứ hai, sản phẩm DOT mang lại giá trị số, do đó tham số thứ ba cũng phải là một giá trị số.

Một chức năng như thế này có thể lấy các tham số với các loại khác nhau được gọi là đa hình.polymorphic.

Một ví dụ khác, hãy xem xét phương pháp

>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
13, in danh sách hai lần, tiến và lùi:

>>> p2 = Point()
>>> p2.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Point' object has no attribute 'x'
>>>
7

Vì phương thức

>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
14 là công cụ sửa đổi, chúng tôi tạo một bản sao của danh sách trước khi đảo ngược nó. Bằng cách đó, phương pháp này không sửa đổi danh sách mà nó nhận được dưới dạng tham số.

Ở đây, một ví dụ áp dụng

>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
13 cho danh sách:

>>> p2 = Point()
>>> p2.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Point' object has no attribute 'x'
>>>
8

Tất nhiên, chúng tôi dự định áp dụng chức năng này vào danh sách, vì vậy không có gì đáng ngạc nhiên khi nó hoạt động. Điều đáng ngạc nhiên là nếu chúng ta có thể áp dụng nó vào

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

Để xác định xem một hàm có thể được áp dụng cho một loại mới hay không, chúng tôi áp dụng quy tắc đa hình cơ bản: nếu tất cả các hoạt động bên trong hàm có thể được áp dụng cho loại, hàm có thể được áp dụng cho loại. Các hoạt động trong phương pháp bao gồm

>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
17,
>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
14 và
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
70.

>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
17 hoạt động trên bất kỳ đối tượng nào và chúng tôi đã viết một phương thức
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
63 cho
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1s, vì vậy tất cả những gì chúng ta cần là phương thức
>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
14 trong lớp
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1:

>>> p2 = Point()
>>> p2.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Point' object has no attribute 'x'
>>>
9

Sau đó, chúng ta có thể chuyển

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1S đến
>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
13:

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

Loại đa hình tốt nhất là loại không chủ ý, nơi bạn phát hiện ra rằng một hàm bạn đã viết có thể được áp dụng cho một loại mà bạn chưa từng lên kế hoạch.

7.17. Bảng chú giải¶Glossary¶

lớp

Một loại hợp chất do người dùng xác định. Một lớp cũng có thể được coi là một mẫu cho các đối tượng là trường hợp của nó.

khởi sự

Để tạo một thể hiện của một lớp.

ví dụ

Một đối tượng thuộc về một lớp.

sự vật

Một loại dữ liệu ghép thường được sử dụng để mô hình hóa một thứ hoặc khái niệm trong thế giới thực.

thuộc tính

Một trong những mục dữ liệu được đặt tên tạo thành một thể hiện.

Chức năng thuần túy

Một hàm không sửa đổi bất kỳ đối tượng nào mà nó nhận được dưới dạng tham số. Hầu hết các chức năng thuần túy đều có kết quả.

bổ nghĩa

Một hàm thay đổi một hoặc nhiều đối tượng mà nó nhận được dưới dạng tham số. Hầu hết các sửa đổi là vô hiệu.

Phong cách lập trình chức năng

Một phong cách thiết kế chương trình trong đó phần lớn các chức năng là thuần túy.

phát triển nguyên mẫu

Một cách phát triển các chương trình bắt đầu với một nguyên mẫu và dần dần kiểm tra và cải thiện nó.

Phát triển theo kế hoạch

Một cách phát triển các chương trình liên quan đến cái nhìn sâu sắc cấp cao về vấn đề và lập kế hoạch nhiều hơn là phát triển gia tăng hoặc phát triển nguyên mẫu.

Ngôn ngữ hướng đối tượng

Một ngôn ngữ cung cấp các tính năng, chẳng hạn như các lớp và kế thừa do người dùng xác định, tạo điều kiện cho lập trình hướng đối tượng.

lập trình hướng đối tượng

Một phong cách lập trình trong đó dữ liệu và các hoạt động thao tác nó được tổ chức thành các lớp và phương pháp.

phương pháp

Một hàm được xác định bên trong định nghĩa lớp và được gọi trên các trường hợp của lớp đó. : Ghi đè :: để thay thế mặc định. Các ví dụ bao gồm thay thế một tham số mặc định bằng một đối số cụ thể và thay thế một phương thức mặc định bằng cách cung cấp một phương thức mới cùng tên.

Phương pháp khởi tạo

Một phương thức đặc biệt được gọi tự động khi một đối tượng mới được tạo và khởi tạo các thuộc tính của đối tượng.

quá tải người vận hành

Mở rộng các toán tử tích hợp (

>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
73,
>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
28,
>>> type(Point)
<class 'type'>
>>> p = Point()
>>> type(p)
<class '__main__.Point'>
89,
>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
30,
>>> print(p.y)
4
>>> x = p.x
>>> print(x)
3
31, v.v.) để chúng hoạt động với các loại do người dùng xác định.

sản phẩm chấm

Một hoạt động được xác định trong đại số tuyến tính nhân lên hai

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1 và mang lại một giá trị số.

nhân bản vô tính

Một hoạt động được xác định trong đại số tuyến tính nhân lên từng tọa độ của

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
1 với giá trị số.

đa hình

Một chức năng có thể hoạt động trên nhiều loại. Nếu tất cả các hoạt động trong một hàm có thể được áp dụng cho một loại, thì hàm có thể được áp dụng cho một loại.

Loại điểm trong Python là gì?

Point -Object đại diện cho một điểm duy nhất trong không gian.Điểm có thể là hai chiều (x, y) hoặc ba chiều (x, y, z).Linestring -Object (tức là một dòng) đại diện cho một chuỗi các điểm kết hợp với nhau để tạo thành một dòng.Do đó, một dòng bao gồm một danh sách ít nhất hai bộ tọa độ.. Points can be either two-dimensional (x, y) or three dimensional (x, y, z). LineString -object (i.e. a line) represents a sequence of points joined together to form a line. Hence, a line consist of a list of at least two coordinate tuples.

P1 trong Python là gì?

Vì vậy, P1 là một ví dụ của người.Khi chúng ta in P1, Python trả về loại và vị trí bộ nhớ của đối tượng.an instance of type Person. When we print p1, Python returns the type and the memory location of the object.

__ str __ trong Python là gì?

Python __str __ () Phương thức này trả về biểu diễn chuỗi của đối tượng.Phương thức này được gọi là hàm in () hoặc str () được gọi trên một đối tượng.Phương thức này phải trả về đối tượng chuỗi.This method returns the string representation of the object. This method is called when print() or str() function is invoked on an object. This method must return the String object.

Bản thân có phải là một con trỏ trong Python không?

hàm (A: Số nguyên): Số nguyên của đối tượng;Cái sau xem xét con trỏ tự (vâng, nó được đặt tên là bản thân nhưng nó là một con trỏ ngầm như thế này trong C ++, trong khi bản thân Python là rõ ràng).typedef int anyclass :: (*mytype) (int a);Là sự khác biệt với Pascal, trong C ++, bạn phải chỉ định lớp sở hữu phương thức.yes, it's named self but it's an implicit pointer like the this in c++, while the python self is explicit). typedef int Anyclass::(*mytype)(int a); As difference with Pascal, in C++ you must specify the class owning the method.