面向对象 1
面向对象思想其实来源于自然界中,在自然界中类别和类别对应的个体,狗和你家的二哈,狗就属于一种类别,是一种抽象的定义,你家的二哈就是狗的一个个体,但是你家的二哈就是一个确实存在的实体了,你家的二哈又属于狗的一种,它包含了狗的所有共性,面想对象思想就是类别和这个类别下的一个实际个体;到python中就这类思想(oop)我们用类和类对象来描述了。
class Dog(object): def __init__(self, name): #构造方法 self.name = name #变量 def eat(self): #方法 print('eat') def bark(self): print('wangwang') erha = Dog('erha') #实例化一个对象 erha.eat() erha.bark() print(erha.name) #eat #wangwang #erha
这里我们创建了一个Dog的类,这个类有两个方法和一个变量,构造方法需要我们在初始化时传入一个name的变量。
erha是我们进行实例化得到的一个Dog类的对象,它拥有Dog类的所有方法和变量。
我们先说下构造方法是什么,在定义一个类是会有__init__(self)的方法,这个方法就是构造方法了,它的作用就是初始化一个对象的变量,它会在实例化一个对象时直接调用,构造方法可以接收参数,这些参数我们一般用于创建属于对象的变量,我们看下面一个例子:
class Human: def __init__(self, name, gender): self.name = name self.gender = gender
self.age = 0 obj = Human('张三', 'man') print(obj.name)print(obj.gender)
我们定义了一个Human类,该类提供了3个变量,需要在创建这个对象时给两个变量赋值,相当于一个人出生的时候会给予性别和名字,这两个变量都属于人都有的变量,所以可以直接在初始化的时候进行赋值,或者直接给予固定值(age)。
类变量:可以理解为类对象都共有的特性,比如人类,都有名字,性别,年龄等。
类方法:类对象共有的功能,比如人类都能说话,吃饭睡觉等。
self:在类中随处可见的self到底代表着什么,类中的self代表实例化一个对象后的这个对象,我们所有类方法和类变量都会通过self绑定到这个对象上面,在类方法中第一个参数永远都是self。
私有变量:默认情况下对象初始化后,可以从外部直接访问对象的所有变量,但是如果想让某些内部变量不被外部直接访问,可以把变量的名称前加上两个下划线__
,在Python中,实例的变量名如果以双下划线开头,就变成了一个私有变量(private
),只有内部可以访问,外部不能访问:
class Student: def __init__(self, name, age, score): self.name = name self.age = age self.__score = score #私有变量 def get_score(self): return self.__score def set_score(self, new_score): if isinstance(new_score, int) and new_score > 0 and new_score < 100: self.__score = new_score return '修改成功!' else: return 'bad score' s1 = Student('xiaoming', 10, 70) print(s1.age) print(s1.name) print(s1.get_score()) print(s1.set_score(80)) print(s1.get_score())
上面我将score这个变量私有化了,在类外部是无法直接访问这个变量的,但是可以通过get_score方法来获取score的值,当然在外部也是无法直接修改变量的,我们提供了一个set_score方法来设置新的score,但是set_score会对传入的new_score进行变量判断,如果不符合规则就不允许修改,这样就比直接在外部修改变量的值安全多了。
下面我们再来说下python面向对象的3大特性:
封装,继承,多态
先看看封装:
其实我们上面所写的所有代码都在进行封装的操作。
封装这个过程有两个操作,一个是将类变量进行封装,一个是将类方法进行封装。
将内容进行封装,然后在某处实例化对象后,然后对封装的内容进行调用,这里的体现就是调用对象变量和对象方法了。
继承:
几乎只要是能够进行面向对象编程的,基本上都有继承的特性。
那什么是继承呢?
继承是实际上是类与类的一种关系,使用继承可以更好的进行代码复用,减少不必要的重复代码。
继承分为父类(基类)和子类(派生类)
我们看下面代码:
class Dog: #父类 def __init__(self, name): self.name = name def eat(self): print('eat') def bark(self): print('wangwang!') class Hashiqi(Dog): #继承Dog类,子类 def __init__(self, name, age): #重写构造方法 self.name = name self.age = age print('二哈降临') def chajia(self): print("拆家!") class Samoye(Dog): #继承Dog,子类
#没有构造方法,继承父类构造方法
def momoda(self): print('摸摸哒!') my_erha = Hashiqi('普拉达', 3) #初始化,调用自己类的构造方法 my_pipi = Samoye('皮皮') #初始化,调用父类的构造方法 print(my_erha.name) #自己变量 print(my_pipi.name) #父类变量 my_erha.bark() #父类方法 my_erha.chajia() #自己类方法 my_pipi.bark() my_pipi.momoda()
这里定义了一个父类,两个子类,可以看出,在调用变量或者方法时,会先到自己类中找,如果没有的话就到父类中找。
多继承
class Foo: def func1(self): print('foo.func1') class Foo2: def func1(self): print('foo.func2') class Bar(Foo2, Foo): pass class Bar2(Foo, Foo2): pass obj = Bar() obj.func1() obj2 = Bar2() obj2.func1()
#foo.func2
#foo.func1
python的继承与其他语言不同,支持多继承特性
在存在多继承关系的时候,调用变量或方法的优先级是 自己所属类 -->父类1 ---->父类2....
在一个类有多个父类时,调用优先级为从左到右的顺序
多态
在python中自带有多态变量,又戏称叫做“鸭子模型”,由于python的函数在传递参数时不需要指定参数的类型,这样就原生的实现了多态,可以说是python基本的特性了,这里多态就不多赘述了