特殊變量
- 類似__xx,以雙下划線開頭的實例變量名,就變成了一個私有變量(private),只有內部可以訪問,外部不能訪問;
- 類似__xx__,以雙下划線開頭,並且以雙下划線結尾的,是特殊變量,特殊變量是可以直接訪問的,它不是private變量,下面會介紹Python中的常見特殊變量;
- 類似_x,以單下划線開頭的實例變量名,這樣的變量外部是可以訪問的,但是,按照約定俗成的規定,當你看到這樣的變量時,意思就是,“雖然我可以被訪問,但是請把我視為私有變量,不要隨意訪問”。
內置函數
- type(),type()函數返回type類型
用法:
import types type('abc')==types.StringType type(u'abc')==types.UnicodeType type([])==types.ListType type(str)==types.TypeType
最后這種類型叫做TypeType,所有類型本身就是TypeType。
也可以對函數或者類:
- isinstance(),判斷一個對象是否屬於某個類型
一個例子:
class P(object): pass class C(P): pass p = P() c = C() print isinstance(p, P) print isinstance(c, P) print isinstance(p, C) # False print isinstance(c, C)
如上,子類實例即是父類類型,也是子類類型,但父類實例不屬於子類類型。
isinstance()也可以代替type()的作用:
isinstance('a', str) isinstance(u'a', unicode) isinstance('a', unicode) #False
- dir(),獲取對象的屬性和方法列表
- getattr(),獲取對象的特定屬性
- hasattr(),對象是否存在某個屬性
- setattr(),設置對象的屬性
用法:
class P(object): name = "cq" def __init__(self, age): self.age = age print hasattr(P, "name") # True print hasattr(P, "age") # False setattr(P, "age", 31) print getattr(P, "name") # cq print getattr(P, "age") # 31
特殊變量
__doc__
定義文檔字符串
__dict__
類的屬性列表
__class__
__slots__
對類的實例可以動態的綁定屬性和方法,如下:
from types import MethodType def set_age(self, age): self.age = age class P(object): pass p = P() p.name = 'chenqi' p.set_age = MethodType(set_age, p, P) p.set_age(31) print p.name print p.age
對一個實例添加的屬性(或方法)僅在該實例有效,對其它實例不起作用。
如果想讓添加的方法對所有實例都生效,可以綁定到類上:
P.set_age = MethodType(set_age, None, P)
最后,__slots__的作用就是限制對類動態綁定的屬性范圍,例如:
class P(object): __slots__ = ("name", "age") pass
如上,除了"name"和"age"之外的屬性就不能再增加了;
注意:__slots__屬性不會繼承給子類,僅在當前類生效。
__init__
創建實例的時候,可以調用__init__方法做一些初始化的工作:
class Student(object): def __init__(self, name, score): self.name = name self.score = score def print_score(self): print('%s: %s' % (self.name, self.score))
與普通的實例方法類似,如果子類不重寫__init__,實例化子類時,會自動調用父類的__init__;
如果子類重寫了__init__,實例化子類時,則只會調用子類的__init__,此時如果想使用父類的__init__,可以使用super函數,如下:
class P(object): def __init__(self, name, score): self.name = name self.score = name class C(P): def __init__(self, name, score, age): super(C, self).__init__(name, score) self.age = age c = C('cq', 100, 31)
__new__
注意:__init__是實例創建之后調用的第一個方法,而__new__更像構造函數,它在__init__之前被調用。
另外,__new__方法是一個靜態方法,第一參數是cls,__new__方法必須返回創建出來的實例。
例如,用__new__實現單例模式:
class Singleton(object): def __new__(cls): # 關鍵在於這,每一次實例化的時候,我們都只會返回這同一個instance對象 if not hasattr(cls, 'instance'): cls.instance = super(Singleton, cls).__new__(cls) return cls.instance obj1 = Singleton() obj2 = Singleton() obj1.attr1 = 'value1' print obj1.attr1, obj2.attr1 print obj1 is obj2
__del__
類似析構函數。
class NewClass(object): num_count = 0 def __init__(self,name): self.name = name self.__class__.num_count += 1 print name,NewClass.num_count def __del__(self): self.__class__.num_count -= 1 print "Del",self.name,self.__class__.num_count a = NewClass("a") b = NewClass("b") c = NewClass("c") del a del b del c
注意:用del刪除一個對象的時候,不一定會調用__del__,只有在對象的引用計數為零時,__del__()才會被執行。
__enter__
__exit__
這兩個方法是用於支持with語句的上下文管理器。
例如讓文件句柄支持with語法的實現:
class File(object): def __init__(self, file_name, method): self.file_obj = open(file_name, method) def __enter__(self): return self.file_obj def __exit__(self, type, value, traceback): self.file_obj.close() with File('demo.txt', 'w') as opened_file: opened_file.write('Hola!')
__iter__
next
如果一個類想被用於for ... in
循環,類似list或tuple那樣,就必須實現一個__iter__()
方法,該方法返回一個迭代對象,然后,Python的for循環就會不斷調用該迭代對象的next()
方法拿到循環的下一個值,直到遇到StopIteration錯誤時退出循環。
class Fib(object): def __init__(self): self.a, self.b = 0, 1 # 初始化兩個計數器a,b def __iter__(self): return self # 實例本身就是迭代對象,故返回自己 def next(self): self.a, self.b = self.b, self.a + self.b # 計算下一個值 if self.a > 100000: # 退出循環的條件 raise StopIteration(); return self.a # 返回下一個值
__call__
實例可以像函數一樣調用。
class Student(object): def __init__(self): self.name = "Michael" def __call__(self): print '__call__ called' s = Student() s()
注意:callable()函數可用於判斷一個對象是否可調用!
__str__,返回用戶看到的字符串
__repr__,返回開發者看到的字符串(用於調試)
# test.py class P(object): def __str__(self): return "__str__ called" def __repr__(self): return "__repr__ called" p = P()
可以看下__str__和__repr__的區別:
>>> from test import p >>> p __repr__ called >>> print p __str__ called
__getitem__
__setitem__
__delitem__
支持下標(或切片)操作的函數,
例如:
class Fib(object): def __getitem__(self, n): if isinstance(n, int): a, b = 1, 1 for x in range(n): a, b = b, a + b return a
if isinstance(n, slice): start = n.start stop = n.stop a, b = 1, 1 L = [] for x in range(stop): if x >= start: L.append(a) a, b = b, a + b return L fib = Fib() print fib[10] print fib[0:10]
__getattr__
__getattribute__
__setattr__
__delattr__
支持點操作(即 "對象.屬性" 訪問方式),
當訪問不存在的屬性時,才會使用__getattr__ 方法.
class Student(object): def __init__(self): self.name = "Michael" def __getattr__(self, attr): print '__getattr__ called' if attr=='score': return 99 elif attr=='name': return "Tom" s = Student() print s.score # 99 print s.name # Michael
Python的字典支持下標操作,但不支持 "." 操作,如果想讓其支持,如下實現:
class Storage(dict): __slots__ = () """ A Storage object is like a dictionary except `obj.foo` can be used in addition to `obj['foo']`. >>> o = Storage(a=1) >>> o.a 1 >>> o['a'] 1 >>> o.a = 2 >>> o['a'] 2 >>> del o.a >>> o.a Traceback (most recent call last): ... AttributeError: 'a' >>> 'b' in o False """ def __getattr__(self, key): try: return self[key] except KeyError, k: raise AttributeError(k) def __setattr__(self, key, value): self[key] = value def __delattr__(self, key): try: del self[key] except KeyError, k: raise AttributeError(k) def __repr__(self): return '<Storage ' + dict.__repr__(self) + '>'
參考文檔:
https://infohost.nmt.edu/tcc/help/pubs/python/web/special-methods.html