Python OOP: Thắc mắc khi tạo Private Attributes ?

Liên hệ QC

Nguyen Rem

Tất cả chỉ là đưa ra quyết định đúng đắn
Tham gia
23/2/22
Bài viết
211
Được thích
30
Giới tính
Nữ
Em chào các anh chị !
Hiện tại em đang học lý thuyết thì gặp một số chỗ chưa hiểu sau mong các anh chị giúp em giải đáp
Vấn đề:
Theo như lý thuyết có nói thì ta không thể truy cập trực tiếp được vào the __attribute từ bên ngoài class bằng cách instance.__attrribute
1655026594192.png
Lúc em thực hành thì đúng theo lý thuyết nói không thể truy cập được vào thật :
1655026815066.png1655026892696.png
Nhưng lúc em viết tiếp như sau thì nó không bị lỗi nữa .
1655027197339.png1655027222087.png
Chắc các anh chị hiểu ý em nói mà ^^. Mong các anh chị giải thích giúp em !
  • Đường link tham khảo :
  • Đường link tới file python(do không upload được file.py nên em upload tạm lên google drive)
 
Lần chỉnh sửa cuối:
Private có nghĩa là nó là riêng của người thiết kế class. Trên nguyên tắc, nó chả liên quan gì đến chuyện có truy cập được hay không.

Cũng như vàng bạc để trong nhà, không khóa trong tủ. Không hề có nghĩa là chủ nhà mặc định ai muốn lấy thì lấy.

Bình thường thì gặp code của người dùng đụng chạm đến hàng private, compiler sẽ đẩy ra. Nhưng compiler hiếm khi cam đoan nó sẽ làm vậy. Và dẫu nó có hứa đi nữa thì cũng có cả chục cách gạt nó.

Theo đúng tinh thần OOP, private là thuộc tính mà người sử dụng class không cần và không nên biết tới - nhấn mạnh từ "không nên". Bên thiết kế class đã đưa ra các phương thức và thuộc tính public để cho dùng là đủ rồi. Người thiết kế class chỉ bảo đảm phần public sẽ giữ nguyên, phần private hoàn toàn có thể thay đổi.

Ví dụ, class ToTiTe có thuộc tính Long X là public thì nó luôn luôn là Long, và nó luôn luôn diễn tả cái gì mà người ta đã định từ đầu. Trong khi đó, thuộc tính __X (biến private thường được đặt tên có gạch ở đầu) là private thì có thể phiên bản 1 của class người ta đặt là Integer, phiên bản 1.1 là Long và phiên bản 2 đặt là Double. Người sử dụng đem __X ra viết code bị sai ráng chịu.

Chú thích: nếu không biết phân biệt giữa thiết kế và sử dụng thì dẹp quách, đừng rớ vào OOP chi cho mất công.

Chú thích quan trọng:
Tôi giải thích chung ở đây cho các bạn có hứng muốn học OOP. Những điều tôi nói trên giải thích rất sâu về thiết kế lớp. Quý vị không dễ gú-gồ được đâu.
Mấy cái rườm rà khác thì gú-gồ đi. Tôi không có hứng giải thích theo chiều rộng.
 
Em chào các anh chị !
Hiện tại em đang học lý thuyết thì gặp một số chỗ chưa hiểu sau mong các anh chị giúp em giải đáp
Vấn đề:
Theo như lý thuyết có nói thì ta không thể truy cập trực tiếp được vào the __attribute từ bên ngoài class bằng cách instance.__attrribute
View attachment 277211
Lúc em thực hành thì đúng theo lý thuyết nói không thể truy cập được vào thật :
View attachment 277212View attachment 277213
Nhưng lúc em viết tiếp như sau thì nó không bị lỗi nữa .
View attachment 277214View attachment 277215
Chắc các anh chị hiểu ý em nói mà ^^. Mong các anh chị giải thích giúp em !
  • Đường link tham khảo :
  • Đường link tới file python(do không upload được file.py nên em upload tạm lên google drive)
Đơn giản đổi thành 1 gạch nối chân thôi (_) thì sẽ không bị thành name mangling như đoạn link của bạn đã nói rõ
Còn muốn chặt chẽ thì hãy dùng C++ cho nó chặt
 
Private có nghĩa là nó là riêng của người thiết kế class. Trên nguyên tắc, nó chả liên quan gì đến chuyện có truy cập được hay không.

Cũng như vàng bạc để trong nhà, không khóa trong tủ. Không hề có nghĩa là chủ nhà mặc định ai muốn lấy thì lấy.

Bình thường thì gặp code của người dùng đụng chạm đến hàng private, compiler sẽ đẩy ra. Nhưng compiler hiếm khi cam đoan nó sẽ làm vậy. Và dẫu nó có hứa đi nữa thì cũng có cả chục cách gạt nó.

Theo đúng tinh thần OOP, private là thuộc tính mà người sử dụng class không cần và không nên biết tới - nhấn mạnh từ "không nên". Bên thiết kế class đã đưa ra các phương thức và thuộc tính public để cho dùng là đủ rồi. Người thiết kế class chỉ bảo đảm phần public sẽ giữ nguyên, phần private hoàn toàn có thể thay đổi.

Ví dụ, class ToTiTe có thuộc tính Long X là public thì nó luôn luôn là Long, và nó luôn luôn diễn tả cái gì mà người ta đã định từ đầu. Trong khi đó, thuộc tính __X (biến private thường được đặt tên có gạch ở đầu) là private thì có thể phiên bản 1 của class người ta đặt là Integer, phiên bản 1.1 là Long và phiên bản 2 đặt là Double. Người sử dụng đem __X ra viết code bị sai ráng chịu.

Chú thích: nếu không biết phân biệt giữa thiết kế và sử dụng thì dẹp quách, đừng rớ vào OOP chi cho mất công.

Chú thích quan trọng:
Tôi giải thích chung ở đây cho các bạn có hứng muốn học OOP. Những điều tôi nói trên giải thích rất sâu về thiết kế lớp. Quý vị không dễ gú-gồ được đâu.
Mấy cái rườm rà khác thì gú-gồ đi. Tôi không có hứng giải thích theo chiều rộng.
Dạ vâng ạ ! Em đã đọc bài của anh rồi :> Nhưng mà em vẫn chưa hiểu anh muốn nói gì ấy . Nên là em xin phép để bài viết của anh lại lúc nào em "khỏe" hơn thì em vô coi lại nhé anh ! Hoặc anh có thể viết một bài khác nó bớt sâu đi thì may ra em mới hiểu được ấy anh
 
Đơn giản đổi thành 1 gạch nối chân thôi (_) thì sẽ không bị thành name mangling như đoạn link của bạn đã nói rõ
Còn muốn chặt chẽ thì hãy dùng C++ cho nó chặt
Không anh ! Chắc anh chưa hiểu em nói gì và hình như anh cũng đọc lướt qua cái link em gửi thì phải ! Mong anh đọc lại bài này giúp em với
Như em đã nói là
Lúc em thực hành thì đúng theo lý thuyết nói không thể truy cập được vào thật :
1655026815066.png
1655026892696.png
Tức là cái câu lệnh print(counter.__current) nó bị lỗi (lý thuyết đúng) :
1655031564918.png
Theo như lý thuyết nói nếu viết __attribute thì nó đã trở thành mangling rồi thì bây giờ phải dùng câu lệnh
instance._class__attribute chứ không được dùng instance.__attribute được nữa vì nó sẽ gây lỗi nhưng mà
Nhưng lúc em viết tiếp như sau thì nó không bị lỗi nữa .
1655027197339.png
1655027222087.png
trong trường hợp hai em viết thì nó không thông báo lỗi nữa vậy lý thuyết có gì sai?

Mà câu trả lời của anh lại là
Đơn giản đổi thành 1 gạch nối chân thôi (_) thì sẽ không bị thành name mangling
Rất mâu thuẫn (Nó chả có nghĩa gì cả -- nó không giải thích với câu hỏi mà em đề ra). Chắc là anh có đưa cho em giải pháp là đổi thành 1 dấu gạch nối nhưng mà đổi thế nào , đổi chỗ nào thì anh phải cho em biết chứ . Anh đã bỏ thời gian để đọc bài và trả lời của em rồi thì thay vì một công viết sao anh không thể viết chỉ tiết cho em đọc dễ hơn vậy
 
Đơn giản đổi thành 1 gạch nối chân thôi (_) thì sẽ không bị thành name mangling như đoạn link của bạn đã nói rõ
Còn muốn chặt chẽ thì hãy dùng C++ cho nó chặt
Cái chuyện một hay hai gạch, mắm nêm nấu măng cá linh gì đó chỉ là cách hoạt động của compiler thôi. Không phải là căn bản lý thuyết OOP.

Vì tiêu đề thớt nói "private" cho nên ở bài trên tôi giải thích cách hiểu từ ấy. Đó là lý thuyết căn bản, không phải riêng của Python.

Thực chất, ba cái mớ này chỉ là "tầm nhìn thấy" (visibility) của biến/hàm (attributes). Không truy cập được có nghĩa là ở trong ngữ cảnh ấy, compiler không "nhìn thấy" cái attribute ấy. Và vì không thấy, không biết là gì cho nên nó báo lỗi.

Python là ngôn ngữ dễ dãi. Người ta bỏ luôn quan niệm "private". Tức là mọi attributes đều là public, muốn truy cập thì cứ tự nhiên. Compiler của Python nhìn thấy tất cả mọi attributes của class.

Cái gạch chỉ là cách đặt tên để phân biệt. Như tôi nói ở trên, theo lệ không thành văn (có nghĩa là nên theo chứ chẳng có gì bắt buộc) thì các attributes nội được đặt tên với dấu gạch.

Python xí xọn, đặt thêm cái lệ "muốn giấu thì tôi cho cách giấu". Thế là thêm cái luật nếu tên bắt đầu bằng hai gạch thì compiler chừa ra, không chịu truy cập. Thực sự nó có thấy, nhưng nó còn ỏng ẹo: đây là "hàng kín", không truy cập khơi khơi vậy nhé! Muốn compiler không ỏng ẹo thì lúc truy cập gắn thêm tên class vào: ngụ ý, tao thực sự biết mình làm gì, và muốn truy cập "hàng kín" ấy.
Mục đích là để tránh chuyện "lỡ tay đụng hàng kín".

Hết.
 
Tôi hiểu bạn thắc mắc gì.

Thông tin: Trong vd. Delphi bạn có thể tạo đối tượng của một lớp nào đó. Nhưng không truy cập được tới các trường PRIVATE. Mọi truy cập tới dữ liệu có trong đối tượng đều được thực hiện qua các thuộc tính, phương thức. Nhưng trong Python code hoàn toàn có thể truy cập vào tất cả các trường vì không có khái niệm trường PRIVATE như trong tài liệu bạn cung cấp
Python doesn’t have a concept of private attributes. In other words, all attributes are accessible from the outside of a class.

Bây giờ xét về code
Mã:
class Counter:
    def __init__(self):
        self.__current = 0

    def increment(self):
        self.__current += 1

    def value(self):
        return self.__current

    def reset(self):
        self.__current = 0

h = Counter()
print(h.__current)

Bạn chạy sẽ có lỗi. Tại sao?

Như đã biết
If you prefix an attribute name with double underscores (__) like this:

__attribute

Python will automatically change the name of the __attribute to:

_class__attribute
Tức trong code bạn vẫn thấy là LỚP Counter có trường __current nhưng thực chất sau cánh gà Python đã đổi tên thuộc tính thành _Counter__current. Vậy kết cục là Counter KHÔNG CÓ trường __current mà chỉ có trường _Counter__current. Chính vì thế truy cập vào __current tức print(h.__current) thì có lỗi do không có - không còn trường với tên là __current, chứ chả phải vì __current là PRIVATE hay không PRIVATE - trường không tồn tại chứ không phải là nó tồn tại nhưng "không nhìn thấy", "cấm truy cập", "đụng vào điện giật chết người", "không phận sự vào thì đi tù" ...

Nhưng truy cập vào _Counter__current tức print(h._Counter__current) thì không có lỗi do đúng là có trường với tên là _Counter__current (được đổi tên từ __current)

Thế tại sao code sau lại không có lỗi?
Mã:
class Counter:
    def __init__(self):
        self.__current = 0

    def increment(self):
        self.__current += 1

    def value(self):
        return self.__current

    def reset(self):
        self.__current = 0

h = Counter()
h.__current = 12
print(h.__current)

Chỉ thêm một dòng h.__current = 12 mà hết lỗi? Tại sao?

Khi chạy code
Mã:
class Counter:
    bla = 12345
    lala = None
h = Counter()
print (h.bla)
h.hichic = "Ngay mai em di"
print(h.hichic)
sẽ có kết quả

12345
Ngay mai em di

Để giải thích thì tôi cung cấp cho bạn vài thông tin:
- trong khai báo LỚP có thể khai báo các trường và hoặc thiết lập giá trị của trường ở thời điểm chào buổi sáng (trường bla) hoặc không (trường lala)
- không thể ĐỌC ra (sẽ có LỖI) giá trị của trường nếu trường đó chưa có trong LỚP (như print(h.__current) ở trên). Tuy nhiên ở thời điểm THIẾT LẬP giá trị cho trường chưa tồn tại thì trường đó được TẠO và có giá trị như THIẾT LẬP.

Như vậy ở thời điểm THIẾT LẬP h.hichic = "Ngay mai em di" thì trường hichic được tạo và có giá trị = "Ngay mai em di"

Bây giờ thì bạn hiểu rồi đó.

h = Counter()
print(h.__current)


có lỗi do ĐỌC ra giá trị của trường không tồn tại __current (đã bị đổi tên thành _Counter__current)

Nhưng code

h = Counter()
h.__current = 12 # (A)
print(h.__current) # (B)


không có lỗi ở (B) do trường __current được tạo ở thời điểm (A).

Ta xét lần cuối:

Mã:
class Counter:
    def __init__(self):
        self.__current = 0

    def increment(self):
        self.__current += 1

    def value(self):
        return self.__current

    def reset(self):
        self.__current = 0

h = Counter()
print(h._Counter__current)   # (A)
h.__current = 12345             # (B)

print(h._Counter__current)   # (C)
print(h.__current)           # (D)

Ở thời điểm (A) đối tượnh h chỉ có trường _Counter__current vì trường khai báo __current đã bị đổi tên thành _Counter__current.
Ở thời điểm (B) do THIẾT LẬP giá trị cho trường không tồn tại __current nên trường __current được TẠO và có giá trị 12345.
Dòng (C) và (D) cho thấy rõ là đối tượng có tận 2 trường: trường _Counter__current có giá trị 0, và trường __current mới được tạo có giá trị 12345.

Lưu ý: trường __current được tạo ở dòng (B) không phải là trường __current được khai báo trong LỚP Counter, vì trường __current trong LỚP Counter đã bị đổi tên thành _Counter__current. Trường được thêm ở (B) là trường mới, đừng nhầm lẫn.


Về PRIVATE thì như bạn đã đọc
Python doesn’t have a concept of private attributes. In other words, all attributes are accessible from the outside of a class.

trong Python không có khái niệm về trường PRIVATE. Trong vd. Delphi thì bạn không thể truy cập trực tiếp vào PRIVATE.
 
Lần chỉnh sửa cuối:
Tôi hiểu bạn thắc mắc gì.

Thông tin: Trong vd. Delphi bạn có thể tạo đối tượng của một lớp nào đó. Nhưng không truy cập được tới các trường PRIVATE. Mọi truy cập tới dữ liệu có trong đối tượng đều được thực hiện qua các thuộc tính, phương thức. Nhưng trong Python code hoàn toàn có thể truy cập vào tất cả các trường vì không có khái niệm trường PRIVATE như trong tài liệu bạn cung cấp


Bây giờ xét về code
Mã:
class Counter:
    def __init__(self):
        self.__current = 0

    def increment(self):
        self.__current += 1

    def value(self):
        return self.__current

    def reset(self):
        self.__current = 0

h = Counter()
print(h.__current)

Bạn chạy sẽ có lỗi. Tại sao?

Như đã biết

Tức trong code bạn vẫn thấy là LỚP Counter có trường __current nhưng thực chất sau cánh gà Python đã đổi tên thuộc tính thành _Counter__current. Vậy kết cục là Counter KHÔNG CÓ trường __current mà chỉ có trường _Counter__current. Chính vì thế truy cập vào __current tức print(h.__current) thì có lỗi do không có - không còn trường với tên là __current, chứ chả phải vì __current là PRIVATE hay không PRIVATE - trường không tồn tại chứ không phải là nó tồn tại nhưng "không nhìn thấy", "cấm truy cập", "đụng vào điện giật chết người", "không phận sự vào thì đi tù" ...

Nhưng truy cập vào _Counter__current tức print(h._Counter__current) thì không có lỗi do đúng là có trường với tên là _Counter__current (được đổi tên từ __current)

Thế tại sao code sau lại không có lỗi?
Mã:
class Counter:
    def __init__(self):
        self.__current = 0

    def increment(self):
        self.__current += 1

    def value(self):
        return self.__current

    def reset(self):
        self.__current = 0

h = Counter()
h.__current = 12
print(h.__current)

Chỉ thêm một dòng h.__current = 12 mà hết lỗi? Tại sao?

Khi chạy code
Mã:
class Counter:
    bla = 12345
    lala = None
h = Counter()
print (h.bla)
h.hichic = "Ngay mai em di"
print(h.hichic)
sẽ có kết quả

12345
Ngay mai em di

Để giải thích thì tôi cung cấp cho bạn vài thông tin:
- trong khai báo LỚP có thể khai báo các trường và hoặc thiết lập giá trị của trường ở thời điểm chào buổi sáng (trường bla) hoặc không (trường lala)
- không thể ĐỌC ra (sẽ có LỖI) giá trị của trường nếu trường đó chưa có trong LỚP (như print(h.__current) ở trên). Tuy nhiên ở thời điểm THIẾT LẬP giá trị cho trường chưa tồn tại thì trường đó được TẠO và có giá trị như THIẾT LẬP.

Như vậy ở thời điểm THIẾT LẬP h.hichic = "Ngay mai em di" thì trường hichic được tạo và có giá trị = "Ngay mai em di"

Bây giờ thì bạn hiểu rồi đó.

h = Counter()
print(h.__current)


có lỗi do ĐỌC ra giá trị của trường không tồn tại __current (đã bị đổi tên thành _Counter__current)

Nhưng code

h = Counter()
h.__current = 12 # (A)
print(h.__current) # (B)


không có lỗi ở (B) do trường __current được tạo ở thời điểm (A).

Ta xét lần cuối:

Mã:
class Counter:
    def __init__(self):
        self.__current = 0

    def increment(self):
        self.__current += 1

    def value(self):
        return self.__current

    def reset(self):
        self.__current = 0

h = Counter()
print(h._Counter__current)   # (A)
h.__current = 12345             # (B)

print(h._Counter__current)   # (C)
print(h.__current)           # (D)

Ở thời điểm (A) đối tượnh h chỉ có trường _Counter__current vì trường khai báo __current đã bị đổi tên thành _Counter__current.
Ở thời điểm (B) do THIẾT LẬP giá trị cho trường không tồn tại __current nên trường __current được TẠO và có giá trị 12345.
Dòng (C) và (D) cho thấy rõ là đối tượng có tận 2 trường: trường _Counter__current có giá trị 0, và trường __current mới được tạo có giá trị 12345.

Lưu ý: trường __current được tạo ở dòng (B) không phải là trường __current được khai báo trong LỚP Counter, vì trường __current trong LỚP Counter đã bị đổi tên thành _Counter__current. Trường được thêm ở (B) là trường mới, đừng nhầm lẫn.


Về PRIVATE thì như bạn đã đọc


trong Python không có khái niệm về trường PRIVATE. Trong vd. Delphi thì bạn không thể truy cập trực tiếp vào PRIVATE.
Em đã đọc bài của anh rồi ạ . Thật xịn quá đi ! Em cảm ơn anh nhiều lắm
Lúc đầu em cũng nghĩ là chắc nó được tạo mới nhưng mà không thể giải thích được tại sao . Đến bây giờ khi đọc lại lý thuyết và dựa vào cách trả lời của anh thì em đã hiểu rồi ạ
Lưu ý: trường __current được tạo ở dòng (B) không phải là trường __current được khai báo trong LỚP Counter, vì trường __current trong LỚP Counter đã bị đổi tên thành _Counter__current. Trường được thêm ở (B) là trường mới, đừng nhầm lẫn.
Ồ !!! Hóa ra cái __current được tạo ở dòng (B) là một Class Variable . Nó được thêm mới vào Class Counter sau khi Class Counter được tạo
1655063175544.png1655063196479.png
Cảm ơn anh đã dành thời gian để đọc bài và sửa lỗi giúp em .
Nghe tên Dephil em thấy rất thú vị . Nhưng chắc cái này em nên tìm hiểu sau thì vẫn hơn :>
 
Lần chỉnh sửa cuối:
Em đã đọc bài của anh rồi ạ . Thật xịn quá đi ! Em cảm ơn anh nhiều lắm
Lúc đầu em cũng nghĩ là chắc nó được tạo mới nhưng mà không thể giải thích được tại sao . Đến bây giờ khi đọc lại lý thuyết và dựa vào cách trả lời của anh thì em đã hiểu rồi ạ

Ồ !!! Hóa ra cái __current được tạo ở dòng (B) là một Class Variable . Nó được thêm mới vào Class Counter sau khi Class Counter được tạo
View attachment 277229View attachment 277230
Cảm ơn anh đã dành thời gian để đọc bài và sửa lỗi giúp em .
Nghe tên Dephil em thấy rất thú vị . Nhưng chắc cái này em nên tìm hiểu sau thì vẫn hơn :>
Nói ngắn gọn thì sau khi tạo đối tượng thì chỉ ĐỌC (read) được những trường được khai báo trong LỚP. Đọc trường chưa tồn tại sẽ có lỗi. Nhưng có thể THIẾT LẬP (write) trường chưa tồn tại. Đơn giản là lúc đó trường chưa tồn tại sẽ được tạo và có giá trị (write giá trị).

Trường được khai báo với tiền tố __ (2 ký tự _) __<tên trường> sẽ bị Python đổi thành _<tên lớp>__<tên trường>, còn trường __<tên trường> không tồn tại. Lúc đó muốn ĐỌC trường có trong LỚP thì phải dùng tên _<tên lớp>__<tên trường> (đang tồn tại) chứ không thể dùng tên __<tên trường> (không còn tồn tại).

Còn đó là Class Variable hay Class constant hay Class Ngày mai em đi *** tôi không quan tâm. Nói cho cùng tôi không thạo tiếng Anh tới mức phân biệt được những nuance. Hiểu được vấn đề, bản chất thôi. Còn nó có tên là gì thì chỉ để có từ để nói trên bàn nhậu, viết trong bài luận, chứ còn để viết code thì chỉ cần hiểu.

Có nhiều phương pháp trong Toán hay lập trình tôi sử dụng tới nhuần nhuyễn nhưng nói chuyện với người Việt tôi không nói được tên của chúng. Nhưng có nhiều người biết tên nhưng họ không biết sử dụng. Ăn nhau hơn nhau ở chỗ hiểu được vấn đề chứ không phải là biết tên.

***: với tôi extension và version là các fields (trường) chứ không là Variable. Bạn muốn gọi thế nào tùy bạn nhưng ăn nhau, hơn nhau ở chỗ hiểu được vấn đề chứ không phải khoe là biết "người ta" gọi đó là gì.
 
Lần chỉnh sửa cuối:
Nói ngắn gọn thì sau khi tạo đối tượng thì chỉ ĐỌC (read) được những trường được khai báo trong LỚP. Đọc trường chưa tồn tại sẽ có lỗi. Nhưng có thể THIẾT LẬP (write) trường chưa tồn tại. Đơn giản là lúc đó trường chưa tồn tại sẽ được tạo và có giá trị (write giá trị).

Trường được khai báo với tiền tố __ (2 ký tự _) __<tên trường> sẽ bị Python đổi thành _<tên lớp>__<tên trường>, còn trường __<tên trường> không tồn tại. Lúc đó muốn ĐỌC trường có trong LỚP thì phải dùng tên _<tên lớp>__<tên trường> (đang tồn tại) chứ không thể dùng tên __<tên trường> (không còn tồn tại).

Còn đó là Class Variable hay Class constant hay Class Ngày mai em đi *** tôi không quan tâm. Nói cho cùng tôi không thạo tiếng Anh tới mức phân biệt được những nuance. Hiểu được vấn đề, bản chất thôi. Còn nó có tên là gì thì chỉ để có từ để nói trên bàn nhậu, viết trong bài luận, chứ còn để viết code thì chỉ cần hiểu.

***: với tôi extension và version là các fields (trường) chứ không là Variable. Bạn muốn gọi thế nào tùy bạn nhưng ăn nhau, hơn nhau ở chỗ hiểu được vấn đề chứ không phải khoe là biết "người ta" gọi đó là gì.
Dạ vâng ạ ! Em vừa phát hiện ra một vấn đề cực nghiêm trọng đó là cái trên người ta gọi là instance variable ^^ chứ không phải là class Variable hi :>
1655065969166.png
1655066008601.png

Học lập trình này thì thật sự rất hay và thú vị ! Kiểu nếu viết sai code thì như trời sập còn nếu viết đúng mà chạy được thì thỏa mãn vô cùng ^^ Em lại cảm ơn anh lần nữa :> --Em đang rất thỏa mãn hi--
Em cảm ơn tất cả các anh vì đã dành thời gian lẫn tâm trí có hạn của mình để giúp em sửa lỗi và khắc phục <3
 
Lần chỉnh sửa cuối:
Qua đây, thấy rằng
Python là ngôn ngữ đơn giản (giản lược để đỡ phải gõ code nhiều)
NHƯNG chính vấn đề đơn giản sẽ làm nó thiếu nhiều sự chặt chẽ về cú pháp

Do đó nhiều ý kiến khác nhau ví như, một số người thì nói nó đơn giản nên học sớm học ngay là ngôn ngữ lập trình đầu tiên nên học, như nhiều người đang chạy theo mốt (mode) hiện nay vậy (đôi khi chỉ là nghe con người ta nói thế, trẻ con cũng bị lôi vào học đè ra dạy)

Song có 1 số người khác thì không như vậy tức là không nên chọn học python là ngôn ngữ lập trình đầu tiên --> vì nó sẽ làm người học rối thiếu hiểu biết, và không biết tại sao ở những chỗ mà ngôn ngữ thiếu chặt chẽ đó , và rất dễ sai hiểu nhầm - mà có khi người đi trước nói họ cũng không rõ vì không đúng không sai trong 1 số trường hợp ngữ cảnh, và trên hết vì nó đơn giản nên những gì thuộc về rối về quản lý chặt chẽ cú pháp họ đẩy cho người sử dụng ngôn ngữ đó. -- có lẽ đó cũng là lý do PYTHON ở nhiều trường có ngành IT chính thức không ai chọn python là ngôn ngữ căn bản (đầu tiền) để dạy ...

Theo các bạn, anh chị thì có nên hay không nên chọn python học như ngôn ngữ lập trình đầu tiên?
 
Lần chỉnh sửa cuối:
Tài liệu ghi rõ vậy rồi còn gì.

1655086490095.png

Mà cái này rất đơn giản, xem chi tiết cái Class đó có tất cả cái gì là xong thôi mà.

1655086706476.png
 
Qua đây, thấy rằng
Python là ngôn ngữ đơn giản (giản lược để đỡ phải gõ code nhiều)
....

Theo các bạn, anh chị thì có nên hay không nên chọn python học như ngôn ngữ lập trình đầu tiên?
Tùy theo bạn học lập trình theo kiểu lý thuyết hay ứng dụng (tôi chỉ dùng từ "lý thuyết" để phân biệt căn bản, không có nghĩa là không ứng dụng được)

Lập trình lý thuyết mới cần mấy cái chặt chẽ.

Ứng dụng thì cứ tiện mà làm. Python là loại này.

Ngày xưa, sức mạnh của một ngôn ngữ tùy thuộc vào cấu trúc. Ngày nay, sức mạnh của một ngôn ngữ ứng dụng tùy thuojc vào đám thư viện mà nó có thể truy cập.

Lúc lập ra Python, bọn thành lập này là dân chuyên Unix và C (lưu ý: không phải C++). Vì vậy họ có cả đống code thư viện C viết sẵn, làm rất nhiều việc. Cộng thêm là code C nếu viết giỏi thì rất tốc độ. Khi chỉ định ngữ pháp và cấu trúc Python thì họ chú trọng thế nào để kết nối các thư viện thật hiệu quả.

Về câu hỏi của bạn: có nên học Python như ngôn ngữ đầu tiên?
Trả lời: thằng cháu nhà tôi chỉ học R và Python. Nó không hề biết các ngôn ngữ khác. Và với cái nó cần làm (thống kê Y Tế Quần Chúng - Population Health Statistics) thì chả cần biết thêm gì nữa. Excel nó chỉ cần biết căn bản. Dữ liệu thiết kế bảng chuẩn, chuyển qua CSV mấy cái phần mềm chuyên thống kê chúng nhai rồn rột. (từ "nhai" dịch ở "crunch", tiếng nghề của IT)

Lưu ý là Python đâu có buộc bạn phải biết OOP. Cũng như VB dot net. Nhiều người viết code ào ào mà căn bản hiểu biết về OOP là con số không.

Lưu ý thứ hai là những lý thuyết bạn học về OOP như tính gói gọn, đa hình,... chỉ là hướng dẫn những điều nên làm thôi. Không phải bắt buộc. Cũng như nhiều người đưa cái bảng tính Excel như hạch lên, mấy bạn chuyên công thức khủng bở đây vẫn giải quyết được như thường.

Tài liệu ghi rõ vậy rồi còn gì.
...
Người ta nói chuyện đổi tên (mắm nêm nấu măng cá linh) là nhìn vào bên trong. Nhiều người như tôi lười nhìn cái mớ debug dump ấy lắm.

Vì vậy tôi giải thích bằng cách dùng luật tiền tố. Nhìn vào cái thiết kế class, thấy cái tên nào có hai gạch ở đầu thì biết nó không thể truy cập trực tiếp. Cực chẳng đã cần truy cập thì qua tiền tố <tên class>. Hết.
Ở đây người ta chọn tiền tố bằng cách thêm một cái string, tức là đổi tên. Nhưng ở ngôn ngữ khác, có thể người ta chọn tiền tố là một class con nào đó và dùng toán tử dấu chấm (.)

-------

Chú thích:
Cái cụm từ "class attribute" đúng ra không khó hiểu lắm. Nhưng vì nó được nêu lên ở đây cho nên gây hiểu lầm. Xin chớ lầm nó với _class__attribute của Python.

class attribute là danh từ chung. Chúng định nghĩa một loại thuộc tính trong class.
_class__attribute là danh từ riêng. Chúng là tên của thuộc tính nào đó trong class.

Cái danh từ riêng không cần phải giải thích thêm. Cái kia thì có lẽ cần giải thích cho các bạn chưa quen thuộc với LTHĐT:

Về tầm nhìn (visibility) thì class có hai loại attributes: private và public (thực ra còn loại protected, nhưng chưa cần biết tới ở đây)

Về phạm vi thực chất (physical scope) khi thiết kế thì class có hai loại attibutes: loại chung cho cả class (class attributes) và loại riêng biệt cho mỗi đối tượng được dựng lên từ class (tiếng nghề gọi là instance).

class attributes được truy cập qua tên class. Và đối với class, chúng in hệt nhau. Bạn sử dụng chúng mà không cần phải dựng đối tượng (*1)
instance attributes được truy cập qua tên dối tượng. Chúng là thuộc tính riêng của đối tượng. Vì chúng liên quan đến đối tượng cho nên hoàn toàn vô nghĩa nếu sử dụng ngoài đối tượng.
Ví dụ tôi có class XeDoVet. Tôi có thể thiết kế các thuộc tính như loại xe, tuyến đường là thuộc tính riêng. Và ga ra chứa xe là thuộc tính chung.
Như vậy: XeDoVet.Gara = "bến An Đông" --> tất cả xe của tôi sẽ chứa ở bến An Đông.
XeMytho = XeDoVet() (dựng đối tượng) ::: XeMytho.Loai = "Toyota" ::: XeMytho.Tuyen = "SG-Mytho" --> đối tượng XeMytho của tôi chiếc Toyota, và nó chuyên chạy chuyến SG-Mytho.
XeBinhduong = XeDoVet() (dựng đối tượng) ::: XeBinhduong.Loai = "Isuzu" ::: XeBinhduong.Tuyen = "SG-Binhduong" --> đối tượng thứ hai, XeBinhduong của tôi là chiếc Isuzu, và nó chuyên chạy chuyến SG-Binhduong.
Nếu bảo in ra XeMytho.Gara hay XeBinhduong.Gara thì vẫn là "bến An Đông". Bởi vì đó là thuộc tính chung. Cả hai xe, cũng như tất cả mọi xe thuộc class XeDoVet đều ga ra ở đó.

Đối với Python, những thuộc tính instance attributes được khai báo bên trong __init__(self...), những thuộc tính class attributes được khai báo bên ngoài __init__

(*1) đặc điểm của class attributes này được được người ta lợi dụng để viết wrapper class, sử dụng một số hàm thư viện. Tôi thêm chỗ này để bạn nào về sau đọc từ "wrapper class" thì biết người ta nói gì.
 
Lần chỉnh sửa cuối:
Dạ vâng ạ ! Em vừa phát hiện ra một vấn đề cực nghiêm trọng đó là cái trên người ta gọi là instance variable ^^ chứ không phải là class
Tôi đưa ra 3 cụm từ: Class Variable, Class constant, Class Ngày mai em đi, trong đó từ đầu tiên Class không đổi. Vì ý tôi chỉ muốn nói tới từ thứ 2 là Viatable, tôi không bàn về từ Class. Mà từ bài #9 cũng thấy là tôi muốn nói tới từ Variable.

***: với tôi extension và version là các fields (trường) chứ không là Variable

Lập trình chán chê trong Delphi mà không biết đâu là class đâu là instance, đâu là trường dữ liệu (trường lưu trữ data) đâu là thuộc tính (properties) đâu là phương thức (method) thì hơi bị lạ. Trong bài #7 tôi dùng từ rất chính xác. Counter là LỚP, còn h là đối tượng.

Ở bài #9 tôi chỉ muốn nói là cho dù tôi gọi Version là field (trường) hay ai đó gọi là variable thì cũng không quan trọng bằng việc hiểu được bản chất và sử dụng thành thạo, viết được code chuẩn. Thế thôi.

Tôi giải thích thêm chút vì có thể ai đó cho rằng tôi chả biết gì, không phân biệt được đâu là class đâu là instance - có thể hiểu lầm câu
Nói cho cùng tôi không thạo tiếng Anh tới mức phân biệt được những nuance.
 
Web KT
Back
Top Bottom