類的物件
有三種物件 |
可以做什麼操作 |
包括什麼屬性 |
類物件 |
屬性引用、例項化 |
函式方法、內建的屬性、類變數 |
例項物件 |
屬性引用 |
函式方法、類變數、例項變數 |
方法物件 |
|
|
1. 類物件、例項物件、方法物件
類[class]是抽象的模型
例項[instance]是根據類建立出來的一個個具體的“物件”
1.1 如何定義類
class 類名(表示該類是從哪個類繼承下來的):
xxx
class ClassName:
<statement-1>
.
.
.
<statement-N>
1.2 屬性引用
class Myclass(object): '''A simple example about class''' i=123 def f(self): return "hello world" def __init__(self,name,score): self.name=name self.score=score # 引用類變數、方法,都是合理的屬性引用,分別返回一個整數和一個函式物件 print(Myclass.i) 123 print(Myclass.f) ->這就叫做建立了方法物件,但要注意這只是建立了物件但不是呼叫了這個方法 <function Student.f at 0x7f81f42c58c8> # 類還有內建的屬性可以被引用 print(Myclass.__doc__) A simple example about class print(Myclass.__name__) Myclass print(Myclass.__dict__) {'__doc__': 'A simple example about class', '__init__': <function Myclass.__init__ at 0x7f0bf8fd0950>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Myclass' objects>, 'i': 123, '__dict__': <attribute '__dict__' of 'Myclass' objects>, 'f': <function Myclass.f at 0x7f0bf8fd08c8>} print(Myclass.__module__) __main__ print(Myclass.__bases__) (<class 'object'>,)
內建類 描述 __dict__ 類的屬性 __doc__ 類的文件字串 __name__ 類名 __module__ 類定義所在的模組 __bases__ 類的所有父類構成元素
1.3 例項化操作
# 例項化操作如下所示,賦值給一個變數,就能夠建立一個例項物件 x=Myclass()
y=Myclass()
print(x.i)
123
print(x.f())
hello world
print(x.__doc__)
A simple example about class
# 建立的例項物件可以自由地繫結屬性
x.iii="a9a"
print(x.iii)
a9a
# 建立的每個例項物件的記憶體地址都不一樣
print(x)
<__main__.Myclass object at 0x7fbe7fa53160>
print(y)
<__main__.Myclass object at 0x7fbe7f7a8630>
1.4 __init__
# 上述的例項化操作建立了一個空的object # 但在很多情況下,我們建立例項物件時,可能都需要有特定的初始狀態。這個由__init__方法實現。 # 當一個類定義了 __init__() 方法, 類在例項化時會自動呼叫 __init__() 方法, 用於建立新的類例項
class Myclass(object): '''A simple example about class''' i=123 def f(self): return "hello world" def __init__(self,name,score): self.name=name self.score=score # 關於__init__,要注意的是:
(1) __init__方法的第一個引數永遠是self,表示建立的例項本身
(2) 有了__init__方法,在建立例項時就不能傳入空的引數了,必須傳入匹配的引數
x=Myclass() TypeError: __init__() missing 2 required positional arguments: 'name' and 'score' x=Myclass("J",11) print(x.name,x.score) J 11
2. 屬性之“變數屬性”、作用域問題、訪問限制問題
2.1 類變數、例項變數、作用域
class test: x=7 #類的直接下級作用域的變數,叫做類變數 def __init__(self,name): self.name=name #例項中的變數,叫例項變數 instance1=test("name1") instance2=test('name2') # 類變數:既是類物件可見的屬性、也是例項物件可見的屬性 print(test.x) 7 print(instance1.x) 7 # 下面的例子中,instance1.x+=100本質是例項物件instance1新建了一個屬性,覆蓋了instance1.x這個變數 # 我們要知道,類變數可以是類物件的屬性也可以是例項物件的屬性,但例項物件的屬性變化影響不了類物件的屬性,也不會影響其他的例項物件 # 反之,類物件屬性的變化倒是能影響例項物件的屬性 test.x=100 print(instance1.x) 100 print(test.x) 100 instance1.x+=100 print(instance1.x) 107 print(test.x) 100 print(instance2.x) 100
2.2 訪問限制
# 如果要讓內部屬性不被外部訪問,可以把屬性的名稱前加上兩個下劃線__,在Python中,例項的變數名如果以__開頭,就變成了一個私有變數(private),只有內部可以訪問,外部不能訪問 # 這樣就確保了外部程式碼不能隨意修改物件內部的狀態,這樣通過訪問限制的保護,程式碼更加健壯 class Student(object): def __init__(self,name,score): self.__name=name self.__score=score stu=Student('J',100) print(stu.__score) AttributeError: 'Student' object has no attribute '__score' # 如果要允許外部訪問者兩個變數,可以增加get方法(get_name()和get_score()) # 如果又要允許外部修改這兩個變數,可以增加set_score,雖然顯得大費周折,但我們可以順帶對引數做個檢查 class Student(object): def __init__(self,name,score): self.__name=name self.__score=score def get_name(self): return '{}'.format(self.__name) def get_score(self): return '{}'.format(self.__score) def print_stu(self): print('%s:%s' % (self.__name,self.__score)) def set_score(self,score): if 0<=score<=100: self.__score=score else: raise ValueError('bad score') stu=Student('J',100) print(stu.get_name()) J print(stu.get_score()) 100 stu.print_stu() J:100
stu.set_score(99);print(stu.get_score()) 99 stu.set_score(101) ValueError: bad score
3. 父類、子類(繼承、多型)
# 基類/父類/超類(base class/super class) <—— 子類(subclass) class Animal(object): def run(self): print("Animal is running...") def run2(self): print("111") class Dog(Animal): def run(self): print("Dog is running...") class Cat(Animal): def run(self): print("Cat is running...") animal=Animal() dog=Dog() cat=Cat() # 子類父類存在同名方法時,子類方法覆蓋父類方法 dog.run() Dog is running... dog.run2() 111 cat.run() Cat is running... # 可以通過isinstance(obj, class_or_tuple, /),可以判斷一個instance object是否屬於某個類 print(isinstance(dog,Dog)) True print(isinstance(dog,Animal)) True print(isinstance(animal,Dog)) False # issubclass(cls, class_or_tuple, /)class Base:
Public_class_var='public class var' #類變數(public) __Private_class_var='private class var' #類變數(private) def __init__(self): self.public_instance_var='public instance var' #例項變數(public) self.__private_instance_var='private instance var' #例項變數(private) def public_instance_method(self): return 'public instance method' def __private_instance_method(self): return 'private instance method' @classmethod def public_class_method(cls): return 'public class method' @classmethod def __private_class_method(cls): return 'private class method' @staticmethod def public_static_method(): return 'public static method' @staticmethod def __private_static_method(): return 'private static method' class Sub(Base): pass sub=Sub() print(sub.__dict__) {'_Base__private_instance_var': 'private instance var', 'public_instance_var': 'public instance var'}
# 子類可以繼承類變數(public)、例項變數(public) class Sub(Base): def print_public_var(self): print(self.Public_class_var) def print_public_instance_var(self): print(self.public_instance_var) sub=Sub() sub.print_public_var() public class var sub.print_public_instance_var() public instance var # 事實上凡是公有的都能繼承,凡是私有的都不能繼承 class Sub(Base): def print_public_class_method(self): print(self.public_class_method()) def print_public_static_method(self): print(self.public_static_method()) def print_public_instance_method(self): print(self.public_instance_method()) sub=Sub() sub.print_public_class_method() public class method sub.print_public_static_method() public static method sub.print_public_instance_method() public instance method
4. classmethod、staticmethod
class A(object): def foo(self,x): print("executing foo({},{})".format(self,x)) @classmethod def class_foo(cls,x): print("executing class_foo({},{})".format(cls,x)) @staticmethod def static_foo(x): print("executing static_foo({})".format(x)) a=A() a.foo(1) executing foo(<__main__.A object at 0x7fe8619c7160>,1) a.class_foo(1) executing class_foo(<class '__main__.A'>,1) a.static_foo(1) executing static_foo(1) a.static_foo('hi') executing static_foo(hi) A.class_foo(1) executing class_foo(<class '__main__.A'>,1) A.static_foo(1) executing static_foo(1) A.foo(1)TypeError: foo() missing 1 required positional argument: 'x' print(a.foo) <bound method A.foo of <__main__.A object at 0x7f57d0ba41d0>> print(a.class_foo) <bound method A.class_foo of <class '__main__.A'>> print(a.static_foo) <function A.static_foo at 0x7f71b0c89b70>