Python基礎之六——類

本博客所有文章僅僅是博主做筆記之用,博客內容並不詳細(以後有空會修改完善),思維也有跳躍之處,想詳細學習博客內容可參考文章後面的參考鏈接,祝學習快樂。

本節要點:

  1. 類的語法
  2. 類變量和實例變量
  3. 特殊方法
  4. 繼承和多態
  5. 私有屬性和方法
  6. 靜態方法、類方法、屬性方法
  7. 反射

1.語法

class ClassName(object): #定義一個類
    """docstring for ClassName"""
    def __init__(self, arg): #構造函數
        super(ClassName, self).__init__()
        self.arg = arg

x = ClassName("yang") #生成一個對象

2. 類變量和實例變量

>>> class ClassName(object):
    """docstring for ClassName"""
    age = 100  #類變量
    list_1 = []   #類變量
    def __init__(self, name, age):
        super(ClassName, self).__init__()
        self.name = name  #實例變量
        self.age = age 
>>> 
>>> x = ClassName("yang",18)
>>> x.age #實例變量會覆蓋類變量
18
>>> y = ClassName('hello',10)
>>> y.age
10
>>> x.age = 17
>>> y.age
10
>>> ClassName.age   #可以直接通過類調用類變量
100
>>> x.IQ  #沒有這個屬性
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'ClassName' object has no attribute 'IQ'
>>> x.IQ = 280  #可以在類外添加新屬性(動態給實例綁定一個屬性)
>>> dir(x)
['IQ', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'list_1', 'name']
>>> x.IQ
280
>>> hasattr(x,'IQ')  
True
>>> hasattr(y,'IQ')  #給x添加的實例變量不會出現在其他對象中
False
>>> ClassName.EQ = 300  #同樣可以在類外添加類變量
>>> x.EQ
300
>>> y.EQ
300

附:動態給實例綁定一個方法

from types import MethodType

class Student(object):
    pass

def set_age(self,age):
    self.age = age

s = Student()

s.set_age = MethodType(set_age,s) # 給實例綁定一個方法

s.set_age(18)

print(s.age)

3. 特殊方法和屬性

特殊方法前後各有兩個下劃線

  1. 構造函數 __init__()
    通過類創建對象時,自動觸發執行。

  2. 析構函數 __del__()
    類一定有析構函數,可以自己定義,銷燬對象的時候自動執行。

>>> class Test(object):
...     def __init__(self):
...         print('生成了一個對象。。。')
...     def __del__(self):
...         print('析構函數執行了。。。')
... 
>>> test = Test()
生成了一個對象。。。
>>> del test
析構函數執行了。。。

3 __doc__
類的描述信息

>>> class ClassName(object):
    """docstring for ClassName""" #__doc__就是這塊東西
    def __init__(self, arg):
        super(ClassName, self).__init__()
        self.arg = arg

... ... ... ... ... ... 
>>> ClassName.__doc__
'docstring for ClassName'

4 __class__和__moudle__

>>> x = ClassName('yang')
>>> x.__class__  #表示當前操作的對象的類是什麼
<class '__main__.ClassName'>
>>> x.__module__ #表示當前操作的對象在哪個模塊
'__main__'

5 __call__ ()
對象後面加括號,觸發執行。使得對象可被調用。

>>> class ClassName(object):
    """docstring for ClassName"""
    def __init__(self, arg):
        super(ClassName, self).__init__()
        self.arg = arg
    def __call__(self):
        print('執行了這裏.')

>>> test = ClassName('yang')
>>> test()
執行了這裏.
>>> print(callable(test))
True

6 __str__()
print(obj)的時候觸發打印這個函數的返回值

>>> class ClassName(object):
    """docstring for ClassName"""
    def __init__(self, arg):
        super(ClassName, self).__init__()
        self.arg = arg
    def __str__(self):
        return '自定義打印。。'  #注意,這裏是return,而不是print

>>> test = ClassName('yang')
>>> print(test)
自定義打印。。

7 __dict__
獲取類的成員(屬性和方法)或者對象的成員(只有屬性)。

class Province:
    country = 'China'
    def __init__(self, name, count):
        self.name = name
        self.count = count

    def func(self, *args, **kwargs):
        print('func')

# 獲取類的成員,即:靜態字段、方法、
print(Province.__dict__)
# 輸出:{'country': 'China', '__module__': '__main__', 'func': <function func at 0x10be30f50>, '__init__': <function __init__ at 0x10be30ed8>, '__doc__': None}

obj1 = Province('HeBei',10000)
print(obj1.__dict__)
# 獲取 對象obj1 的成員
# 輸出:{'count': 10000, 'name': 'HeBei'}

obj2 = Province('HeNan', 3888)
print(obj2.__dict__)
# 獲取 對象obj2 的成員
# 輸出:{'count': 3888, 'name': 'HeNan'}

8 __slots__(*待補充)
https://eastlakeside.gitbooks.io/interpy-zh/content/slots_magic/
http://wiki.jikexueyuan.com/project/start-learning-python/212.html
http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143186739713011a09b63dcbd42cc87f907a778b3ac73000

9 __len__()使得可以使用len(obj)

>>> class Student(object):
    def __len__(self):
        return 100
>>> a = Student()
>>> len(a)
100

4.繼承和多態

繼承

class Person(object): #object是所有類的基類
    """docstring for Person"""
    def __init__(self, name,age):
        self.__flag = False
        self.name = name
        self.age = age

class Student(Person):
    """docstring for Student"""
    def __init__(self, name, age, ID):#重構的構造函數,繼承的屬性和子類新的屬性都要寫進去
        super(Student, self).__init__(name,age) #新式類寫法,將繼承的屬性寫進去,這個函數相當於把父類的構造函數抄了一遍
        self.ID = ID

    def test(self):
        print('go to school')

多繼承

一個類還可以同時繼承多個類
py2 經典類是按深度優先來繼承的,新式類是按廣度優先來繼承的
py3 經典類和新式類都是統一按廣度優先來繼承的

多態

(*僞多態)

5. 私有屬性和方法

在Python中,如果在變量名或函數名前加上‘_ _’,就會將這個變量或函數變爲私有,在類外不可訪問,對子類也不可見,子類不能繼承父類的私有屬性和方法。

但是,事實上,python不存在真正的私有,_ _xxx或者_ _xxx()
可以在類外加上_class_ _xxx來訪問。Python解釋器將私有的變量名改了一個名字來實現類外私有變量名不可見。不同解釋器的改名規則可能不一樣。

總的來說就是,Python本身沒有任何機制阻止你幹壞事,一切全靠自覺。

>>> class Person(object):
        def __init__(self, name):
            self.name = name
            self.__age = 18

        def __test(self):
            print('私有方法')

>>> class Student(Person):
        pass
>>> p = Person('yang')
>>> s = Student('world')
>>> print(p.name)
yang
>>> print(s.name)
world
>>> print(p.__age)
Traceback (most recent call last):
  File "test.py", line 16, in <module>
    print(p.__age)
AttributeError: 'Person' object has no attribute '__age'
>>> print(s.__age)
Traceback (most recent call last):
  File "test.py", line 16, in <module>
    print(s.__age)
AttributeError: 'Student' object has no attribute '__age'
>>> print(p._Person__age)
18
>>> print(s._Person__age)
18
>>> p.__test()
Traceback (most recent call last):
  File "test.py", line 18, in <module>
    p.__test()
AttributeError: 'Person' object has no attribute '__test'
>>> s.__test()
Traceback (most recent call last):
  File "test.py", line 16, in <module>
    s.__test()
AttributeError: 'Student' object has no attribute '__test'
>>> p._Person__test()
私有方法
>>> s._Person__test()
私有方法

6. 靜態方法、類方法、屬性方法

靜態方法

@staticmethod

普通的方法,可以在實例化後直接調用,並且在方法裏可以通過self.調用實例變量或類變量,但靜態方法是不可以訪問實例變量或類變量的(Python本質上沒有不可訪問的東西,只是不能按一般的調用類方法的方式去訪問而已),一個不能訪問實例變量和類變量的方法,其實相當於跟類本身已經沒什麼關係了,它與類唯一的關聯就是需要通過類名來調用這個方法。

靜態方法有什麼用呢?可以把一堆函數集中放在一塊,通過類名來調用,就相當於一個工具包裏面有很多的函數而已。

>>> class Dog(object):
        def __init__(self,name):
            self.name = name

        @staticmethod #截斷跟類的關係
        def test(self): #這樣寫不能以obj.test()來訪問,需要把obj當參數傳進去
            print(self.name)
>>> d = Dog("taidi")
>>> d.test()  #這樣會出錯
>>> d.test(d) #手動傳進來一個參數,這樣就可以了。

類方法

@classmethod

類方法通過@classmethod裝飾器實現,類方法和普通方法的區別是, 類方法只能訪問類變量,不能訪問實例變量。

class Dog(object):
    n = 123
    def __init__(self,name):
        self.name = name

    @classmethod
    def test(self):
        print(self.name) #訪問不了
        print(self.n)  #沒問題

d = Dog("taidi")
d.test() #錯誤

屬性方法

@property

屬性方法的作用就是通過@property把一個方法變成一個靜態屬性

(學習東西的時候一定要知道它的應用場景,先有需求纔會有解決相應需求的方法誕生。生活上也是如此,當你有某種需要的時候,一定會有相應的產品出現的,如果沒有,那恭喜你,你的機會來了。。)

關於@property的知識請移步這裏,這篇教程寫的非常好,從需求出發,引入@property,這樣的教程才能真正學習到一些東西。

7. 反射

getattr(object, name) #name是字符串
hasattr(obj, name)
etattr(obj, name, value)
delattr(obj, name)

class Foo(object):
    def __init__(self):
        self.name = 'wupeiqi'

    def func(self):
        return 'func'

obj = Foo()

# #### 檢查是否含有成員 ####
hasattr(obj, 'name')  #返回True
hasattr(obj, 'func')

# #### 獲取成員 ####
getattr(obj, 'name') #返回的是對象的內存地址
getattr(obj, 'func')

# #### 設置成員 ####
setattr(obj, 'age', 18)
setattr(obj, 'show', lambda num: num + 1)

# #### 刪除成員 ####
delattr(obj, 'name')
delattr(obj, 'func')

參考鏈接:

  1. http://www.cnblogs.com/alex3714/articles/5188179.html
  2. http://www.cnblogs.com/alex3714/articles/5213184.html
  3. http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431864715651c99511036d884cf1b399e65ae0d27f7e000
  4. http://wiki.jikexueyuan.com/project/start-learning-python/212.html
  5. http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143186739713011a09b63dcbd42cc87f907a778b3ac73000
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章