有关面向对象的定义,我不在阐述,在我之前的Java基础文章中已经阐述的相对很清除了,这里我们直接来进行学习以及操作。
这里我将脱离网站上的教学,直接与Java对比学习,我相信对于任何一个掌握了另外一门语言的人来说,对比学习,应该是最快上手的。
类
创建一个类
python:
class Dog:
#名字
name =""
#颜色 双下划线+属性名 这个属性就会变成伪私有
__color=""
#构造器 参数:类型 (当然,:和类型你可以不写,
# 但是作为曾经写强类型语言的开发人员,不写类型实在有点难受...)
#self 就相当于 Java中的自动传入的this引用
def __init__(self, name:str, color:str):
self.name = name
self.__color = color
def _toString(self):
print("Dog: name='{}', color='{}' ".format(self.name,self.__color))
#new这个关键字在Python中并不存在,直接使用 类名()就是在创建对象
dog = Dog("大黄","yellow")
dog._toString()
#改变共有属性
dog.name = "蠢蠢"
#改变私有属性
# dog.__color("red") 因为这是私有属性,如果没有set方法,我们不能从外部修改它
#然后说这个是伪私有是有原因的,实例._类型__私有属性 照样可以修改和访问
dog._Dog__color = "red"
dog._toString()
# 结果:Dog: name='大黄', color='yellow'
# Dog: name='蠢蠢', color='red'
java:
public class Dog {
//名字
public String name;
//颜色
private String color;
//构造器
Dog(String name , String color){
this.name = name;
this.color = color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
'}';
}
public static void main(String args[]){
Dog dog = new Dog("大黄","yellow");
//改变共有属性
dog.name = "蠢蠢";
System.out.println(dog);
//改变私有属性
dog.setColor("red");
System.out.println(dog);
}
}
//结果:Dog{name='蠢蠢', color='yellow'}
// Dog{name='蠢蠢', color='red'}
简单总结一下,创建类:
class <类名>:
#构造器,注意一个类只能由一个构造器,在Python中方法是可以给默认参数的,
#所以不需要多余的构造器进行重载
def __init__(self,参数1,参数2):
#代表什么都不做
pass
对象
创建一个对象
# 构造器 __init__ 中的self 代表着当前这个对象,会自动传入,所以只要传入需要的参数即可
对象名 = 类名(参数1,参数2)
创建一个对象时,会自动调用构造器,也就是 __init__(self)
方法
销毁一个对象时,对自动调用析构函数,__del__(self)
,类似Java中的 finallize。简单来说是将对象回收的方法,一般不会进行显示调用,并且也不会重写它。
访问权限
python中可以说不存在访问权限,所有属性,所有的方法都是共有的,而在OOP中,访问权限还是要有的,所有Python中有了伪私有
#共有属性
name = "zhangsan"
#私有属性 外部还是可以通过 实例名._类名__属性或方法 进行访问
__sex = "男"
public String name = "zhangsan"
private String sex = "男"
属性和方法调用
class A:
name = "张三"
def __init__(self):
#代表什么也不做
pass
#注意,对象方法都要有一个基本参数就是self,
def getName(self):
return self.name
a = A()
#调用方法
a.getName()
为什么必须要传入self?简单来说就是要确定是那个对象调用的这个方法。(至少在IDE环境中都要求必须传入一个self)这就是一个实例方法,也叫对象方法
类方法:需要用**@classmethod**修饰
class C:
name = "zs"
@classmethod
#必须要传一个参数代表当前类,普遍将第一个参数定义为cls,定义为其他名字也无所谓
def fun(cls):
print(cls.name)
def fun2(self):
print(self.name)
#也可以将普通方法转为类方法
fun2 = classmethod(fun2)
c = C()
c.name ="ls"
#对象也能够调用类方法
#注意哪怕对象调用了类方法,类方法的内容是对类的某一个属性进行改变
#与对象的属性无关
c.fun1()
c.fun2()
print(c.name)
# ls
print(C.name)
# zs
静态方法,需要用 @staticmethod 修饰
静态方法与Java不同,Java的静态方法实际上就是类方法,但是Python将它分开处理了
对象和类都可以调用静态方法,并且不会自动传入任何值。
class StaicTest:
str = "static method Test"
@staticmethod
def test():
print(StaticTest.str)
@staticmethod
def test2(a,b):
print(a,b)
def test3(self):
print("它被转为了静态方法")
#如果这样做,会直接报错
#所以对象方法和类方法,不能强转为静态方法
test4 = staticmethod(test3)
st = StaticTest()
st.test()
#static method Test
st.test2("a","b")
#a b
继承
Python的每一个类都继承自Object 类,这点与Java 很相像。
他会继承父类所有的非私有方法以及非私有属性。
(注意! 子类的属性或者方法与父类有重名的现象,直接进行覆盖)
class 类名(父类名):
pass
如果一旦有重名的方法,那么子类的方法会覆盖父类的方法。
class father(object):
name = "123"
def __init__(self):
self.name = "fatherName"
print("father类初始化")
def __privateFun__(self):
print("父类的私有方法无法继承")
def fatherMethod(self):
print("father的普通方法")
@classmethod
def fatherClassMethod(cls):
print("father的类方法")
@staticmethod
def fatherStaticMethod():
print("father的静态方法")
class son(father):
pass
s = son()
print(s.name)
#结果: fatherName
class son1(father):
def __init__(self):
print("son1初始化")
s1 = son1()
print("访问", "不到父类的name,因为重写了__init__方法导致无法初始化父类"
if s1.name=="" else s1.name)
#结果: son1初始化
# 访问 不到父类的name,因为重写了__init__方法导致无法初始化父类
所以说,当我们的子类继承父类时,如果子类重写了构造方法,也就是自定义了__init__ ()
方法,那么就不会默认调用父类的构造器,所以会造成父类的对象,在子类中无法被调用的情况。
如果说子类要自己进行初始化,并且也要将对应的父类进行初始化,那么就可以直接使用super关键字来调用,或者使用 父类.__init__方法进行传值,
class son1(father):
def __init__(self):
#初始化父类
super(son1,self).__init__()
#又或者
#super().init(参数1,参数2,参数3....)
#使用父类的构造器方法
# father.__init__(self)
print("son1初始化")
总结,显示调用父类的构造器的方法方式有两种:
super(子类,self).__init__(参数1,参数2....) 或 super().__init__(参数1,参数2,参数3)
父类.__init__(子类的self,参数1,参数2....)
在Pyhon中,并不是一种单继承的模式。
一个类可以有好几个父类,也就是多重继承,但是我建议,除非必要并且确定,否则不要使用多重继承。
class Base1:
def fun1(self):
print("Base1 的方法")
class Base2:
def fun2(self):
print("Base2 的方法")
class SuperClass(Base1,Base2):
pass
s = SuperClass()
s.fun1()
s.fun2()
抽象类
抽象类:具有抽象方法的类就是抽象类。也就是说作为一个抽象类,只定义好要做什么事情,具体怎么干,要子类自己具体实现。
定义抽象方法,需要用到 模块 以及 @abc.abstractmethod,所以我们需要导入模块 abc。
import abc
class pay(object):
#不需要实现,让子类进行实现。
@abc.abstractmethod
def pay(self):
pass
class AliPay(pay):
def pay(self):
print("支付宝支付")
class WxPay(pay):
def pay(self):
print("微信支付")
ap = AliPay()
wp = WxPay()
ap.pay()
wp.pay()
#结果:支付宝支付
#微信支付
并且有一系列的抽象设计,但实际上常用的还是就这个 @abc.abstractmethod
接口
python中并没有接口类型,实际上接口本质上就是抽象类。所以在Python中接口成为了一种描述,而不是定义。真正使用的还是抽象类。我们可以发现哪怕是在Java中,接口的功能也越发的趋向抽象类,所以python这么做,也是大势所趋,并且简单好用。
多态
多态的关键有三个,继承,重写,向上转型
在python中很难做到向上转型(主要是我没有查出来…)
import abc
class Animal(object):
def __init__(self):
pass
#定义一个抽象方法,注意抽象方法也是可以写方法体的。
@abc.abstractmethod
def eat(self):
pass
class Dog(Animal):
def eat(self):
print("小狗在吃骨头")
class Cat(Animal):
def eat(self):
print("小猫在吃鱼")
#多态实现函数放到了程序的主函数中
def eat(self):
self.eat()
d = Dog()
c = Cat()
#d = Animal(d) 这个的意思是调用了Animal的__init__函数,传入了d这个对象
#直接报错,因为我们并没有定义一个__init__(self,参数)的方法。
eat(d)
#小狗在吃骨头
eat(c)
#小猫在吃鱼
导入包
其实到现在没有解决一个问题,就是我们自己写的一个py文件,怎么样让其他的py文件进行访问呢???
这里我们在OOP2中使用OOP1中的类,我们发现只要按需导入即可。从 from 这个目录下,HightStudy ,导入import BaseOOP1 这个模块。
非常容易理解。也很类似Java