Mục đích của từ 'bản thân' là gì?


1130

Mục đích của selftừ trong Python là gì? Tôi hiểu rằng nó đề cập đến đối tượng cụ thể được tạo từ lớp đó, nhưng tôi không thể hiểu tại sao nó cần được thêm rõ ràng vào mọi hàm như một tham số. Để minh họa, trong Ruby tôi có thể làm điều này:

class myClass
    def myFunc(name)
        @name = name
    end
end

Mà tôi hiểu, khá dễ. Tuy nhiên, trong Python tôi cần bao gồm self:

class myClass:
    def myFunc(self, name):
        self.name = name

Bất cứ ai có thể nói chuyện với tôi thông qua điều này? Đó không phải là điều tôi đã gặp trong trải nghiệm (bị giới hạn) của tôi.


111
Bạn có thể thấy thú vị bài tiểu luận này "Tại sao bản thân rõ ràng phải ở lại" bởi Guido van Rossum: neopythonic.blogspot.com/2008/10/ Kẻ
unutbu

14
Xem thêm: "Tại sao phải 'tự' được sử dụng một cách rõ ràng trong định nghĩa phương pháp và các cuộc gọi": docs.python.org/faq/...
unutbu

37
"Điều mà tôi hiểu, khá dễ dàng" --- Khá chủ quan, bạn không nghĩ sao? Điều gì làm cho @nametrực quan hơn self.name? Cái sau, IMO, trực quan hơn.
Santa

14
Đó là sự khác biệt chính giữa một hàm và một phương thức lớp. Một chức năng là trôi nổi miễn phí, không bị cản trở. Một phương thức lớp (thể hiện) phải nhận thức được nó là thuộc tính cha mẹ (và thuộc tính cha mẹ), do đó bạn cần truyền phương thức tham chiếu đến lớp cha (dưới dạng tự ). Đó chỉ là một quy tắc ít ngầm định mà bạn phải tiếp thu trước khi hiểu OOP. Các ngôn ngữ khác chọn đường cú pháp thay vì đơn giản ngữ nghĩa, python không phải là ngôn ngữ khác.
Evan Plaice

9
Tôi không nghĩ "rõ ràng là tốt hơn ngầm" thực sự giải thích tốt sự lựa chọn thiết kế này. @fooself.foorõ ràng như nhau vì không cần phải giải quyết ngầm định (ví dụ: trong C ++, các thành viên thể hiện có thể được truy cập "ngầm" mà không "rõ ràng" sử dụng không gian tên). Sự khác biệt duy nhất là Ruby giới thiệu một ngữ nghĩa mới (@), trong khi Python thì không. Việc một ngữ nghĩa mới có đáng hay không với mức độ dài dòng tránh được hoàn toàn chủ quan. Mặc dù vậy, cần lưu ý rằng hầu hết các ngôn ngữ hiện đại đều chọn giới thiệu một khái niệm ở đây (ví dụ: php's $ this, JS's this).
Jing

Câu trả lời:


710

Lý do bạn cần sử dụng self. là vì Python không sử dụng @cú pháp để chỉ các thuộc tính thể hiện. Python quyết định thực hiện các phương thức theo cách làm cho cá thể mà phương thức thuộc về được truyền tự động, nhưng không được nhận tự động: tham số đầu tiên của phương thức là thể hiện mà phương thức được gọi. Điều đó làm cho các phương thức hoàn toàn giống như các hàm và để tên thực tế sử dụng cho bạn (mặc dù selflà quy ước và mọi người thường sẽ cau mày với bạn khi bạn sử dụng một cái gì đó khác.)self Không phải là đặc biệt đối với mã, nó chỉ là một đối tượng khác .

Python có thể đã làm một cái gì đó khác để phân biệt các tên bình thường với các thuộc tính - cú pháp đặc biệt như Ruby có hoặc yêu cầu các khai báo như C ++ và Java làm, hoặc có lẽ là một cái gì đó khác biệt hơn - nhưng nó đã không. Python là tất cả để làm cho mọi thứ rõ ràng, làm cho nó rõ ràng những gì, và mặc dù nó không làm điều đó hoàn toàn ở mọi nơi, nhưng nó làm điều đó cho các thuộc tính ví dụ. Đó là lý do tại sao việc gán cho một thuộc tính thể hiện cần biết thể hiện nào để gán cho và đó là lý do tại sao nó cần self..


23
@Georg: clsđề cập đến đối tượng lớp, không phải đối tượng thể hiện
SilentGhost

17
@SilentGhost: Thật ra, tên của tham số đầu tiên là bất cứ thứ gì bạn muốn. Trên các phương thức lớp, quy ước là sử dụng clsselfđược sử dụng theo quy ước cho các phương thức ví dụ. Nếu tôi muốn, tôi có thể sử dụng selfcho clscác phương thức phân loại và ví dụ. Tôi cũng có thể sử dụng bobfnordnếu tôi thích.
SingleNegationElimination

67
Tôi thấy thú vị khi cộng đồng không chọn thisthay thế self. Có selfmột số lịch sử mà tôi không biết về các ngôn ngữ lập trình cũ hơn?
Jules GM

24
@Julius Xuất selfphát từ các công ước của Modula-3, xem câu trả lời này để biết thêm chi tiết về lựa chọn này. (Tuyên bố từ chối trách nhiệm: của tôi).
Bakuriu

9
@Julius selfTừ khóa (Smalltalk, 1980) có trước thistừ khóa (từ C ++). Xem: stackoverflow.com/questions/1079983/ Mạnh
Wes Turner

425

Hãy tham gia một lớp vectơ đơn giản:

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

Chúng tôi muốn có một phương pháp tính toán độ dài. Nó sẽ trông như thế nào nếu chúng ta muốn định nghĩa nó trong lớp?

    def length(self):
        return math.sqrt(self.x ** 2 + self.y ** 2)

Nó trông như thế nào khi chúng ta định nghĩa nó là một phương thức / hàm toàn cục?

def length_global(vector):
    return math.sqrt(vector.x ** 2 + vector.y ** 2)

Vì vậy, toàn bộ cấu trúc vẫn giữ nguyên. Làm thế nào tôi có thể sử dụng này? Nếu chúng ta giả định rằng chúng ta đã không viết một lengthphương thức cho Vectorlớp của mình, chúng ta có thể làm điều này:

Vector.length_new = length_global
v = Vector(3, 4)
print(v.length_new()) # 5.0

Điều này hoạt động vì tham số đầu tiên của length_global, có thể được sử dụng lại làm selftham số trong length_new. Điều này sẽ không thể có được nếu không có một rõ ràng self.


Một cách hiểu khác về sự cần thiết của sự rõ ràng selflà xem nơi Python thêm một số đường cú pháp. Khi bạn ghi nhớ, về cơ bản, một cuộc gọi như

v_instance.length()

được chuyển đổi nội bộ sang

Vector.length(v_instance)

thật dễ dàng để biết nơi selfphù hợp. Bạn không thực sự viết các phương thức cá thể bằng Python; những gì bạn viết là các phương thức lớp phải lấy một thể hiện làm tham số đầu tiên. Và do đó, bạn sẽ phải đặt tham số cá thể ở đâu đó một cách rõ ràng.


4
Vector.length_new = length_global ... Tôi thực sự bắt đầu sử dụng cú pháp như thế này trong khai báo lớp. Bất cứ khi nào tôi chỉ muốn kế thừa một số phương thức từ một lớp khác, tôi chỉ cần sao chép rõ ràng tham chiếu đến các phương thức.
Jeeyoung Kim

2
sẽ công bằng khi nói rằng "phương thức cá thể" của python chỉ đơn giản là một đường cú pháp của các phương thức toàn cầu tĩnh (như trong Java hoặc C ++) với một đối tượng được truyền vào để đóng gói nhiều thuộc tính? --- ồ, đây là một nửa đúng vì trong đa hình, mục đích quan trọng hơn của "cái này" (như trong java) hoặc "bản thân" là để cho bạn thực hiện đúng các phương thức. Python có cái này. vì vậy, gọi myobj.someMethod () bằng với TheClassOfMyObj.someMethod (myobj) trong python. lưu ý rằng "TheClassOfMyObj" được python tự động tìm ra từ "bản thân", nếu không bạn sẽ phải tìm ra điều đó.
gấu bông

3
Nguyên vẹn, không chỉ các phương thức cá thể chỉ là các phương thức lớp, mà các phương thức chỉ là các hàm là thành viên của một lớp, như các Vector.length_new = length_globalchương trình.
Nga

1
"Điều này hoạt động, bởi vì tham số đầu tiên của length_global, có thể được sử dụng lại làm tham số tự trong length_new. Điều này sẽ không thể thực hiện được nếu không có bản thân rõ ràng." - nó sẽ hoạt động như nhau. nó sẽ được sử dụng lại cho bản thân ngầm ... ví dụ thứ hai là một lý luận tròn - bạn phải đặt chính mình ở đó, bởi vì python cần bản thân rõ ràng.
Karoly Horvath

1
@KarolyHorvath: Chắc chắn, cũng có thể có một ngôn ngữ với một mô hình trong đó các phương thức được xác định bên trong không cần một bản thân rõ ràng nhưng các phương thức được xác định bên ngoài làm. Nhưng tôi muốn nói rằng có một sự nhất quán trong việc yêu cầu bản thân rõ ràng trong cả hai trường hợp, điều đó làm cho nó trở thành một lý do chính đáng để làm theo cách này. Các ngôn ngữ khác có thể chọn cách tiếp cận khác nhau.
Debilski

422

Giả sử bạn có một lớp ClassAchứa phương thức methodAđược định nghĩa là:

def methodA(self, arg1, arg2):
    # do something

ObjectAlà một ví dụ của lớp này.

Bây giờ khi ObjectA.methodA(arg1, arg2)được gọi, python chuyển đổi nội bộ cho bạn thành:

ClassA.methodA(ObjectA, arg1, arg2)

Các selfbiến đề cập đến chính đối tượng.


94
Tôi đọc tất cả các câu trả lời khác và loại hiểu, tôi đọc câu này và sau đó tất cả đều có ý nghĩa.
Seth

3
Điều này đóng đinh nó cho tôi!
Bernard 'Beta Berlin' Parah

2
Tại sao không giữ những can đảm bên trong, mặc dù, giống như Ruby?
Cees Timmerman

Nhưng trong phương thức __init __ (tự), nó chấp nhận bản thân, thậm chí ngay cả khi không tạo đối tượng, làm thế nào để nó tự tham chiếu?
saurav

Nghiêm túc mà nói, điều này tốt hơn nhiều so với ví dụ của Debilski vì nó không quá phức tạp và mọi người có thể không quen thuộc với các vectơ.
NoName

215

Khi các đối tượng được khởi tạo, chính đối tượng được truyền vào tham số tự.

nhập mô tả hình ảnh ở đây

Do đó, dữ liệu của đối tượng bị ràng buộc với đối tượng. Dưới đây là một ví dụ về cách bạn có thể hình dung dữ liệu của từng đối tượng có thể trông như thế nào. Lưu ý cách 'cái tôi' được thay thế bằng tên đối tượng. Tôi không nói sơ đồ ví dụ dưới đây là hoàn toàn chính xác nhưng hy vọng với mục đích phục vụ mục đích trực quan hóa việc sử dụng bản thân.

nhập mô tả hình ảnh ở đây

Đối tượng được truyền vào tham số tự để đối tượng có thể giữ dữ liệu của chính nó.

Mặc dù điều này có thể không hoàn toàn chính xác, hãy nghĩ đến quá trình khởi tạo một đối tượng như thế này: Khi một đối tượng được tạo ra, nó sử dụng lớp làm khuôn mẫu cho dữ liệu và phương thức của chính nó. Nếu không chuyển tên riêng của nó vào tham số tự, các thuộc tính và phương thức trong lớp sẽ vẫn là một khuôn mẫu chung và sẽ không được tham chiếu đến (thuộc về) đối tượng. Vì vậy, bằng cách chuyển tên của đối tượng vào tham số tự, điều đó có nghĩa là nếu 100 đối tượng được khởi tạo từ một lớp, tất cả chúng có thể theo dõi dữ liệu và phương thức của riêng chúng.

Xem hình minh họa dưới đây:

nhập mô tả hình ảnh ở đây


Xin chào, khi truy cập các thuộc tính của Bob chẳng hạn bằng "bob.name ()", bạn thực sự đã nhấn bob (). Self.name để nói từ ' init ' phải không?
udarH3

3
Khi bạn viết bob.name () trong nhận xét trên, bạn đang ngụ ý rằng bob có một phương thức gọi là name () do thực tế là bạn đã thêm dấu ngoặc sau tên. Trong ví dụ này tuy nhiên không có phương pháp như vậy. 'bob.name' (không có dấu ngoặc đơn) đang truy cập trực tiếp vào thuộc tính được gọi là tên từ phương thức init (constructor). Khi phương thức speak của bob được gọi, đó là phương thức truy cập thuộc tính name và trả về nó trong một câu lệnh in. Hi vọng điêu nay co ich.
sw123456

3
Không, bạn nhận được giá trị của self.name, đối với đối tượng bob thực sự là bob.name, vì tên của đối tượng được truyền vào tham số self khi nó được tạo (khởi tạo). Một lần nữa, hy vọng điều này sẽ giúp. Hãy thoải mái upvote bài chính nếu nó có.
sw123456

2
Tên được gán cho self.name tại thời điểm khởi tạo. Sau khi một đối tượng được tạo, tất cả các biến thuộc về đối tượng là những tiền tố có 'self'. Hãy nhớ rằng bản thân được thay thế bằng tên của đối tượng khi nó được tạo từ lớp.
sw123456

5
Đây là cách bạn giải thích công cụ! làm tốt lắm :)
penta

80

Tôi thích ví dụ này:

class A: 
    foo = []
a, b = A(), A()
a.foo.append(5)
b.foo
ans: [5]

class A: 
    def __init__(self): 
        self.foo = []
a, b = A(), A()
a.foo.append(5)
b.foo
ans: []

18
vì vậy các vars không có bản thân chỉ đơn giản là các vars tĩnh của lớp, như trong java
teddy teddy

5
gấu bông, bạn không hoàn toàn chính xác. Hành vi (giống như tĩnh hoặc không tĩnh) không chỉ phụ thuộc vào selfmà còn phụ thuộc vào loại biến. Hãy thử làm ví dụ đầu tiên với số nguyên đơn giản thay vì danh sách. Kết quả sẽ khá khác nhau.
Konstantin

2
Trên thực tế, câu hỏi của tôi với điều này là tại sao bạn được phép nói a.footrong ví dụ đầu tiên, chứ không phải là A.foo? Rõ ràng foothuộc về lớp ...
Radon Rosborough

Bạn có thể gọi các thành viên tĩnh từ các phiên bản của đối tượng bằng hầu hết các ngôn ngữ. Tại sao điều đó đáng ngạc nhiên?
Paarth

2
@RadonRosborough Bởi vì trong ví dụ đầu tiên, abcả hai nhãn (hoặc con trỏ) cho A()(lớp). a.footham chiếu A().foophương thức lớp. Trong ví dụ thứ hai, mặc dù, atrở thành một tham chiếu đến một thể hiện của A(), như b. Bây giờ chúng là các thể hiện thay vì chính đối tượng lớp, self cho phép foophương thức hoạt động trên các cá thể.
LegendaryDude

40

Tôi sẽ chứng minh với mã không sử dụng các lớp :

def state_init(state):
    state['field'] = 'init'

def state_add(state, x):
    state['field'] += x

def state_mult(state, x):
    state['field'] *= x

def state_getField(state):
    return state['field']

myself = {}
state_init(myself)
state_add(myself, 'added')
state_mult(myself, 2)

print( state_getField(myself) )
#--> 'initaddedinitadded'

Các lớp chỉ là một cách để tránh vượt qua "trạng thái" này mọi lúc (và những thứ hay ho khác như khởi tạo, thành phần lớp, siêu dữ liệu hiếm khi cần và hỗ trợ các phương thức tùy chỉnh để ghi đè toán tử).

Bây giờ chúng ta hãy chứng minh mã trên bằng cách sử dụng máy móc lớp python tích hợp, để cho thấy về cơ bản nó giống như thế nào.

class State(object):
    def __init__(self):
        self.field = 'init'
    def add(self, x):
        self.field += x
    def mult(self, x):
        self.field *= x

s = State()
s.add('added')    # self is implicitly passed in
s.mult(2)         # self is implicitly passed in
print( s.field )

[di chuyển câu trả lời của tôi từ câu hỏi đóng trùng lặp]


1
Tôi muốn Python làm đường cho những người xử lý cũng như Ruby.
Cees Timmerman

20

Các đoạn trích sau đây là từ tài liệu Python về bản thân :

Như trong Modula-3, không có tốc ký [trong Python] để tham chiếu các thành viên của đối tượng từ các phương thức của nó: hàm phương thức được khai báo với một đối số rõ ràng đầu tiên đại diện cho đối tượng, được cung cấp ngầm bởi lệnh gọi.

Thông thường, đối số đầu tiên của một phương thức được gọi là tự. Điều này không có gì khác hơn là một quy ước: tên tự nó hoàn toàn không có ý nghĩa đặc biệt với Python. Tuy nhiên, lưu ý rằng bằng cách không tuân theo quy ước, mã của bạn có thể khó đọc hơn đối với các lập trình viên Python khác và cũng có thể hình dung rằng một chương trình trình duyệt lớp có thể được viết dựa trên quy ước đó.

Để biết thêm thông tin, hãy xem hướng dẫn tài liệu Python về các lớp .


20

Cũng như tất cả các lý do khác đã nêu, nó cho phép truy cập dễ dàng hơn vào các phương thức được ghi đè; bạn có thể gọi Class.some_method(inst).

Một ví dụ về nơi hữu ích:

class C1(object):
    def __init__(self):
         print "C1 init"

class C2(C1):
    def __init__(self): #overrides C1.__init__
        print "C2 init"
        C1.__init__(self) #but we still want C1 to init the class too
>>> C2()
"C2 init"
"C1 init"

17

Việc sử dụng nó tương tự như việc sử dụng thistừ khóa trong Java, tức là để đưa ra một tham chiếu đến đối tượng hiện tại.


2
class myClass: def myFunc (this, name): this.name = name
LEMUEL ADane

16

Python không phải là ngôn ngữ được xây dựng cho Lập trình hướng đối tượng không giống như Java hay C ++.

Khi gọi một phương thức tĩnh trong Python, người ta chỉ cần viết một phương thức với các đối số thông thường bên trong nó.

class Animal():
    def staticMethod():
        print "This is a static method"

Tuy nhiên, một phương thức đối tượng, yêu cầu bạn tạo một biến, đó là Động vật, trong trường hợp này, cần đối số tự

class Animal():
    def objectMethod(self):
        print "This is an object method which needs an instance of a class"

Phương thức tự cũng được sử dụng để chỉ một trường biến trong lớp.

class Animal():
    #animalName made in constructor
    def Animal(self):
        self.animalName = "";


    def getAnimalName(self):
        return self.animalName

Trong trường hợp này, self đang đề cập đến biến AnimalName của toàn bộ lớp. HÃY NHỚ: Nếu bạn có một biến trong một phương thức, bản thân sẽ không hoạt động. Biến đó chỉ đơn giản là tồn tại trong khi phương thức đó đang chạy. Để xác định các trường (các biến của toàn bộ lớp), bạn phải xác định chúng BÊN NGOÀI các phương thức lớp.

Nếu bạn không hiểu một từ nào tôi đang nói, thì Google "Lập trình hướng đối tượng". Một khi bạn hiểu điều này, bạn thậm chí sẽ không cần phải hỏi câu hỏi đó :).


+1 vì sự khác biệt giữa staticMethod()objectMethod(self). Tôi muốn nói thêm rằng để gọi đầu tiên, bạn sẽ nói Animal.staticMethod(), trong khi objectMethod()cần một ví dụ:a = Animal(); a.objectMethod()
Laryx Decidua 24/07/2015

Những gì bạn đang nói không đúng 100%. Đó chỉ là một quy ước. Bạn vẫn có thể gọi phương thức tĩnh từ một đối tượng được tạo. Bạn sẽ không thể sử dụng bất kỳ thành viên nào trong lớp vì bạn không tự khai. Tôi thậm chí có thể gọi Animal.objectMethod (AnimalObj) để gọi không tĩnh. Về cơ bản, điều này có nghĩa là một phương thức tĩnh chỉ là một phương thức không sử dụng các biến thành viên. Không cần phải tự khai. Đó là một yêu cầu ngôn ngữ ngớ ngẩn tôi nghĩ. Các ngôn ngữ như Lua và C ++ cung cấp cho bạn các biến obj đằng sau hậu trường.
dùng441521

Bạn đã thực hiện một khai báo chuỗi AnimalName vô dụng và phương thức AnimalName bị lỗi.
Cees Timmerman

3
@ytpillai Không liên quan. Mã khó hiểu và không chính xác không nên được trình bày như một câu trả lời.
Cees Timmerman

1
def getAnimalNameđể không ghi đè chuỗi bạn đang cố gắng trả về và selftham chiếu đến thể hiện của lớp, không phải bất kỳ trường nào bên trong chuỗi.
Cees Timmerman

10

Nó ở đó để làm theo Python rõ ràng là tốt hơn so với ẩn. Nó thực sự là một tài liệu tham khảo cho đối tượng lớp học của bạn. Trong Java và PHP, ví dụ, nó được gọi là this.

Nếu user_type_namelà một trường trên mô hình của bạn, bạn truy cập nó bằng self.user_type_name.


10

Trước hết, bản thân là một cái tên thông thường, bạn có thể đặt bất cứ thứ gì khác (mạch lạc) thay cho nó.

Nó đề cập đến chính đối tượng, vì vậy khi bạn đang sử dụng nó, bạn đang tuyên bố rằng .name và .age là thuộc tính của các đối tượng Sinh viên (lưu ý, không phải của lớp Sinh viên) mà bạn sẽ tạo.

class Student:
    #called each time you create a new Student instance
    def __init__(self,name,age): #special method to initialize
        self.name=name
        self.age=age

    def __str__(self): #special method called for example when you use print
        return "Student %s is %s years old" %(self.name,self.age)

    def call(self, msg): #silly example for custom method
        return ("Hey, %s! "+msg) %self.name

#initializing two instances of the student class
bob=Student("Bob",20)
alice=Student("Alice",19)

#using them
print bob.name
print bob.age
print alice #this one only works if you define the __str__ method
print alice.call("Come here!") #notice you don't put a value for self

#you can modify attributes, like when alice ages
alice.age=20
print alice

Mã ở đây


1
Câu trả lời của bạn có vẻ rõ ràng nhất với tôi. +1
Pawel

9

selflà một đối tượng tham chiếu đến chính đối tượng, do đó, chúng giống nhau. Các phương thức Python không được gọi trong ngữ cảnh của chính đối tượng. selftrong Python có thể được sử dụng để đối phó với các mô hình đối tượng tùy chỉnh hoặc một cái gì đó.


8

Việc sử dụng đối số, theo cách gọi thông thường selflà không khó hiểu, tại sao nó lại cần thiết? Hoặc như tại sao đề cập rõ ràng về nó? Điều đó, tôi cho rằng, là một câu hỏi lớn hơn đối với hầu hết người dùng tìm kiếm câu hỏi này hoặc nếu không, chắc chắn họ sẽ có câu hỏi tương tự khi họ tiến lên học trăn. Tôi khuyên họ nên đọc vài blog này:

1: Sử dụng tự giải thích

Lưu ý rằng nó không phải là một từ khóa.

Đối số đầu tiên của mọi phương thức lớp, bao gồm init, luôn là một tham chiếu đến thể hiện hiện tại của lớp. Theo quy ước, lập luận này luôn được đặt tên là tự. Trong phương thức init, self tham chiếu đến đối tượng vừa tạo; trong các phương thức lớp khác, nó dùng để chỉ trường hợp có phương thức được gọi. Ví dụ mã dưới đây giống như mã trên.

2: Tại sao chúng ta có nó theo cách này và tại sao chúng ta không thể loại bỏ nó như một đối số, như Java và có một từ khóa thay thế

Một điều nữa tôi muốn thêm là, một selfđối số tùy chọn cho phép tôi khai báo các phương thức tĩnh bên trong một lớp, bằng cách không viết self.

Mã ví dụ:

class MyClass():
    def staticMethod():
        print "This is a static method"

    def objectMethod(self):
        print "This is an object method which needs an instance of a class, and that is what self refers to"

PS : Điều này chỉ hoạt động trong Python 3.x.

Trong các phiên bản trước, bạn phải thêm @staticmethodtrang trí một cách rõ ràng , nếu không thì selfđối số là bắt buộc.


7

Tôi ngạc nhiên không ai đưa lên Lua. Lua cũng sử dụng biến 'tự' tuy nhiên nó có thể được bỏ qua nhưng vẫn được sử dụng. C ++ cũng làm như vậy với 'cái này'. Tôi không thấy bất kỳ lý do nào để phải khai báo 'tự' trong mỗi chức năng nhưng bạn vẫn có thể sử dụng nó giống như bạn có thể với lua và C ++. Đối với một ngôn ngữ tự hào là ngắn gọn, thật kỳ quặc khi nó yêu cầu bạn phải khai báo biến tự.


6

Hãy xem ví dụ sau đây, giải thích rõ ràng mục đích của self

class Restaurant(object):  
    bankrupt = False

    def open_branch(self):
        if not self.bankrupt:
           print("branch opened")

#create instance1
>>> x = Restaurant()
>>> x.bankrupt
False

#create instance2
>>> y = Restaurant()
>>> y.bankrupt = True   
>>> y.bankrupt
True

>>> x.bankrupt
False  

self được sử dụng / cần thiết để phân biệt giữa các trường hợp.

Nguồn: tự biến trong python giải thích - Pythontips


Vâng, tôi nghĩ rằng chúng ta biết tại sao bản thân được sử dụng, nhưng câu hỏi là tại sao ngôn ngữ làm cho bạn tuyên bố rõ ràng. Nhiều ngôn ngữ khác không yêu cầu điều này và một ngôn ngữ tự hào là ngắn gọn, bạn nghĩ rằng họ sẽ chỉ cung cấp cho bạn biến số đằng sau hậu trường để sử dụng như Lua hoặc C ++ (điều này).
dùng441521

3
@ kmario23 Phản hồi của bạn là từ đây: pythontips.com/2013/08/07/the-elf-variable-in-python-explained Vui lòng luôn ghi nhận tác giả gốc khi đăng câu trả lời là của riêng bạn.
geekidharsh

@geekidharsh cảm ơn, tôi đã thêm một ghi chú!
kmario23

5

Là bởi vì cách python được thiết kế, các lựa chọn thay thế sẽ khó hoạt động. Python được thiết kế để cho phép các phương thức hoặc hàm được xác định trong ngữ cảnh mà cả ẩn this(a-la Java / C ++) hoặc tường minh @(a-la ruby) sẽ không hoạt động. Hãy lấy một ví dụ với cách tiếp cận rõ ràng với các quy ước python:

def fubar(x):
    self.x = x

class C:
    frob = fubar

Bây giờ fubarhàm sẽ không hoạt động vì nó sẽ cho rằng đó selflà một biến toàn cục (và cả trong đó frob). Phương án thay thế sẽ là thực thi phương thức với phạm vi toàn cầu được thay thế ( selfđối tượng là đối tượng).

Cách tiếp cận ngầm sẽ là

def fubar(x)
    myX = x

class C:
    frob = fubar

Điều này có nghĩa là myXsẽ được hiểu là một biến cục bộ trong fubar(và cả trong frob). Cách thay thế ở đây sẽ là thực thi các phương thức với phạm vi cục bộ được thay thế được giữ lại giữa các cuộc gọi, nhưng điều đó sẽ loại bỏ tính khả thi của các biến cục bộ của phương thức.

Tuy nhiên, tình hình hiện tại hoạt động tốt:

 def fubar(self, x)
     self.x = x

 class C:
     frob = fubar

ở đây khi được gọi là một phương pháp frobsẽ nhận được các đối tượng trên đó nó được gọi là thông qua các selftham số, và fubarvẫn có thể được gọi với một đối tượng như tham số và làm việc như nhau (nó giống như C.frobtôi nghĩ).


3

Trong __init__phương thức, tự đề cập đến đối tượng mới được tạo; trong các phương thức lớp khác, nó dùng để chỉ trường hợp có phương thức được gọi.

tự, như một cái tên, chỉ là một quy ước , gọi nó như bạn muốn! nhưng khi sử dụng nó, ví dụ để xóa đối tượng, bạn phải sử dụng cùng tên : __del__(var), nơi varđược sử dụng trong__init__(var,[...])

Bạn cũng nên xem qua cls, để có bức tranh lớn hơn . Bài đăng này có thể hữu ích.


3

self đang hoạt động như tên đối tượng hiện tại hoặc thể hiện của lớp.

# Self explanation.


 class classname(object):

    def __init__(self,name):

        self.name=name
        # Self is acting as a replacement of object name.
        #self.name=object1.name

   def display(self):
      print("Name of the person is :",self.name)
      print("object name:",object1.name)


 object1=classname("Bucky")
 object2=classname("ford")

 object1.display()
 object2.display()

###### Output 
Name of the person is : Bucky
object name: Bucky
Name of the person is : ford
object name: Bucky

1

self là không thể tránh khỏi.

Chỉ có một câu hỏi nên selfẩn hoặc rõ ràng. Guido van Rossumgiải quyết câu hỏi này nói selfphải ở lại .

Vậy selfsống ở đâu?

Nếu chúng ta chỉ cần gắn bó với lập trình chức năng, chúng ta sẽ không cần self. Khi chúng tôi nhập Python OOP, chúng tôi tìm thấyself ở đó.

Dưới đây là trường hợp sử dụng điển hình class Cvới phương thứcm1

class C:
    def m1(self, arg):
        print(self, ' inside')
        pass

ci =C()
print(ci, ' outside')
ci.m1(None)
print(hex(id(ci))) # hex memory address

Chương trình này sẽ xuất ra:

<__main__.C object at 0x000002B9D79C6CC0>  outside
<__main__.C object at 0x000002B9D79C6CC0>  inside
0x2b9d79c6cc0

Vì vậy, selfgiữ địa chỉ bộ nhớ của thể hiện lớp. Mục đích của việc selflà giữ tham chiếu cho các phương thức ví dụ và để chúng tôi có quyền truy cập rõ ràng vào tham chiếu đó.


Lưu ý có ba loại phương thức lớp khác nhau:

  • phương thức tĩnh (đọc: hàm),
  • phương pháp lớp,
  • phương pháp ví dụ (đã đề cập).

0

từ các tài liệu ,

điều đặc biệt về các phương thức là đối tượng thể hiện được truyền vào làm đối số đầu tiên của hàm. Trong ví dụ của chúng tôi, cuộc gọi x.f()hoàn toàn tương đương với MyClass.f(x). Nói chung, việc gọi một phương thức với một danh sách n đối số tương đương với việc gọi hàm tương ứng với một danh sách đối số được tạo bằng cách chèn đối tượng thể hiện của phương thức trước đối số đầu tiên.

trước đoạn trích này có liên quan,

class MyClass:
    """A simple example class"""
    i = 12345

    def f(self):
        return 'hello world'

x = MyClass()


-2

nó là một tham chiếu rõ ràng đến đối tượng thể hiện của lớp.


21
Tôi không nghĩ rằng điều này giúp richzilla hiểu lý do đằng sau nó.
Georg Schölly

1
@SilentGhost: bạn đã đóng đinh nó. Tôi rất ấn tượng. nếu tôi hiểu chính xác: Tôi có tạo một đối tượng như là một thể hiện của lớp được định nghĩa và tham số tự tham chiếu đến đối tượng đó không? Tôi hiểu bản thân đề cập đến cách ngầm cho lớp học nhưng sẽ thật tuyệt nếu bạn giải thích câu trả lời của mình nhiều hơn một chút.
dkrynicki
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.