2012-06-26 30 views
6

Đây là một mã rất đơn giản mà tôi đã thực hiện để chứng minh vấn đề tôi đang gặp phải. Điều đang xảy ra ở đây là tôi đang tạo ra hai trường hợp khác nhau của cùng một lớp nhưng việc thay đổi một thuộc tính của một lớp sẽ thay đổi thuộc tính tương ứng của cá thể kia. Tôi không chắc tại sao lại như vậy. Đây có phải là bình thường trong Python hoặc tôi gặp phải một cái gì đó đang hoàn toàn sai lầm?Nhiều phiên bản của một lớp sẽ bị ghi đè cùng một lúc? (Python)

class exampleClass(object): 

    attribute1=0 
    attribute2="string" 

x=exampleClass 
x.attribute1=20 
x.attribute2="Foo" 

y=exampleClass 
y.attribute1=60 
y.attribute2="Bar" 

print("X attributes: \n") 
print(x.attribute1) 
print(x.attribute2) 

print("Y attributes: \n") 
print(y.attribute1) 
print(y.attribute2) 

Dưới đây là những gì mà chương trình trông giống như sắp ra của giao diện điều khiển của tôi:

>>> 
X attributes: 

60 
Bar 
Y attributes: 

60 
Bar 
>>> 

Tôi nghĩ rằng nó nên nói:

X attributes: 

20 
Foo 
Y attributes: 

60 
Bar 

Tôi đang làm gì sai?

+0

Câu trả lời ngắn gọn: Cả hai 'x' và' y' đều tham chiếu đến đối tượng lớp 'exampleClass', chứ không phải đối tượng của nó. Để tạo các cá thể, bạn cần gọi đối tượng lớp như trong 'x = exampleClass()'. Sau đó, các thay đổi thuộc tính mà bạn thực hiện đối với 'x' sẽ chỉ ảnh hưởng đến cá thể mà nó đề cập đến. – martineau

Trả lời

8

Bạn đang tạo thuộc tính lớp, khi bạn muốn các thuộc tính mẫu. Sử dụng điều này:

class exampleClass(object): 
    def __init__(self): 
     self.attribute1 = 0 
     self.attribute2 = "string" 

Ngoài ra, bạn không tạo ra bất kỳ trường hợp của exampleClass, bạn cần điều này:

x = exampleClass() 
y = exampleClass() 

Mã của bạn chỉ đơn giản là sử dụng tên mới cho các lớp, và thay đổi thuộc tính của nó.

+0

Đây là giao diện trong giao diện điều khiển của tôi ... vẫn gặp sự cố tương tự. >>> lớp exObj (object): \t def __init __ (tự): \t \t self.attribute1 = 0 \t \t self.attribute2 = "string" \t \t >>> ce = exObj > >> ct = exObj >>> ce.attribute1 = 44 >>> ct.attribute1 = 54 >>> ce.attribute1 >>> ct.attribute1 >>> – jecaklafa

+0

Xin lỗi vì sự thô định dạng. – jecaklafa

+0

@jecaklafa: bạn cần phải khởi tạo lớp, với parens. –

3

Sửa đổi được thực hiện sao cho rõ ràng hơn.

Với mã mà bạn có, vấn đề của bạn là bạn đang tạo các biến x và y tham chiếu đến định nghĩa lớp thay vì khởi tạo các đối tượng mà tôi tin rằng hiện đã nổi lên như vấn đề với tất cả các cuộc thảo luận và bài đăng.

x = exampleClass 

Bây giờ có nghĩa là x hiện trỏ đến định nghĩa lớp. Thật thú vị bởi vì kể từ khi bạn đã attribute1 như là một biến của exampleClass, bạn có thể làm điều này:

x.attribute1 = 3 

Bây giờ nếu bạn đã làm như sau:

exampleClass.attribute1 

Thay vì xem 0 như bạn ban đầu cài đặt nó, bây giờ bạn sẽ thấy 3!

Để nhanh chóng đối tượng của lớp bạn cần phải làm như sau:

x = exampleClass() 
y = exampleClass() 

Bây giờ cả hai biến đang tham chiếu đối tượng mới mà mỗi người đều có thuộc tính riêng của họ vì vậy nếu bạn đã làm:

x.attribute1 = 219 

Sau đó, bạn sẽ thấy rằng y.attribute1 không được sửa đổi :) Sử dụng tên của lớp và hàm là phổ biến trong python như một tham chiếu đến định nghĩa. Vì vậy, hãy cẩn thận, nếu bạn muốn khởi tạo một đối tượng, hãy chắc chắn sử dụng dấu ngoặc đơn, nếu bạn muốn gọi hàm, hãy đảm bảo bạn cũng làm như vậy, nếu không, sử dụng tên là tham chiếu đến định nghĩa.

Tôi đề nghị bạn đọc câu trả lời của Ned Batchelder (và những người khác) vì bạn nên tạo biến mẫu theo cách đó với hàm init vì nó sạch hơn và nhiều hơn nữa.

Nhưng tổng thể kể từ khi nó kế thừa từ lớp Object thì bạn có thể giả định làm theo cách này sẽ tạo các cá thể (với dấu ngoặc đơn) và như vậy bạn có thể sửa đổi các giá trị đối tượng như tôi tin rằng chúng phải là biến mẫu ngay cả khi không có " tự ".

4

Bạn đã tạo thuộc tính lớp thuộc tính. Điều này có nghĩa là chúng được sắp xếp theo lớp, chứ không phải đối tượng của lớp.

Nếu bạn muốn đối tượng Phạm vi bạn có thể làm một cái gì đó như:

class exampleClass(object): 
     def __init__(self): 
      self.attribute1=0 
      self.attribute2="string" 

x = exampleClass() 
y = exampleClass() 

Sau đó, khi bạn thay đổi giá trị thuộc tính của một đối tượng, nó chỉ ảnh hưởng mà đặc biệt, như trái ngược với TẤT CẢ các đối tượng của lớp đó.

+2

Vẫn cần phải làm exampleClass() chứ không phải exampleClass nếu không nó sẽ là một con trỏ tới các bản thiết kế của lớp đó. – richardhsu

+0

@richardhsu: Nó sẽ tạo ra một 'NameError' vì các thuộc tính sẽ chưa được tạo ra. –

+1

Chính xác nhưng bạn vẫn có thể làm x = exampleClass, nó hợp lệ trong Python và làm cho x tham chiếu đến exampleClass để có mã của bạn là đúng cho thiết kế của lớp nhưng khởi tạo một đối tượng của lớp đó yêu cầu các dấu ngoặc đơn. – richardhsu

1

Các lớp cũng là các đối tượng, bằng Python. Do đó, chúng có thể được gán cho các biến và có các thuộc tính riêng của chúng, giống như bất kỳ đối tượng nào khác.

Tất cả các tên bạn liên kết trong khối class sẽ trở thành thuộc tính của lớp được tạo. Chúng là các thuộc tính không phải là của các phiên bản tương lai của lớp đó. Nhưng khi bạn cố gắng đọc một thuộc tính từ một cá thể và cá thể không có thuộc tính đó, Python mặc định xem xét các thuộc tính của lớp của cá thể đó và sẽ trả về nó nếu nó tìm thấy nó. Đó thực sự là phương thức hoạt động trong Python; chúng chỉ là thuộc tính trên lớp, và khi bạn cố gắng lấy chúng từ cá thể (nơi chúng không tồn tại) chúng được tìm thấy bằng cách nhìn vào lớp.

Với ý nghĩ đó, chương trình của bạn không làm những gì bạn nghĩ.

class exampleClass(object): 

    attribute1=0 
    attribute2="string" 

đây bạn đã tạo một lớp có tên exampleClass, với hai thuộc tính attribute1attribute2. Chúng là không phải là thuộc tính thể hiện; đây là một sai lầm thực sự phổ biến của những người học Python. Bạn cần phải rèn luyện bản thân trong số này, bởi vì đối với các ví dụ đơn giản, nó thường xuất hiện để làm việc "như thể" chúng là các thuộc tính cá thể. Tên gắn kết trong khối class tạo thuộc tính trên đối tượng lớp. Cách duy nhất để tạo các thuộc tính instance là lấy một tham chiếu đến cá thể khi nó tồn tại và gán các thuộc tính vào nó; Python cung cấp cho bạn phương thức __init__ (sẽ được gọi khi cá thể được tạo) làm nơi để thực hiện việc này. Vì vậy, quy tắc cơ bản của ngón tay cái là: tên được xác định trong một khối lớp là thuộc tính trên đối tượng lớp, tên được gán làm thuộc tính của self trong __init__ là thuộc tính trên tất cả các phiên bản của lớp đó.

nhầm lẫn của bạn được thêm phức tạp bởi một vấn đề khác:

x=exampleClass 
x.attribute1=20 
x.attribute2="Foo" 

Bởi vì lớp học được đối tượng như mọi thứ khác trong Python, đây là mã Python hoàn toàn hợp lý, nhưng nó không làm những gì bạn nghĩ rằng nó. Bạn đã không thực sự tạo ra một thể hiện của lớp học của bạn; cho rằng bạn cần phải gọi lớp như trong exampleClass(). Tên trống exampleClass chỉ đơn giản đề cập đến đối tượng lớp, vì vậy bạn đã chỉ cần đặt tên x cho đối tượng đó và sau đó gán một số thuộc tính của nó. Đương nhiên, khi bạn sau đó liên kết y với đối tượng lớp và gán các thuộc tính trên đối tượng đó thông qua y, đối tượng được gọi bởi x bị ảnh hưởng (đó là cùng một đối tượng).

Các vấn đề liên quan