Truy cập các biến thành viên của một lớp trong Python?


83
class Example(object):
    def the_example(self):
        itsProblem = "problem"

theExample = Example()
print(theExample.itsProblem)

Làm cách nào để truy cập biến của lớp? Tôi đã thử thêm định nghĩa này:

def return_itsProblem(self):
    return itsProblem

Tuy nhiên, điều đó cũng không thành công.


1
Đã chỉnh sửa tiêu đề, câu hỏi thực sự về các biến "tĩnh" của lớp: stackoverflow.com/questions/707380/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功 Ngày

Câu trả lời:


139

Câu trả lời, trong một vài từ

Trong ví dụ của bạn, itsProblemlà một biến cục bộ.

Bạn phải sử dụng selfđể đặt và lấy các biến phiên bản. Bạn có thể đặt nó trong __init__phương thức. Sau đó, mã của bạn sẽ là:

class Example(object):
    def __init__(self):
        self.itsProblem = "problem"


theExample = Example()
print(theExample.itsProblem)

Nhưng nếu bạn muốn một biến lớp đúng, thì hãy sử dụng trực tiếp tên lớp:

class Example(object):
    itsProblem = "problem"


theExample = Example()
print(theExample.itsProblem)
print (Example.itsProblem)

Nhưng hãy cẩn thận với biến này, vì theExample.itsProblemnó được đặt tự động bằng Example.itsProblem, nhưng không phải là cùng một biến và có thể thay đổi độc lập.

Một số giải thích

Trong Python, các biến có thể được tạo động. Do đó, bạn có thể làm như sau:

class Example(object):
    pass

Example.itsProblem = "problem"

e = Example()
e.itsSecondProblem = "problem"

print Example.itsProblem == e.itsSecondProblem 

bản in

Thật

Do đó, đó chính xác là những gì bạn làm với các ví dụ trước.

Thật vậy, trong Python, chúng tôi sử dụng selfas this, nhưng nó nhiều hơn thế một chút. selflà đối số đầu tiên của bất kỳ phương thức đối tượng nào vì đối số đầu tiên luôn là tham chiếu đối tượng. Điều này là tự động, cho dù bạn có gọi selfhay không.

Có nghĩa là bạn có thể làm:

class Example(object):
    def __init__(self):
        self.itsProblem = "problem"


theExample = Example()
print(theExample.itsProblem)

hoặc là:

class Example(object):
    def __init__(my_super_self):
        my_super_self.itsProblem = "problem"


theExample = Example()
print(theExample.itsProblem)

Nó giống hệt nhau. Đối số đầu tiên của phương thức đối tượng BẤT KỲ là đối tượng hiện tại, chúng ta chỉ gọi nó selfnhư một quy ước. Và bạn chỉ thêm một biến vào đối tượng này, giống như cách bạn làm từ bên ngoài.

Bây giờ, về các biến lớp.

Khi bạn làm:

class Example(object):
    itsProblem = "problem"


theExample = Example()
print(theExample.itsProblem)

Bạn sẽ nhận thấy trước tiên chúng tôi đặt một biến lớp , sau đó chúng tôi truy cập một biến đối tượng (cá thể) . Chúng tôi không bao giờ đặt biến đối tượng này nhưng nó hoạt động, làm thế nào điều đó có thể?

Vâng, Python cố gắng lấy biến đối tượng đầu tiên, nhưng nếu nó không thể tìm thấy nó, nó sẽ cung cấp cho bạn biến lớp. Cảnh báo: biến lớp được chia sẻ giữa các phiên bản và biến đối tượng thì không.

Như một kết luận, không bao giờ sử dụng các biến lớp để đặt giá trị mặc định cho các biến đối tượng. Sử dụng __init__cho điều đó.

Cuối cùng, bạn sẽ biết rằng các lớp Python là các thể hiện và do đó là các đối tượng của chính nó, điều này mang lại cái nhìn sâu sắc mới để hiểu những điều trên. Hãy quay lại và đọc lại điều này sau khi bạn nhận ra điều đó.


bạn nói: "theExample.itsProblem được tự động đặt bằng Example.itsProblem, nhưng hoàn toàn không giống một biến và có thể thay đổi độc lập" - nhưng điều đó không hoàn toàn đúng và cụm từ của bạn gây hiểu lầm. Tôi tin rằng bạn biết những gì đang xảy ra ở đó, vì vậy tôi khuyên bạn nên diễn đạt lại rằng: "nó cùng một biến, nhưng nó có thể được quay lại một cách độc lập cho từng đối tượng".
jsbueno

Có, nhưng ràng buộc là một khái niệm ai đó dành cho một ngôn ngữ lập trình khác như Java hoặc C (như tôi nghi ngờ là OP) hoàn toàn không được biết đến. Sau đó, tôi sẽ giải thích ràng buộc là gì, sau đó là ràng buộc muộn, sau đó là vấn đề với các tham chiếu trên các đối tượng có thể thay đổi. Nó sẽ là quá dài. Tôi nghĩ đôi khi bạn phải hy sinh sự chính xác trên bàn thờ của sự hiểu biết.
e-thoả mãn

Ngoài ra còn có (tôi nghĩ đây có thể là 2.7+) trình trang trí @classmethod, đáng xem xét. cuộc thảo luận thú vị ở đây - stackoverflow.com/questions/12179271/…
jsh Ngày

1
ràng buộc tên tuổi: Tôi nghĩ rằng đó là một ý tưởng tồi nếu đưa ra những tuyên bố sai sự thật, dù ở cấp độ nào. Tôi đề nghị chỉnh sửa nhỏ này: Nhưng hãy cẩn thận với điều này, vì theExample.itsProblemnó được tự động đặt bằng Example.itsProblem, nhưng, từ góc độ thực tế *, không phải là biến giống nhau chút nào và có thể được thay đổi độc lập. *: Thực sự nó bắt đầu ra như cùng một đối tượng nhưng nó là rất dễ dàng để vô tình thay đổi điều đó nếu bạn không hiểu Python của tên ràng buộc
n611x007

11

Bạn đang khai báo một biến cục bộ, không phải một biến lớp. Để đặt một biến phiên bản (thuộc tính), hãy sử dụng

class Example(object):
    def the_example(self):
        self.itsProblem = "problem"  # <-- remember the 'self.'

theExample = Example()
theExample.the_example()
print(theExample.itsProblem)

Để đặt một biến lớp (hay còn gọi là thành viên tĩnh), hãy sử dụng

class Example(object):
    def the_example(self):
        Example.itsProblem = "problem"
        # or, type(self).itsProblem = "problem"
        # depending what you want to do when the class is derived.

1
Ngoại trừ các biến lớp được khai báo một lầncấp độ lớp . Cách của bạn sẽ đặt lại nó sau mỗi lần cài đặt, đây thực sự không phải là điều bạn muốn. Cũng xem stackoverflow.com/questions/2709821/python-self-explained để biết lý do đằng sau bản thân rõ ràng.

2

Nếu bạn có một hàm cá thể (tức là một hàm được truyền tự), bạn có thể sử dụng hàm self để nhận tham chiếu đến lớp bằng cách sử dụng self.__class__

Ví dụ trong đoạn mã dưới đây tornado tạo một thể hiện để xử lý các yêu cầu nhận, nhưng chúng ta có thể nắm giữ get_handlerlớp và sử dụng nó để giữ một ứng dụng khách riak, vì vậy chúng ta không cần phải tạo một đối tượng cho mọi yêu cầu.

import tornado.web
import riak

class get_handler(tornado.web.requestHandler):
    riak_client = None

    def post(self):
        cls = self.__class__
        if cls.riak_client is None:
            cls.riak_client = riak.RiakClient(pb_port=8087, protocol='pbc')
        # Additional code to send response to the request ...
    

Đây là một ví dụ rất tốt để chứng minh câu hỏi từ tiêu đề gốc của OP. Trên thực tế, ví dụ OPs không khớp với titel và các câu trả lời khác đề cập đến ví dụ. Dù sao, đây là cách tốt nhất để truy cập một biến mức lớp vì nó không vi phạm nguyên tắc DRY. Giống như một số ví dụ khác. Tốt hơn là sử dụng self .__ class__ thay vì lặp lại tên lớp. Nó làm cho mã trở thành bằng chứng trong tương lai, giúp việc tái cấu trúc dễ dàng hơn và nếu bạn dám sử dụng phân lớp thì điều này cũng có thể có lợi thế.
mit

Người đọc nên được cảnh báo rằng việc sử dụng một trình xử lý như trên có thể dẫn đến các vấn đề không chỉ trong các ứng dụng không chạy đơn luồng. Về lý thuyết, nhiều trường hợp của lớp có thể sử dụng cùng một trình xử lý iin song song và nếu trình xử lý không được thiết kế để làm điều này, điều này phụ thuộc vào cấu trúc bên trong của nó, thì nó có thể không hoạt động. 'Song song' trong một ứng dụng luồng đơn có nghĩa là, cá thể lớp đầu tiên chưa hoàn thành việc sử dụng trình xử lý và sau đó cá thể thứ hai bắt đầu sử dụng trình xử lý. Trong những trường hợp như vậy, bạn nên sử dụng một biến thể hiện để thay thế.
mit

0

Thực hiện câu lệnh return như ví dụ bên dưới! Bạn nên tốt. Tôi hi vọng nó giúp ích cho ai đó..

class Example(object):
    def the_example(self):
        itsProblem = "problem"
        return itsProblem 


theExample = Example()
print theExample.the_example()

1
Bạn nên sửa lỗi thụt lề mã của mình. Cũng có những câu trả lời cao cấp cho câu hỏi này và câu trả lời của bạn là biến thể cơ bản của những câu trả lời đó, không phải là giải pháp thay thế ...
HEADLESS_0NE
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.