Python中類方法定義及常用的實現方式
1. python類的屬性和方法檢視
class Person_1:
mind = '有思想'
belif = '有信仰'
animal = '高階動物'
def tt():
pass
print(Person_1.__dict__) #查詢類Person中所有的內容,表現形式是字典.
print(Person_1.__dict__['belif']) #查詢類Person中的變數'belif'
class Person_2:
mind = '有思想'
belif = '有信仰'
animal = '高階動物'
def work():
print('666')
def money():
print('777')
print(Person_2.animal) #高階動物
print(Person_2.mind) #有思想
Person_2.mind = '沒有思想' #修改變數'mind'的值,可以通過__dicy__檢視修改後的內容
Person_2.pay = '貨幣交換' #增加變數'pay'和它的值,可以通過__dicy__檢視增加後的內容
Person_2.say = '語言交流'
print (Person_2.work()) #也可以呼叫類中的方法(函式),工作中不用類名去操作
print(Person_2.__dict__) #檢視類中所有的內容
執行:
{'__module__': '__main__', 'mind': '有思想', 'belif': '有信仰', 'animal': '高階動物', 'tt': <function Person_1.tt at 0x10f243f28>, '__dict__': <attribute '__dict__' of 'Person_1' objects>, '__weakref__': < attribute '__weakref__' of 'Person_1' objects>, '__doc__': None}
有信仰
高階動物
有思想
666
None
{'__module__': '__main__', 'mind': '沒有思想', 'belif': '有信仰', 'animal': '高階動物', 'work': <function Person_2.work at 0x1114429d8>, 'money': <function Person_2.money at 0x1114421e0>, '__dict__': <attribute '__dict__' of 'Person_2' objects>, '__weakref__': <attribute '__weakref__' of 'Person_2' objects>, '__doc__': None, 'pay': '貨幣交換', 'say': '語言交流'}
2. python物件方法、類方法、靜態方法:
下面是簡單的幾個例子:
class Person(object):
grade=6 # 類變數
def __init__(self):
self.name = "king"
self.age=20
def sayHi(self): #加self區別於普通函式
print ('Hello, your name is?',self.name)
def sayAge(self):
print( 'My age is %d years old.'%self.age)
@staticmethod # 靜態方法不能訪問類變數和例項變數,也不能使用self
def sayName():
print ("my name is king")
@classmethod #類方法可以訪問類變數,但不能訪問例項變數
def classMethod(cls):
#print('cls:',cls)
print('class grade:',cls.grade)
#print("class method")
class Child(object):
def __init__(self):
self.name = "小明"
self.age=20
def sayName(self,obj):
print('child name is:',self.name)
print(obj.sayName)
print(obj.sayName()) # 這裡要特別注意帶括號和不帶括號的區別:一個是物件,一個是方法
p = Person() # 例項化物件
print('p.grade:',p.grade) # 例項物件呼叫類變數
p.grade=9
print(p.classMethod(),p.grade) # 例項改變類變數時,其grade變數只會在例項中改變
print(Person().grade) # 類物件呼叫類變數
p.sayHi() # 例項物件呼叫類成員函式
Person().sayAge() # 類物件呼叫類成員函式
p.sayName() # 例項物件呼叫類靜態方法
m=Person()
m.sayName() # 多個例項共享此靜態方法
Person().sayName() # 類物件呼叫靜態方法
p.classMethod() # 例項物件呼叫類方法
Person.classMethod() # 類物件呼叫類方法
# 呼叫類
tt=Child()
tt.sayName(Person())
執行結果:
p.grade: 6
class grade: 6
None 9
6
Hello, your name is? king
My age is 20 years old.
my name is king
my name is king
my name is king
class grade: 6
class grade: 6
child name is: 小明
<function Person.sayName at 0x10f1cc598>
my name is king
None
小小總結下:
python中實現靜態方法和類方法都是依賴於python的裝飾器來實現的。 物件方法有self引數,類方法有cls引數,靜態方法不需要這些附加引數。
- 靜態方法
要在類中使用靜態方法,需在類成員函式前面加上@staticmethod標記符,以表示下面的成員函式是靜態函式。使用靜態方法的好處是,不需要定義例項即可使用這個方法。另外,多個例項共享此靜態方法(靜態方法無法訪問類屬性、例項屬性,相當於一個相對獨立的方法,跟類其實沒什麼關係,簡單講,靜態方法就是放在一個類的作用域裡的函式而已)。
- 類方法
類方法與普通的成員函式和靜態函式有不同之處。定義: 一個類方法就可以通過類或它的例項來呼叫的方法, 不管你是用類來呼叫這個方法還是類例項呼叫這個方法,該方法的第一個引數總是定義該方法的類物件。 也即是方法的第一個引數都是類物件而不是例項物件. 按照習慣,類方法的第一個形參被命名為 cls
。任何時候定義類方法都不是必須的(類方法能實現的功能都可以通過定義一個普通函式來實現,只要這個函式接受一個類物件做為引數就可以了)。同時,類方法可以訪問類屬性,無法訪問例項屬性。上述的變數grade,在類裡是類變數,在例項中又是例項變數,所以使用的時候要注意,使用好的話功能很強大,使用不好容易混淆。
3. 類方法之間的呼叫
class Person(object):
# 不加任何引數直接定義,也是類方法
def Work():
print(" I am working!")
# 類方法 第一種方法:加裝飾器方法
@classmethod
def Think(cls,b): #類方法Think必須要帶至少1個引數,第一個引數預設為類名,後面可以引用。
cls.Eat(b) #在類方法Think中,呼叫類方法Eat類方法。
cls.Work() #在類方法Think中,呼叫Work類方法。
print(b,",I am Thinking!")
# 屬於第二種方法,先定義類方法,至少1個引數,第一個預設為類名。
def Eat(cls,b):
print(b+",I am eating")
Eat=classmethod(Eat) #第二種方法:通過內建函式classmethod()來建立類方法。
# 靜態方法,引用時直接用類名.Sleep()即可。
@staticmethod
def Sleep():
print("I am sleeping")
# 這種方法是:例項物件呼叫方法
def __scolia__(self):
print("scola")
return "scola"
# 例項物件可以訪問的私有方法,在類方法中可以相互呼叫和使用。類不能直接訪問或者外部訪問。
def __good(self):
print("good")
return "good"
Person.Think("li")
Person.Eat("jcy")
Person.Work()
# a.Work() 報錯,例項物件不能呼叫類方法
Person.Sleep()
a=Person()
a.__colia__() # 魔術方法,沒有私有化。
#a.__good() # 私有方法:報錯了!
執行:
li,I am eating
I am working!
li ,I am Thinking!
jcy,I am eating
I am working!
I am sleeping
scola
4. python使用@property @x.setter @x.deleter
- 只有@property表示只讀。
- 同時有@property和@x.setter表示可讀可寫。
- 同時有@property和@x.setter和@x.deleter表示可讀可寫可刪除。
方法必須要先經過 property()函式的裝飾後,才有後面兩個裝飾器的用法。
直接看例項:
class student(object): #新式類
def __init__(self,id):
self.__id=id
@property #只讀
def score(self):
return self._score
@score.setter #只寫
def score(self,value):
if not isinstance(value,int):
raise ValueError('score must be an integer!')
if value<0 or value>100:
raise ValueError('score must between 0 and 100')
self._score=value
@property #只讀
def get_id(self):
return self.__id
s=student('123456')
s.score=100 # 寫
print(s.score) #讀
print(s.__dict__)
print (s.get_id) #只讀
#s.get_id=456 #只能讀,不可寫:AttributeError: can't set attribute
class A(object): # 新式類(繼承自object類)
def __init__(self):
self.__name=None
def getName(self):
return self.__name
def setName(self,value):
self.__name=value
def delName(self):
del self.__name
name=property(getName,setName,delName)
a=A()
print(a.name) #讀
a.name='python' #寫
print(a.name) #讀
del a.name #刪除
#print a.name #a.name已經被刪除 AttributeError: 'A' object has no attribute '_A__name'
執行結果:
100
{'_student__id': '123456', '_score': 100}
123456
None
python
經典類和新式類的對比:
class test1:#經典類:沒有繼承object
def __init__(self):
self.__private='alex 1' #私有屬性以2個下劃線開頭
#讀私有屬性
@property
def private(self):
return self.__private
#嘗試去寫私有屬性(對於經典類而言,“寫”是做不到的)
@private.setter
def private(self,value):
self.__private=value
#嘗試去刪除私有屬性(對於經典類而言,“刪除”也是做不到的)
@private.deleter
def private(self):
del self.__private
class test2(object):# 新式類:繼承了object
def __init__(self):
self.__private='alex 2' #私有屬性以2個下劃線開頭
#讀私有屬性
@property
def private(self):
return self.__private
#寫私有屬性
@private.setter
def private(self,value):
self.__private=value
#刪除私有屬性
@private.deleter
def private(self):
del self.__private
t1=test1()
#print t1.__private # 外界不可直接訪問私有屬性
print (t1.private) # 讀私有屬性
print (t1.__dict__)
t1.private='change 1' #對於經典類來說,該語句實際上是改變了例項t1的例項變數private
print (t1.__dict__)
print (t1.private) # 輸出剛剛新增的例項變數private
t1.private='change 2'
print (t1.__dict__)
del t1.private # 刪除剛剛新增的例項變數private
print (t1.__dict__)
#print (t1.private) #讀私有屬性,因為已經刪除,所以這裡會報錯
print ('-------------------------------------------------------')
t2=test2()
print (t2.__dict__)
print (t2.private) # 繼承了object,新增@private.setter後,才可以寫
t2.private='change 2' # 修改私有屬性
print (t2.__dict__)
print (t2.private)
del t2.private #刪除私有變數
#print t2.private #私有變數已經被刪除,執行“讀”操作會報錯:AttributeError: 'test2' object has no attribute '_test2__private'
print (t2.__dict__)
執行:
alex 1
{'_test1__private': 'alex 1'}
{'_test1__private': 'change 1'}
change 1
{'_test1__private': 'change 2'}
{}
-------------------------------------------------------
{'_test2__private': 'alex 2'}
alex 2
{'_test2__private': 'change 2'}
change 2
{}
貌似差別也不是很大。
參考:
https://blog.csdn.net/sxingming/article/details/52916249
5. “魔術方法”的使用
可以參考:https://blog.csdn.net/NightCharm/article/details/79357559