面向对象最重要的是类和实例,类是抽象的,是具有某些相同属性和方法的集合;实例就是根据类创建出来的一个个对象
对象=属性+方法
类的定义:
class 类名(object) :
语句
其中object是指类继承与哪个类,(object)可不写,所有的类都继承与object类
self参数:
类中的方法无论是有参还是无参,默认都有第一个参数self,称为实例的引用,它也是方法和函数的区别(除此之外没有任何区别)。这个self参数,你可以将其命名为任意参数,但是最好是默认为self。它相当于Java中的this,在你将类实例化之后赋予一个对象,self参数就是这个对象本身。比如你有一个类Class和这个类的一个实例MyClass,当你调用这个对象的方法MyClass.getName(arg1,arg2)时,其实就是相当于MyClass.getName(MyClass,arg1,arg2)
init方法:
在类的一个对象被创建时,会立即运行一个初始化方法init方法,这个方法就相当于Java中的构造函数。在定义时需要注意init前后各有两条下划线__init()__,定义的时候第一个参数还是self。有init方法的类在创建实例化对象的时候必须给它传入和init方法中相匹配的参数,否则函数会报错。子类不能重写父类的构造方法,如果子类的构造方法中用到了父类的构造方法里面的属性,应该考虑继承。
类的实例化:
一个类Person()创建之后就会产生一个类对象,通过p = Person()可以创建一个Person类的实例。可以直接通过p来调用类的方法和属性(私有属性不能直接调用)。如果Person类有构造方法,在创建类的实例时,需传入对应的参数。
类的私有属性:
类的私有属性一般用两个下划线表示__i,类的实例不能直接访问,需要通过一些方法去访问和处理这些私有属性。这种方式保证了代码的将壮性。
访问类的私有变量:
class Person(): def __init__(self,name,age): self.__name =name self.__age = age def getName(self): return self.__name def getAge(self): return self.__age def setName(self,name): self.__name = name def setAge(self,age): self.__age = age p = Person("Tom",18) print(p.__name) print(p.__age)
这段代码中Person类中的__name和__age属性都是私有属性,如果想直接访问这里面的属性,p.__name和p.__age,会报错
Traceback (most recent call last): File "D:/PythonDemo/hello.py", line 171, in <module> print(p.__name) AttributeError: 'Person' object has no attribute '__name'
这是因为,Python将私有变量变为了,_Person__name和_Person__age,但是不要用p._Person__name这样的方式去直接访问私有变量,因为不同版本的解释器会把__name变为不同的变量名。需要写一些方法去访问和改变私有变量。上面代码中的getName()、getAge()、setName()、setAge()方法,是用来访问和改变这些私有变量的。
p = Person("Tom",18) print(p.getAge()) print(p.getName()) p.setName("Jerry") print(p.getName()) p.setAge(22) print(p.getAge())
结果为:
18
Tom
Jerry
22
封装、继承和多态:
类的属性和方法都是放在内部的,我们直接可以在外部使用这些方法去访问类的内部数据,不需要在外面重新写方法,也不需要知道实现的细节,这就叫封装,封装还有一个好处就是可以增加类的方法,比如getAge(),外部同样不用知道方法的细节,但是可以去访问类的数据。
继承:当我们定义一个类时,可以从某个类继承,这个被继承的类叫做父类(SupperClass或者BaseClass)、新类叫做子类(SubClass),所有的类都继承于Object类。比方说定义一个Man()类继承于Person()类,写法应该是class Man(Person): 子类可以继承父类的方法和属性,比如Person类中有eat()方法,则Man()类中不必再写eat()方法,可以直接使用eat()方法,同样,子类也可以重写父类的方法,在子类的实例调用这个方法时,总是会调用子类的方法。
class Person(): def __init__(self,name,age): self.name =name self.age = age def eat(self): return "i can eat" class Man(Person): pass m = Man("Tom",12) print(m.name) print(m.age) print(m.eat())
输出为:
Tom 12 i can eat
可以看到子类能直接使用类的属性和方法
再来看子类重写父类的方法“
class Person(): def __init__(self,name,age): self.name =name self.age = age def eat(self): return "i can eat" class Man(Person): def eat(self): return "i eat more" m = Man("Tom",12) print(m.name) print(m.age) print(m.eat())
输出为:
Tom 12 i eat more
可以看到,调用的是子类的方法
如果一个类同时继承多个类,从左到右依次继承,对于继承的方法,也是从左到右依次查找,调用先查找到的方法。比如:
class People: name = "" age = 0 __weight = 0 def __init__(self, n, a, w): self.name = n self.age = a self.__weight = w def speak(self): print("%s说:我今年%d岁,体重是%d公斤" % (self.name,self.age,self.__weight)) class Student(People): grade = 0 def __init__(self, n, a, w, g): People.__init__(self, n, a, w) self.grade = g def speak(self): print("%s说:我今年%d岁,读%d年级" % (self.name, self.age, self.grade)) class Speaker: topic = "" name = "" def __init__(self, n, t): self.name = n self.topic = t def speak(self): print("%s说,我今天演讲的主题是%s" % (self.name, self.topic)) class Sample(Speaker, Student): a = "" def __init__(self, n, a, w, g, t): Student.__init__(self, n, a, w, g) Speaker.__init__(self, n, t) test = Sample("小明", 20, 55, 3, "Python") print(test.speak())
Sample(Speaker,Student)类继承于Speaker()和Student(),那么输出的结果为:
小明说,我今天演讲的主题是Python
如果把继承的顺序变为Sample(Student,Speaker),那么输出的结果为:
小明说:我今年20岁,读3年级
同时从”People.__init__(self, n, a, w)“也可以看出,子类在写构造方法时,可以直接使用父类.__init__(self,arg1,arg2...)的方式继承父类的构造方法里的属性
多态:Python本身就是一种多态类的语言,如果某些类具有相同的方法,我们可以把它们看作同一类型的。如果Cat类和Dog类都继承于Animal类,它们都有behaviour()方法。我们可以把Animal、Cat、Dog看成Animal、Cat、Dog类型的数据,同时Cat和Dog也是Animal类型的数据,但是反过来就不成立了。我们写一个函数叫做beh,有方法behaviour(),参数类型为Animal类型,这样我们就可以往里面传入Animal、Cat和Dog类型的参数,同时如果我们新建一个类Bird(Animal)继承于Animal,也不必修改beh函数。
class Animal: def behaviour(self): print("Animal can run") class Cat(Animal): def behaviour(self): print("Cat can miaomiaomiao") class Dog(Animal): def behaviour(self): print("Dog can wangwangwang") lst = [Animal(),Cat(),Dog()] for items in lst: print(items.behaviour()) print("===============================") def beh(animal): animal.behaviour() print(beh(Animal())) print(beh(Cat())) print(beh(Dog()))
结果为:
Animal can run None Cat can miaomiaomiao None Dog can wangwangwang None =============================== Animal can run None Cat can miaomiaomiao None Dog can wangwangwang None
我们只需关注,这个这个参数是Animal类型的就行了,至于具体的是属于Cat类型还是属于Dog类型,则需要看传入的参数是什么,而且当我们新增一个类Bird继承于Animal时,不需要去修改这个函数,只需要保证这个函数的正确性即可,这个就是多态便利性的一个体现。