python基礎-abstractmethod、__屬性、property、setter、deleter、classmethod、staticmethod
python中的介面概念
在python中根本就沒有一個叫做interface的關鍵字,如下的程式碼只是看起來像介面,其實並沒有起到介面的作用
利用NotImplementedError
class Payment:
def pay(self):
raise NotImplementedError
class ApplePay(Payment):
def zhifu(self,money):
print("ApplePay zhifu %d" % money)
#必須實現pay方法,否則報錯NotImplementedError
# def pay(self):
# print("ApplePay pay")
app = ApplePay()
app.zhifu(200)
#ApplePay必須實現,才呼叫不報錯
app.pay()
輸出如下:
E:\python\python_sdk\python.exe E:/python/py_pro/python.py
Traceback (most recent call last):
File "E:/python/py_pro/python.py", line 51, in <module>
app.pay()
File "E:/python/py_pro/python.py" , line 38, in pay
raise NotImplementedError
NotImplementedError
ApplePay zhifu 200
Process finished with exit code 1
所以我們通過raise NotImplementedError方式,強制其子類,實現方法,才能不報錯,將上面程式碼註釋去掉,然後就可以順利輸出如下的正確資訊:
E:\python\python_sdk\python.exe E:/python/py_pro/python.py
ApplePay zhifu 200
ApplePay pay
利用abstractmethod
注意事項:
子類必須全部實現重寫父類的abstractmethod方法
非abstractmethod方法可以不實現重寫
帶abstractmethod方法的類不能例項化
#介面類
from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self,money):
pass
@abstractmethod
def get(self, money):
print("Payment get%d" % money)
def total(self,money):
print("Payment total %d" % money)
def __init__(self,name):
print(self)
self.name = name
class AppPay(Payment):
def pay(self,money):
print("AppPay pay %d"%money)
def get(self,money):
print("AppPay get %d" % money)
app = AppPay("safly")
app.pay(100)
app.get(200)
app.total(400)
# 不能例項化
# TypeError: Can't instantiate abstract class Payment
# with abstract methods get, pay
# a = Payment("safly")
輸出如下:
E:\python\python_sdk\python.exe E:/python/py_pro/python.py
<__main__.AppPay object at 0x01201E30>
AppPay pay 100
AppPay get 200
Payment total 400
抽象類
與java一樣,python也有抽象類的概念但是同樣需要藉助模組實現,抽象類是一個特殊的類,它的特殊之處在於只能被繼承,不能被例項化
from abc import ABCMeta,abstractmethod
class Base(metaclass=ABCMeta):
def __init__(self,fName):
self.fName = fName;
@abstractmethod
def open(self):pass
class File(Base):
def open(self):
print("file open")
file = File("safly")
file.open()
輸出如下:
E:\python\python_sdk\python.exe E:/python/py_pro/python.py
file open
多型概念
在面向物件方法中一般是這樣表述多型性:
向不同的物件傳送同一條訊息(!!!obj.func():是呼叫了obj的方法func,又稱為向obj傳送了一條訊息func),不同的物件在接收時會產生不同的行為(即方法)。
也就是說,每個物件可以用自己的方式去響應共同的訊息。所謂訊息,就是呼叫函式,不同的行為就是指不同的實現,即執行不同的函式。
比如:老師.下課鈴響了(),學生.下課鈴響了(),老師執行的是下班操作,學生執行的是放學操作,雖然二者訊息一樣,但是執行的效果不同
from abc import ABCMeta,abstractmethod
class Base(metaclass=ABCMeta):
@abstractmethod
def talk(self):
pass
class Pig(Base):
def talk(self):
print("pig talk")
class People(Base):
def talk(self):
print("People talk")
def talk(obj):
obj.talk()
pig = Pig()
people = People()
pig.talk()
people.talk()
輸出如下:
E:\python\python_sdk\python.exe E:/python/py_pro/python.py
pig talk
People talk
__屬性封裝
私有靜態屬性、私有方法
print("------封裝-------")
#封裝
#把屬性、方法藏在類裡面,在類內部呼叫
class Dog:
# 私有靜態屬性
__kind = "wangcai"
#呼叫私有靜態屬性
def getKind(self):
return Dog.__kind
#私有方法
def __func(self):
print("__func")
#呼叫私有方法
def func(self):
self.__func()
#如下呼叫不提倡
print(Dog.__dict__)
print(Dog._Dog__kind)
#如下呼叫錯誤,因為需要在類內呼叫
# print(Dog.__kind)
d = Dog()
print(d.getKind())
#如下呼叫不提倡
d._Dog__func()
d.func()
輸出如下:
E:\python\python_sdk\python.exe E:/python/py_pro/python.py
------封裝-------
{'__module__': '__main__', '_Dog__kind': 'wangcai', 'getKind': <function Dog.getKind at 0x02BB1F60>, '_Dog__func': <function Dog.__func at 0x02BB1F18>, 'func': <function Dog.func at 0x02BB1ED0>, '__dict__': <attribute '__dict__' of 'Dog' objects>, '__weakref__': <attribute '__weakref__' of 'Dog' objects>, '__doc__': None}
wangcai
wangcai
__func
__func
私有物件屬性
#私有物件屬性
class Room:
def __init__(self,name,area):
self.name = name
self.__area = area
def getArea(self):
return self.__area
room = Room("safly",100)
print(room.name)
print(room.getArea())
#不能如下方法呼叫私有物件屬性
# print(room.__area)
輸出如下:
E:\python\python_sdk\python.exe E:/python/py_pro/python.py
safly
100
私有屬性不能被繼承
#私有方法不能被繼承
class A:
__role = "role"
def __func(self):
print("__a func")
def __init__(self,name):
self.__name = name
class B(A):
#如下的方法是錯誤的
def getRole(self):
return B.__role
a = A("safly")
print(dir(a))
print("-------------")
b = B("safly")
print(dir(b))
#呼叫報錯AttributeError: type object 'B' has no attribute '_B__role'
# print(b.getRole())
輸出如下:
E:\python\python_sdk\python.exe E:/python/py_pro/python.py
['_A__func', '_A__name', '_A__role', '__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__']
-------------
['_A__func', '_A__name', '_A__role', '__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__', 'getRole']
property 方法轉屬性
@property 把一個方法 偽裝成一個屬性
1.屬性的值 是這個方法的返回值
2.這個方法不能有引數了
3.類不能呼叫,只能物件呼叫
class Person:
def __init__(self,name,height,weight):
self.name = name
self.height = height
self.weight = weight
@property
def bmi(self):
return self.weight / (self.height**2)
@property
def methdd(self):
print("method")
per = Person("safly",1.73,75)
print(per.bmi)
per.methdd
#如下呼叫沒有效果
Person.methdd
輸出如下:
E:\python\python_sdk\python.exe E:/python/py_pro/python.py
25.05930702662969
method
property-setter設定值
class Goods:
discount = 0.8
def __init__(self,name,price):
self.name = name
self.price = price
@property
def getPrice(self):
return self.price * Goods.discount
@getPrice.setter
def getPrice(self,newPrice):
self.price= newPrice
app = Goods("apple",10)
print(app.getPrice)
app.getPrice = 20
print(app.getPrice)
輸出如下:
E:\python\python_sdk\python.exe E:/python/py_pro/python.py
8.0
16.0
deleter
class Foo:
name = "Foo"
@property
def AAA(self):
print('get的時候執行我啊')
@AAA.setter
def AAA(self,value):
print('set的時候執行我啊',value)
@AAA.deleter
def AAA(self):
del Foo.name
print('delete的時候執行我啊')
#只有在屬性AAA定義property後才能定義AAA.setter,AAA.deleter
f1=Foo()
f1.AAA
#setter
f1.AAA='aaa'
print(Foo.name)
#deleter
del f1.AAA
#刪除完畢後,再次呼叫報如下錯誤
#AttributeError: type object 'Foo' has no attribute 'name'
# print(Foo.name)
輸出如下:
E:\python\python_sdk\python.exe E:/python/py_pro/python.py
get的時候執行我啊
set的時候執行我啊 aaa
Foo
delete的時候執行我啊
在del f1.AAA後,刪除完畢後,再次呼叫print(Foo.name)報如下錯誤
AttributeError: type object ‘Foo’ has no attribute ‘name’
內建property函式
一個靜態屬性property本質就是實現了get,set,delete三種方法
class Foo:
def get(self):
print('get的時候執行我啊')
def set(self,value):
print('set的時候執行我啊',value)
def delet(self):
print('delete的時候執行我啊')
#def __init__(self, fget=None, fset=None, fdel=None, doc=None)
AAA=property(get,set,delet) #內建property三個引數與get,set,delete一一對應
f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA
輸出如下:
E:\python\python_sdk\python.exe E:/python/py_pro/python.py
get的時候執行我啊
set的時候執行我啊 aaa
delete的時候執行我啊
classmethod
下面程式碼中我分別列出了,在不使用classmethod類方法,和使用類方法的2種寫法
@classmethod也不需要self引數,但第一個引數需要是表示自身類的cls引數
不管這個方式是從例項呼叫還是從類呼叫,它都用第一個引數把類傳遞過來
#classmethod
#需要使用靜態變數,且不需要跟物件相關
class Goods:
__discount = 0.8
@classmethod
def change(cls,newPrice):
cls.__discount = newPrice
@classmethod
def getPrice(cls):
return cls.__discount
#之前的使用方式
def change1(self,newPri):
Goods.__discount = newPri
def getPrice1(self):
return Goods.__discount
Goods.change1(Goods,30)
print(Goods.getPrice1(Goods))
Goods.change(20)
print(Goods.getPrice())
輸出如下:
E:\python\python_sdk\python.exe E:/python/py_pro/python.py
30
20
staticmethod
staticmethod不需要表示自身物件的self和自身類的cls引數,就跟使用函式一樣。
class A:
def func(self,name):
print(name)
def func1(name):
print(name)
@staticmethod
def func2(self,name):
print(name)
@staticmethod
def func3(name):
print(name)
A.func(A,"safly")
A.func1("safly")
A.func2(A,"safly")
A.func3("safly")
輸出如下:
safly
safly
safly
safly
總結類、物件可以呼叫的方法
# staticmethod self\cls失效,類物件、例項物件均可以呼叫
# classmethod cls不管類物件、例項物件,輸出均是類物件
class A:
@staticmethod
def func1(name):
print("func1",name)
@staticmethod
def func2(self,name):
print("func2",self,name)
@classmethod
def func3(cls):
print("func3",cls)
@classmethod
def func4(cls,name):
print("func4",cls,name)
@classmethod
def func5(self,name):
print("func5",self,name)
@classmethod
def func6(cls,self,name):
print("func6",cls,self, name)
def func7(self,name):
print("func7",name)
def func8(name):
print("func8",name)
print("-----類呼叫--------")
A.func1("safly")
A.func2("A","safly")
A.func3()
A.func4("safly")
A.func5("safly")
A.func6("A","A")
A.func7(A,"safly")
A.func8("safly")
# print("----物件呼叫------")
a = A()
a.func1("safly")
a.func2("A","safly")
a.func3()
a.func4("safly")
a.func5("safly")
a.func6("A","A")
a.func7("safly")
a.func8()
輸出如下:
E:\python\py_dev\venv\Scripts\python.exe "E:/python/py_dev/python/03 python模擬登陸MysQL版.py"
-----類呼叫--------
func1 safly
func2 A safly
func3 <class '__main__.A'>
func4 <class '__main__.A'> safly
func5 <class '__main__.A'> safly
func6 <class '__main__.A'> A A
func7 safly
func8 safly
func1 safly
func2 A safly
func3 <class '__main__.A'>
func4 <class '__main__.A'> safly
func5 <class '__main__.A'> safly
func6 <class '__main__.A'> A A
func7 safly
func8 <__main__.A object at 0x059B4750>
Process finished with exit code 0
我們看到a.func5(“safly”)這樣的呼叫方式是錯誤的,其他的方式是可以的,這就為我們增加了呼叫方法的寫法