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”)这样的调用方式是错误的,其他的方式是可以的,这就为我们增加了调用方法的写法