Ngôn ngữ Python ( Chương IV. Lớp trong Python)

IV. Lp trong Python:
1. Cú pháp đnh nghĩa lp:

        Python s dng mt cách thc khá đơn gin đ đnh nghĩa mt lp.Cú pháp như sau:

class ClassName:
    <statement-1>
    .
    .
    .
    <statement-N>
 
        Cũng ging như đnh nghĩa hàm, mt lp phi được đnh nghĩa trước khi nó có th s dng.Thc tế, các lnh viết trong đnh nghĩa lp thường s dng là các đnh nghĩa hàm.
        Đi tượng lp s được to ra ngay sau khi đnh nghĩa lp kết thúc.

2. Các đi tượng lp:
        Các đi tượng lp trong Python h tr 2 thao tác : tham chiếu thuc tính và thc th.
2.1. Tham chiếu thuc tính
        Cú pháp tham chiếu thuc tính ca các đi tượng lp cũng như cú pháp chun cho tt c các tham chiếu thuc tính trong Python:
        Obj.name
        Giá tr ca tên thuc tính là tt c các tên mà nm trong không gian tên ca lp khi đi tượng được to ra.
Xét mt lp được đnh nghĩa như sau:
class MyClass:
    "A simple example class"
    i = 12345
    def f(self):
        return 'hello world'
Thì MyClass.i và MyClass.f là các giá tr tham chiếu thuc tính, tr v mt s nguyên và mt đi tượng hàm.
2.2. Thc th lp:
        Thc th lp s dng ký hiu hàm, mô t đi tượng lp như là mt hàm không tham s và tr v mt thc th mi ca lp đó. Ví d (gi s đã có lp MyClass trên):
            x = MyClass()
to ra mt thc th ca lp này và đăng kí đi tượng to ra vi biến cc b x.
          Việc thao tác một thực thể ( gọi một đối tượng lớp) tạo ra một đối tượng rỗng. Có nhiều lớp mục đích là để tạo ra các đối tượng với các thực thể  thỏa mãn một trạng thái khởi tạo xác định. Vì thế một lớp có thể định nghĩa một phương thức đặc biệt tên là __init__( ), giống như sau:
def __init__(self):
        self.data = []
          Khi một lớp định nghĩa một phương thức __init__( ), thực thể lớp tự động gọi đến hàm __init__( ) cho thực thể vừa được tạo ra. Vì thế trong ví dụ trên, một thực thể khởi tạo mới có thể thu được bởi:
x = MyClass()
          Tất nhiên, hàm __init__( ) có thể có đối số để linh hoạt hơn. Trong trường hợp đó, các đối số được truyền đến toán tử thực thể lớp  thông qua hàm __init__( ).
Ví dụ:
>>> class Complex:
...     def __init__(self, realpart, imagpart):
...         self.r = realpart
...         self.i = imagpart
... 
>>> x = Complex(3.0, -4.5)
>>> x.r, x.i
(3.0, -4.5)

3. Các đi tượng thc th:
        Đi tượng thc th ch cho phép thao tác duy nht là tham chiếu thuc tính. Có 2 loi thuc tính là: thuc tính d liu và phương thc.
        Thuc tính d liu không cn phi khai báo, ging như biến cc b, chúng t sinh ra ngay ln đu gi đến chúng. Ví d, nếu x là mt thc th ca MyClass to ra trên, thì đon mã dưới đây s in ra giá tr 16

x.counter = 1
while x.counter < 10:
    x.counter = x.counter * 2
print x.counter
del x.counter
 
        Loi tham chiếu thuc tính th 2 là phương thc. Mt phương thc là mt hàm thuc mt đi tượng. Trong ví d trên MyClass.f là mt hàm, còn x.f là mt đi tượng phương thc, không phi mt đi tượng hàm.

4. Các đi tượng phương thc:

        Thông thường mt đi tượng phương thc được gi sau khi nó được chp nhn:
        x.f ( )
        Trong ví d MyClass, li gi trên s tr v xâu ‘hello world’. Tuy nhiên, không cn thiết phi gi 1 phương thc theo đúng cách như trên, vì x.f là mt đi tượng phương thc, có th được lưu tr li và gi ln tiếp theo, ví d:

            xf = x.f
      while True:
            print xf( )
 
            Đoạn mã này sẽ tiếp tục in ra dòng chữ ‘hello world’ cho đến khi ngừng chương trình.
 
5. Tính kế thừa:
5.1. Kế tha đơn
        Trong Python không có khái nim Protected như C++ , ch có các hàm ,d liu thành phn public hay private , và chúng được phân bit qua tên , nhng tên bt đu bng __ và kết thúc có ti đa 1 du _ là private
        Ví d __x , __x_ , __abc là nhng biến private , __y__ ,a ,bc , xyz__ , x_ là nhng biến public . Tương t như vy vi tên hàm.
        Các biến và phương thc private ch có th truy cp ni b trong class đó , các biến và phương thc public có th truy xut trong toàn b chương trình. Ch có 1 loi kế tha là public.
        Cú pháp khai báo mt lp con kế tha như sau

    class DerivedClassName(BaseClassName):
<statement-1>
         .
         .
         .
    <statement-N>

        Xét ví d sau:

        >>> class A:
    sa='Day la thuoc tinh cua lop A'
    __pri='Day la thuoc tinh rieng cua A'
    def __init__(self):
         print 'Ham khoi tao cua lop A'
    pass

>>> class B(A):
         sb='Day la thuoc tinh cua lop B'
         def __init__(self):
             print 'Ham khoi tao cua lop B'

>>> b=B()
Ham khoi tao cua lop B
>>> b.sa
'Day la thuoc tinh cua lop A'
>>> b.sb
'Day la thuoc tinh cua lop B'
>>> b.__pri

Traceback (most recent call last):
  File "<pyshell#261>", line 1, in <module>
    b.__pri
AttributeError: B instance has no attribute '__pri'
>>>


Như thy trên lp A có 1 thuc tính public là sa và 1 thuc tính private là __pri mà lp B kế tha t A cũng không truy xut được. Mt đim lưu ý na là hàm khi to ca B không t gi hàm khi to ca A , do đó người lp trình phi gi hàm khi to ca A .

5.2.Đa kế tha
        Khai báo Đa kế tha cũng như đơn kế tha  ,ch vic thêm danh sách các lp cơ s vào trong cp du () sau tên lp:

class DerivedClassName(Base1, Base2, Base3):
    <statement-1>
    .
    .
    .
    <statement-N>

        Do Python không t gi hàm khi to ca các lp cha nên th t kế tha không quan trng.
        Ví d đa kế tha:

>>> class A:
    sa='Day la thuoc tinh lop A'
    def __init__(self):
         print 'Ham khoi tao lop A'
    pass

>>> class B:
    sb='Day la thuoc tinh lop B'
    def __init__(self):
         print 'Ham khoi tao lop B'
    pass

>>> class C(A,B):
    sc='Day la thuoc tinh lop C'
    def __init__(self):
         print 'Ham khoi tao lop C'
    pass

>>> c=C()
Ham khoi tao lop C
>>> c.sa
'Day la thuoc tinh lop A'
>>> c.sb
'Day la thuoc tinh lop B'
>>> c.sc
'Day la thuoc tinh lop C'
>>>
       
6. Các k thut v chng hàm, chng toán t, hàm và d liu thành phn tĩnh:
6.1. Chng hàm trong class
        Python không h tr chng hàm trong class khi mà không có mt khai báo cht ch v kiu ca d liu các tham s truyn cho hàm , kiu ca chúng được xác đnh tuỳ theo giá tr truyn cho hàm lúc gi hàm.

6.2 Chng toán t
        Chng toán t trong Python được thc hin bng vic khai báo đè lên mt s tên đc bit.Có rt nhiu toán t có th chng trong Python.
Ví d   phương thc __add__(self,x) s đnh nghĩa li phép cng
                    __sub__(self,x) s đnh nghĩa li phép tr
self đây là tham s bt buc phi có đi vi mi phương thc , nó ging con trthis trong C++
               
Xét lp sau
        >>> class A:
         x=1
         y=2.0
         def __add__(self,a):
         self.x-=a
         self.y-=a

>>> a
<__main__.A instance at 0x00BBCF58>
>>> a=A()
>>> a.x
1
>>> a.y
2.0
>>> a+1
>>> a.x
0
>>> a.y
1.0
>>>

6.3 Hàm và d liu thành phn tĩnh
a. Hàm (hay phương thc tĩnh ) được khai báo trong Python như sau

        class C:
    @staticmethod
    def f(arg1, arg2, ...): ...
        Hoc

        class C:
         @classmethod
         def f(arg1,arg2,…):….
               
        S khác nhau gia @staticmethod @classmethod như sau:
- Nếu mt hàm khai báo là @classmethod    thì khi gi hàm, h thng s ngm đnh truyn cho hàm tham s đu tiên là thc th ca chính class đó , do đó hàm phi luôn s dng arg1 nhưself (ging con trthis trong C++ ).
- Nếu mt hàm khai báo là @staticmethod   thì khi gi hàm, h thng s không ngm đnh truyn cho hàm tham s đu tiên là thc th ca chính class đó , do đó hàm này không th biết được thc th nào đã gi mình.

Ví d:

>>> class C:
    @staticmethod
    def hello():
         print 'Hello'
        
>>> C.hello()
Hello


class D:
    @classmethod
    def hello():
         print 'Hello'
        
>>> D.hello()

Traceback (most recent call last):
  File "<pyshell#73>", line 1, in <module>
    D.hello()
TypeError: hello() takes no arguments (1 given)
>>>

Li xy ra trong lp D là do hàm hello khi khai báo không nhn 1 tham s nào, nhưng khi được gi, h thng t thêm tham s đàu tiên là selfvào.

        b. D liu thành phn tĩnh
                D liu thành phn tĩnh ca lp được khai báo ngay sau tên lp

                >>> class A:
             counter=0
             def __init__(self):
                 self.__class__.counter+=1
                 print 'Thuoc tinh tinh',A.counter
                 print 'Thuoc tinh cua lop',self.counter


>>> A.counter
0
>>> a=A()
Thuoc tinh tinh 1
Thuoc tinh cua lop 1
>>> b=A()
Thuoc tinh tinh 2
Thuoc tinh cua lop 2
>>>

        Thuc tính tĩnh được chia s bi tt c các thc th ca lp và bn thân tên lp đó

7. K thut Odds and Ends đi vi lp

          Trong Python thông đôi khi k thut này cũng được s dng đ to ra các kiu d liu ging record trong Pascal hoc struct trong C, đng thi cùng vi mt vài thành phn d liu được đt tên. Ta dùng mt đnh nghĩa lp rng đ thc hin hin điu này:

class Employee:
    pass
 
john = Employee() # Create an empty employee record
 
# Fill the fields of the record
john.name = 'John Doe'
john.dept = 'computer lab'
john.salary = 1000
8. Các phương thc đc bit:

        Có mt s các phương thc được dành đ s dng vi các mc đích đc bit, nó được kết thúc vi 2 du gch dưới. Thông thường các phương thc đó được bt đu vi mt du gch dưới đ đánh du nó là ‘private’ vi phm vi mà nó được s dng trong đó.

Phương thc khi to:
__init__
        Mt trong nhng mc đích ca nó là đ xây dng mt thc th lp, và tên đc bit cho phương thc này là ‘__init__’
        Hàm __init__() được gi trược khi mt thc th được tr v. Ví d:

class A:
    def __init__(self):
         print 'A.__init__()'
a = A()
s đưa ra
A.__init__()

__init__()  có th có đi s, trong trường hp cn thông qua các đi s đ to ra mt thc th. Ví d:

class Foo:
    def __init__ (self, printme):
         print printme
foo = Foo('Hi!')
s đưa ra:
Hi!

Sau đây là mt ví d ch ra s khác nhau gia s dng và không s dng __init__():

class Foo:
    def __init__ (self, x):
         print x
foo = Foo('Hi!')
class Foo2:
    def setx(self, x):
         print x
f = Foo2()
Foo2.setx(f,'Hi!')

S in ra

Hi!
Hi!
Phương thc miêu t:
__str__

        Biến đi mt đi tượng thành mt xâu, như là vi câu lnh print hoc vi hàm str(), nó có th được đưa ra bi __str__. Thông thường __str__ tr v mt bn đã đnh dng ca ni dung đi tượng, điu này s không được thường xuyên thc hin. Ví d:

class Bar:
    def __init__ (self, iamthis):
         self.iamthis = iamthis
    def __str__ (self):
         return self.iamthis
bar = Bar('apple')
print bar

s in ra:
apple

__repr__
       
        Hàm này cũng ging như __str__().  __repr__ được s dng đ tr v biu din ca mt đi tượng trong dng xâu. Thông thường nó có th tr v đi tượng gc. Ví d:

class Bar:
    def __init__ (self, iamthis):
         self.iamthis = iamthis
    def __repr__(self):
         return "Bar('%s')" % self.iamthis
bar = Bar('apple')
print bar
s in ra:
Bar('apple')

Các thuc tính:
__setattr__
       
        Đây là hàm qun lí các thuc tính trong mt lp. Nó được cung cp vi tên và giá tr các biến được đăng kí. Tt nhiên, mi lp có mt __setattr__ mc đnh đơn gin đ thiết lp giá tr ca các biến, nhưng cũng có th gt b nó:

>>> class Unchangable:
... def __setattr__(self, name, value):
... print "Nice try"
...
>>> u = Unchangable()
>>> u.x = 9
Nice try
>>> u.x
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: Unchangable instance has no attribute 'x'

__getattr___

        Cũng ging vi  __setattr__, tr hàm này được gi khi ta  truy nhp vào mt thành viên lp, và mc đnh đơn gin tr v giá tr.

>>> class HiddenMembers:
... def __getattr__(self, name):
... return "You don't get to see " + name
...
>>> h = HiddenMembers()
>>> h.anything
"You don't get to see anything"

__delattr__
        Hàm này được gi đ xóa mt đi tượng

>>> class Permanent:
... def __delattr__(self, name):
... print name, "cannot be deleted"
...
>>> p = Permanent()
>>> p.x = 9
>>> del p.x
x cannot be deleted
>>> p.x
9
9. Đóng gói lớp:
        Bi vì tt c các thành phn ca mt lp trong Python là có th truy nhp bi các hàm và phương thc bên ngoài lp đó, không có cách nào đ đóng gói các hàm ghi đè __getattr__, __setattr__ và __delattr__. Tuy nhiên, thc tế, đ to ta mt lp hoc mt module đ đơn gin người ta ch s dng phn giao din đã dành cho và tránh truy cp đến vùng làm vic ca module khác

No comments:

Post a Comment

Bài đăng mới: