Làm cách nào tôi có thể truy cập các biến lớp của lớp static static trong các phương thức lớp trong Python?


162

Nếu tôi có mã python sau:

class Foo(object):
    bar = 1

    def bah(self):
        print(bar)

f = Foo()
f.bah()

Nó phàn nàn

NameError: global name 'bar' is not defined

Làm thế nào tôi có thể truy cập lớp / biến tĩnh bartrong phương thức bah?


Thông tin thêm về Python và statics có thể được tìm thấy ở đây: stackoverflow.com/questions/68645/python-static-variable
bedwyr

Câu trả lời:


166

Thay vì barsử dụng self.barhay Foo.bar. Việc chỉ định Foo.barsẽ tạo một biến tĩnh và gán cho self.barsẽ tạo một biến thể hiện.


12
Foo.bar sẽ hoạt động, nhưng self.bar tạo một biến thể hiện chứ không phải biến tĩnh.
bedwyr

47
bedwyr, "print self.bar" sẽ không tạo bất kỳ biến thể hiện nào (mặc dù việc gán cho self.bar sẽ).
Constantin

@Constantin - Tôi không nhận ra rằng, đó là một sự khác biệt thú vị. Cảm ơn đã sửa :-)
bedwyr

2
Nhưng nếu bạn không có ý định sử dụng ngà voi, thì rõ ràng hơn là sử dụng Foo. Classmember.
mk12

2
Khi sử dụng các biến tĩnh, bạn nên đọc gotchas từ đây: stackoverflow.com/questions/68645/ . @Constantin đưa ra một trong nhiều vấn đề.
Trevor Boyd Smith

84

Xác định phương thức lớp:

class Foo(object):
    bar = 1
    @classmethod
    def bah(cls):    
        print cls.bar

Bây giờ nếu bah()phải là phương thức cá thể (tức là có quyền truy cập vào bản thân), bạn vẫn có thể truy cập trực tiếp vào biến lớp.

class Foo(object):
    bar = 1
    def bah(self):    
        print self.bar

3
Tại sao không chỉ là Foo.bar, thay vì self.__ class__.bar?
mk12

15
@ Mk12: Khi bạn có quyền thừa kế lớp, "biến lớp" có thể nằm trong lớp cơ sở hoặc lớp con. Mà bạn muốn tham khảo? Phụ thuộc vào những gì bạn đang cố gắng làm. Foo.bar sẽ luôn đề cập đến một thuộc tính của lớp được chỉ định - có thể là lớp cơ sở hoặc lớp con. self.__ class__.bar sẽ đề cập đến bất kỳ lớp nào mà thể hiện là một loại.
Craig McQueen

7
Bây giờ chúng tôi đã đạt đến điểm đáng tiếc đó khi chúng tôi trở nên nhận thức được các chi tiết của ngôn ngữ mà chúng tôi có thể phân biệt giữa hai trường hợp sử dụng hài hòa. Nó thực sự phụ thuộc vào những gì bạn muốn làm, nhưng nhiều người sẽ không tham dự vào sự tinh tế như vậy.
Holdenweb

2
BTW, đây là cách sử dụng RARE của "biến lớp". Phổ biến hơn nhiều để có nó được định nghĩa trong một lớp cụ thể, ở đây Foo. Đây là thông tin hữu ích cho một số tình huống lập trình nâng cao. Nhưng hầu như chắc chắn không phải là câu hỏi ban đầu muốn làm câu trả lời (bất kỳ ai cần câu trả lời NÀY đều sẽ biết cách làm Foo.bar). +1 vì tôi đã học được điều gì đó từ điều này.
ToolmakerSteve 25/11/13

3
Tôi đang tìm hiểu khi nào nên sử dụng các biến và phương thức của lớp (trái ngược với các biến và phương thức của thể hiện). Khi bạn muốn truy cập một biến lớp trong một phương thức cá thể, có nhất thiết phải sử dụng self.__ class__.bar không? Tôi nhận thấy rằng self.bar hoạt động ngay cả khi thanh là biến lớp không phải là biến thể hiện.
Bill

13

Như với tất cả các ví dụ hay, bạn đã đơn giản hóa những gì bạn đang thực sự làm. Điều này là tốt, nhưng điều đáng chú ý là python có rất nhiều tính linh hoạt khi nói đến lớp so với các biến thể hiện. Điều tương tự cũng có thể nói về phương pháp. Để có danh sách tốt các khả năng, tôi khuyên bạn nên đọc phần giới thiệu các lớp học theo phong cách mới của Michael Fötsch , đặc biệt là các phần từ 2 đến 6.

Một điều cần rất nhiều công việc cần nhớ khi bắt đầu là python không phải là java. Không chỉ là một sáo ngữ. Trong java, toàn bộ một lớp được biên dịch, làm cho độ phân giải không gian tên thực sự đơn giản: bất kỳ biến nào được khai báo bên ngoài một phương thức (bất cứ nơi nào) đều là các biến thể (hoặc, nếu tĩnh, lớp) và có thể truy cập ngầm trong các phương thức.

Với python, quy tắc lớn là có ba không gian tên được tìm kiếm theo thứ tự cho các biến:

  1. Hàm / phương thức
  2. Các mô-đun hiện tại
  3. Nội địa

{begin pedagogy}

Có những ngoại lệ hạn chế cho điều này. Cái chính xảy ra với tôi là, khi một định nghĩa lớp đang được tải, định nghĩa lớp là không gian tên ẩn của chính nó. Nhưng điều này chỉ tồn tại chừng nào mô-đun đang được tải và hoàn toàn bị bỏ qua khi trong một phương thức. Như vậy:

>>> class A(object):
        foo = 'foo'
        bar = foo


>>> A.foo
'foo'
>>> A.bar
'foo'

nhưng:

>>> class B(object):
        foo = 'foo'
        def get_foo():
            return foo
        bar = get_foo()



Traceback (most recent call last):
  File "<pyshell#11>", line 1, in <module>
    class B(object):
  File "<pyshell#11>", line 5, in B
    bar = get_foo()
  File "<pyshell#11>", line 4, in get_foo
    return foo
NameError: global name 'foo' is not defined

{end pedagogy}

Cuối cùng, điều cần nhớ là bạn làm được tiếp cận với bất kỳ của các biến mà bạn muốn truy cập, nhưng có lẽ không ngầm. Nếu mục tiêu của bạn đơn giản và dễ hiểu, thì việc tìm kiếm Foo.bar hoặc self.bar có thể là đủ. Nếu ví dụ của bạn trở nên phức tạp hơn hoặc bạn muốn làm những việc ưa thích như thừa kế (bạn có thể kế thừa các phương thức tĩnh / lớp!) Hoặc ý tưởng đề cập đến tên của lớp trong chính lớp đó có vẻ sai với bạn, hãy kiểm tra phần giới thiệu tôi liên kết.


IIRC, về mặt kỹ thuật có 3 (+) không gian tên được tìm kiếm - hàm cục bộ, mô đun / toàn cầu và nội trang. Phạm vi lồng nhau có nghĩa là nhiều phạm vi địa phương có thể được tìm kiếm, nhưng đó là một trong những trường hợp đặc biệt. (...)
Jeff Shannon

Ngoài ra, tôi cẩn thận khi nói 'mô-đun chính', vì đó là mô-đun chứa chức năng được tìm kiếm, không phải mô-đun chính ... Và việc tìm kiếm thuộc tính từ một tham chiếu thể hiện là một điều khác, nhưng câu trả lời này giải thích tại sao bạn cần tham chiếu cá thể / lớp.
Jeff Shannon


-2
class Foo(object):    
    bar = 1

    def bah(object_reference):
        object_reference.var = Foo.bar
        return object_reference.var


f = Foo() 
print 'var=', f.bah()

4
Mặc dù mã này có thể giải quyết câu hỏi, bao gồm giải thích về cách thức và lý do giải quyết vấn đề này thực sự sẽ giúp cải thiện chất lượng bài đăng của bạn và có thể dẫn đến nhiều lượt bình chọn hơn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai, không chỉ người hỏi bây giờ. Vui lòng chỉnh sửa câu trả lời của bạn để thêm giải thích và đưa ra dấu hiệu về những hạn chế và giả định được áp dụng. Từ đánh giá
tiếng bíp đôi
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.