Thắc mắc về cách gọi biến của class trong method

mk có đoạn code này:

class Employee(object):
	"""docstring for Employee"""
	numbers = 0

	def __init__(self, name):
		self.name = name
		Employee.numbers += 1
		self.n = Employee.numbers

m = Employee('Q')
print(em.numbers)

ở đoạn trên thì mk thay _Employee.numbers bằng self.numbers_ được không???

Được, tuy nhiên, chỉ đúng khi bạn khởi tạo 1 instance thôi :smiley:

class Employee:
    numbers = 0
    def __init__(self, name):
        self.name = name
        Employee.numbers += 1
        self.n = Employee.numbers

a = Employee('A')
print(a.numbers)
b = Employee('B')
print(b.numbers)

Kết quả

1
2

Tuy nhiên

class Employee:
    numbers = 0
    def __init__(self, name):
        self.name = name
        self.numbers += 1
        self.n = self.numbers

a = Employee('A')
print(a.numbers)
b = Employee('B')
print(b.numbers)

Kết quả

1
1

Tại sao lại như vậy? Ở đây, chúng ta vẫn chưa đi sâu hết vấn đề. Chúng ta hãy quay trở lại cái ví dụ đầu tiên và mình thêm một câu lệnh để làm rõ cái mình sắp nói

class Employee:
    numbers = 0
    def __init__(self, name):
        self.name = name
        Employee.numbers += 1
        self.n = Employee.numbers

a = Employee('A')
print(a.numbers)
b = Employee('B')
print(b.numbers)
# kiểm  tra lại a numbers
print(a.numbers)

Kết quả

1
2
2

Wow, mình nghĩ ít nhiều bạn cũng bất ngờ là tại sao attribute numbers của a lại bị thay đổi.

Nhìn chung khi bạn sử dụng Employee thì bạn đang sử dụng lớp (mang tính toàn cục), còn khi bạn sử dụng self thì bạn đang sử dụng đối tượng (cục bộ). Để mình giải thích ý của mình.
Khi thay đổi giá trị một thuộc tính được khai báo trong lớp thông qua lớp thì thuộc tính ở toàn bộ đối tượng thuộc lớp đó sẽ được cập nhật lại giá trị mới.
Còn khi bạn thay đổi giá trị thuộc tính của một đối tượng, thì chỉ có đối tượng đó bị thay đổi, còn lớp của chúng ta vẫn như vậy. Và dĩ nhiên nếu như có nhiều đối tượng khác nó cũng vẫn sẽ không bị ảnh hưởng chung như khi thay đổi bởi lớp.

Mình có một bài viết về phần này. Bạn cũng có thể tham khảo đường link How Kteam

4 Likes

Có lẽ bạn vẫn chưa thật sự hiểu về Python hay OOP nói chung.

Cái bạn đang thắc mắc là Class variables vs Instance variables, nếu bạn vẫn đang phân vân giữa 2 khái niệm trên thì m nghĩ b nên đọc lại về OOP. Những thứ như vậy không nên hiểu nhầm.

Code bạn viết cộng với việc xử lý multithread thì chắc chắn sẽ xuất hiện deadlock, exceptions hay những logic flaws mà rất khó để debug.

2 Likes

thế thì bạn có tài liệu nào về OOP ko z, cho mk xin với!!!

Về OOP nói chung: https://www.javatpoint.com/java-oops-concepts

Về OOP trong Python: https://realpython.com/python3-object-oriented-programming/

2 Likes

Tiếng Việt thì đây. Còn tiếng Anh thì rất nhiều, nhưng mình nghĩ bạn nên tham khảo trong cuốn Learning Python 5th Edition. Nhìn chung muốn hiểu Python, cứ đọc cuốn đó.

1 Like

thế thì nếu thay self.tricks bằng Dog.tricks đc ko bn??

class Dog(object):

    tricks = []

    def __init__(self, name):
        self.name = name

    def addtrick(self, trick):
        self.tricks.append(trick)

d = Dog('Fido')
e = Dog('Buddy')

d.addtrick('roll over')
e.addtrick('play dead')

print(d.tricks)

:smile: được hay không, thì bạn phải nói cái hàm đó muốn gì đã chứ, nói khơi khơi vậy ai biết.

2 Likes

tricks là list chứa mỗi trick riêng của từng instance, z thì trick để như z có thể hiển thị một thuộc tính ko.

:smiley:
Code bạn ngay từ đâu đã sai rồi, vì ở đây bạn đang lưu tất cả các tricks tại cùng một list

2 Likes

ý mk là nếu ở cái class Employee ở trên mk gọi là self.numbers thì nó chỉ chạy số thứ tự cho mỗi instance. Nhưng mà sao lần này mk cx gọi self.tricks mà nó lại chạy cho cả 2 đối tượng z

Lí do là vì biến đó là một list. Cái này liên quan tới kiến thức về List, chứ không phải class

1 Like

nghĩa là 2 list đc gán = nhau thì cùng chung 1 ô nhớ. Nên cái này append thì cái kia cx append đúng ko!!

2 Likes

Nếu instance không có thì nó lấy của class luôn :smiley:

2 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?