2010-04-20 45 views
7

Tôi đang dạy tự python của tôi và tôi đã dịch một số mẫu mã vào đâypython biến phạm vi

class Student(object): 
    def __init__(self, name, a,b,c): 
     self.name = name 
     self.a = a 
     self.b = b 
     self.c = c 

    def average(self): 
     return (a+b+c)/3.0 

Đó là khá nhiều định nghĩa lớp học dành tôi

Sau đó trong phương thức main tôi tạo một thể hiện và gọi nó là a

if __name__ == "__main__" : 
    a = Student("Oscar", 10, 10, 10) 

đó là cách tôi tìm ra rằng biến a khai báo trong main có sẵn để phương pháp average và để làm cho phương pháp đó hoạt động, tôi phải nhập self.a + self.b + self.c thay vì

Lý do là gì?

tôi thấy câu hỏi có liên quan, nhưng tôi không thực sự biết nếu họ về

+2

Là một lưu ý phụ, luôn kế thừa 'đối tượng' để bạn đang sử dụng * lớp kiểu mới *, tức là' lớp Học sinh (đối tượng): '. –

+0

@ Giống như Subclassing 'object' trong Python 2.x là thực hành tốt, nhưng trong Python 3, điều này là không cần thiết, vì tất cả các lớp là" kiểu mới ". Tôi nhận thấy Python 3 thông qua là người nghèo, và giả sử OP đang sử dụng Python 2.x là hợp lý, nhưng một số ngày tôi hy vọng nó sẽ là một giả định nghèo. – gotgenes

Trả lời

9

Barenames (như a, b, c) là luôn có phạm vi cục bộ hoặc toàn cục (lưu cho các hàm lồng nhau, không có gì xung quanh trong mã của bạn). Lý do là việc thêm các phạm vi tiếp theo sẽ không cần thiết làm cho mọi thứ trở nên phức tạp hơn - ví dụ: nếu trong tên self.a = a tên mã a của bạn có thể bị nhiễu để có nghĩa là bạn muốn (tương đương với self.a) thì bản thân nhiệm vụ sẽ vô nghĩa (gán tên chính nó), vì vậy bạn cần các quy tắc phức tạp hơn.

Chỉ cần sử dụng tên đủ điều kiện (như self.a) khi bạn muốn một cái gì đó khác với hành vi đơn giản, đơn giản và tối ưu hóa của thanh cốt, là cách tiếp cận đơn giản nhất - hoàn toàn khả thi, không có quy tắc phức tạp nào và cho phép trình biên dịch tối ưu hóa mọi thứ có hiệu quả (vì ví dụ như phạm vi của tên mã luôn được xác định bằng từ vựng, không phải là phụ thuộc vào các đặc tính thay đổi động của môi trường). Vì vậy, bên cạnh có lẽ là nỗi nhớ cho ngôn ngữ khác với các quy tắc phạm vi phức tạp hơn, thực sự không có lý do gì để làm phức tạp ngữ nghĩa của tên lửa.

+0

Tôi gần như có được nó ... những gì tôi don 't khá, là, những gì sẽ xảy ra nếu tôi tuyên bố một địa phương 'a' trong phương pháp của tôi ... (Tôi đoán tôi sẽ tìm thấy nó bằng cách gõ chỉ một chút) BRB – OscarRyz

+0

Tôi trở lại .. vì vậy khi tôi khai báo biến cục bộ 'a' nó được ưu tiên hơn biến toàn cục' a' (như mong đợi) Tôi đoán cách duy nhất tôi phải sử dụng biến toàn cầu đó là .. không đặt tên cho địa phương của tôi giống nhau, đúng không? – OscarRyz

+0

@Oscar Reyes: Nếu bạn muốn sử dụng biến số như vậy, hãy chuyển biến đó làm tham số cho phương thức, ví dụ: 'student.average (a)' trong đó 'def average (self, para)'. Hơn bạn có thể sử dụng 'para' bên trong phương thức của bạn và nó sẽ có giá trị bạn cung cấp khi bạn gọi phương thức. Nhưng đây không phải là Python cụ thể, đó là cách này trong bất kỳ ngôn ngữ lập trình ... –

-1

Tất cả các biến ví dụ tương tự nên được gọi là sử dụng tự

+1

đó là một sự khởi đầu không may cho sự nghiệp SO ':) – KevinDTimm

+0

để thêm vào, tôi nghĩ rằng câu trả lời của bạn có thể đúng, chỉ mơ hồ (và không đầy đủ) như yêu cầu một downvote – KevinDTimm

2

Có nhiều lý do, mặc dù nguyên nhân chính là từ Zen của Python: "Rõ ràng là tốt hơn là ngầm." Trong một ngôn ngữ như C++, một phương thức trên lớp luôn có đối số ẩn this được đẩy lên ngăn xếp mỗi khi phương thức được gọi. Trong trường hợp này, khi một biến mẫu b tồn tại cũng như biến toàn cầu b, thì người dùng có thể chỉ tham chiếu đến b đề cập đến một biến mà không nhận ra rằng biến kia sẽ được sử dụng. Vì vậy, Python buộc bạn phải rõ ràng về phạm vi của bạn để tránh nhầm lẫn.

Với điều đó đang được nói, cũng có những lý do khác. Ví dụ, tôi có thể định nghĩa một hàm bên ngoài một lớp và sau đó đính kèm nó vào một lớp khi chạy. Ví dụ:

def log(self): 
    print "some library function requires all objects to have a log method" 
    print "unfortunately we're using the Student class, which doesn't have one" 
    print "this class is defined in a separate library, so we can't add the method" 
    print "fortunately, we can just add the method dynamically at runtime" 

Student.log = log 

Ở đây thực tế là chúng tôi định nghĩa một chức năng bên ngoài lớp và sau đó đính kèm chức năng đó vào lớp đó. Tôi không làm điều này một cách vô cùng thường xuyên, nhưng nó cực kỳ hữu ích khi tôi làm.

Dưới đây là một ví dụ phức tạp hơn; giả sử chúng ta muốn xác định một lớp bên trong một lớp khác, chẳng hạn như đối với các mục đích của kiểm tra đơn vị:

class SomeUnitTests(TestCase): 
    def test_something(self): 
     class SomeMockObject(SomeActualObject): 
      def foo(self2): 
       self.assertEqual(self2.x, SOME_CONSTANT) 

     some_lib.do_something_with(SomeMockObject) 

Ở đây sự hiện diện của một tự rõ ràng (mà chúng tôi có thể gọi bất cứ điều gì chúng ta muốn, nó không phải là tự) cho phép phân biệt giữa các lớp trong và ngoài của self. Một lần nữa, đây không phải là điều tôi thường xuyên làm, nhưng khi tôi làm thì nó cực kỳ hữu ích.

+2

Có ý nghĩa, ngoại trừ không có toàn cầu rõ ràng (hoặc là nó?) – OscarRyz

+0

Có một từ khóa chung, mà bạn có thể sử dụng để khai báo một biến bên trong một hàm có phạm vi toàn cục: http://docs.python.org/ phát hành/2.5.2/ref/global.html –