|
Posted on
2019-10-12 19:10
兰智杰
阅读( 220)
评论()
编辑
收藏
举报
继承和多态
程序中当定义一个class的时候,可以从某个现有的class继承,新的class称之为子类(Subclass),而被继承的class称之为基类、父类或超类;子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法
class Animal():
def __init__(self,name,food):
self.name = name
self.food = food
def eat(self):
print('%s爱吃%s'%(self.name,self.food))
#声明一个子类继承animal
class Dog(Animal):
def __init__(self,name,food,drink):
#加载父类构造方法(两种可以任选其中一种)
#Animal.__init__(self,name,food)
super(Dog, self).__init__(name,food)
self.drink = drink #子类自己的属性
def drinks(self): #子类自己的方法
print('%s爱喝%s'%(self.name,self.drink))
class Cat(Animal):
def __init__(self,name,food,drink):
# 加载父类构造方法(两种可以任选其中一种)
Animal.__init__(self,name,food,)
#super(Cat, self).__init__(name,food)
self.drink = drink #子类自己的属性
def drinks(self): #子类自己的方法
print('%s爱喝%s'%(self.name,self.drink))
#重写父类的eat
def eat(self):
print('%s特别爱吃%s'%(self.name,self.food))
dog1 = Dog('金毛','骨头','可乐')
dog1.eat() #输出为 金毛爱吃骨头
dog1.drinks() #输出为 金毛爱喝可乐
cat1 = Cat('波斯猫','秋刀鱼','雪碧')
cat1.eat() #输出为 波斯猫特别爱吃秋刀鱼
cat1.drinks() #输出为 波斯猫爱喝雪碧
多继承
需要注意子类调用父类时,圆括号中父类的顺序,如果继承的父类中有相同的方法名, 而在子类中使用时未指定,python将从左至右查找父类中是否包含方法
class A():
def __init__(self, mid,jungle):
self.jungle = jungle
self.mid = mid
def a(self):
print('我是skt的中单%s' %self.mid)
class B():
def __init__(self, ad, sub):
self.ad = ad
self.sub = sub
def b(self):
print('我是skt的射手%s' % self.ad)
def a(self):
print('我是skt的替补%s' % self.sub)
class C():
def c(self):
print('我是skt的教练kkoma')
'''
需要注意圆括号中父类的顺序,如果继承的父类中有相同的方法名,
而在子类中使用时未指定,python将从左至右查找父类中是否包含方法
'''
class D(A,B,C):
def __init__(self,mid,jungle,ad,sub):
#加载父类构造方法(两种可以任选其中一种)
# A.__init__(self, mid,jungle) #init A
# B.__init__(self, ad, sub) #init B
super(D, self).__init__(mid,jungle) #init A 注意里面是D,但加载的却是A
super(A, self).__init__(ad, sub) #init B 注意里面是A,但加载的却是B
d = D('faker','bengi','bang','blank')
d.a() #输出为 我是skt的中单faker 这里调用的a()是A中的方法
d.c() #输出为 我是skt的教练kkoma
d.b() #输出为 我是skt的射手bang
class E(B,A,C): #不同于D中的顺序,这里为B,A,C
def __init__(self,mid,jungle,ad,sub):
#加载父类构造方法(两种可以任选其中一种)
# A.__init__(self, mid,jungle) #init A
# B.__init__(self, ad, sub) #init B
super(E, self).__init__(mid,jungle) #init A 注意里面是E,但加载的却是B
super(B, self).__init__(ad, sub) #init B 注意里面是B,但加载的却是A
e = E('bang','blank','faker','bengi')
e.a() #输出为 我是skt的替补blank 这里调用的a()是B中的方法
e.c() #输出为 我是skt的教练kkoma
e.b() #输出为 我是skt的射手bang
类属性和实例属性
1、实例属性:
在__init__(self,...)中初始化,内部调用时都需要加上self,外部调用时用“对象名.属性名”调用
2、类属性:
在__init__()里初始化,在内部用类名.类属性名调用,外部既可以用类名.类属性名(推荐这种方式)又可以用对象名.类属性名来调用
3、私有属性:
双下划线__开头,外部不可通过“对象名.属性名”来访问,可以通过“_类名__属性名”强制访问
单下划线、双下划线、头尾双下划线说明
1、__foo__:定义的是特殊方法,类似 __init__()之类的
2、_foo:以单下划线开头的表示的是保护类型的变量,即保护类型只能允许其本身与子类进行访问(创建的实例可以访问),而不能够
用于from module import *
3、__foo:双下划线的表示的是私有类型的变量, 只能是允许这个类本身进行访问了
访问限制——私有属性
1、为了保护属性不被随意修改和访问,可以将属性定义为私有属性;如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例变量名如果以__开头,就变成了一个私有变量,只有内部可以访问,外部不能访问
2、设置为私有属性不能直接通过对象访问属性,但是可以通过“实例化对象名._类名__属性名”直接进行访问和修改;但是不建议这样操作,不同版本的Python解释器可能会把“__属性名”改成不同的变量名,总的来说就是,Python本身没有任何机制阻止你干坏事,一切全靠自觉
3、通过“对象名.__属性名”直接修改私有属性,表面上看好像修改了其实并没有,因为Python解释器已经将对象内部的属性名解释成“_类名__属性名”,如果在外部修改相当于另外声明一个属性
class person():
country = '中国' #声明类属性,并且赋值
def __init__(self,name,age,sex,address): #构造方法,实例属性通过构造方法来声明
self.name = name #通过self创建实例属性,并且赋值 self不是关键字
self.age = age
self.sex = sex
self.__address = address #双下划线开头的属性是私有属性
def getName(self): #创建普通方法
#类属性的使用通过类名.属性名使用 这是规范
#私有属性在类里面使用正常使用
print('我的名字叫:%s,我来自%s,我住在%s'%(self.name,person.country,self.__address)) #在方法里面使用实例属性
#外部要修改私有属性 预留一个接口去访问或者修改私有属性 这个就是正确的打开方式
def getAddre(self,pwd):
if pwd == '123':
return self.__address
else:
return '权限不够'
people01 = person('joe',19,'男','上海') #实例化对象
people01.getName() #输出为我的名字叫:joe,我来自中国,我住在上海
#通过对象名.属性名访问私有属性
#print(people01.__address) #系统报错 因为外部无法使用这种方式访问
print(people01.getAddre('1234')) #输出为 权限不够
print(people01._person__address) #强制访问,不建议这么做 输出为上海
people01.__address = '北京' #看上去好像改了,其实没有 相当于给当前对象声明了一个新属性
print(people01.__address) #输出为北京
print(people01.getAddre('123')) #输出为上海
people01._person__address = '南京' #强制修改,不建议这么做
print(people01.getAddre('123')) #输出为南京
类方法和静态方法
1、普通方法:
def fun_name(self,...):
pass
外部用实例调用
2、静态方法:通过装饰器 @staticmethod 装饰,不能访问实例属性,参数不能传入self,静态方法只能访问类属性
3、类方法:@classmethod,不能访问实例属性,参数必须传入cls,必须传入cls参数(即代表了此类对象-----区别------self代表实例对象),并且用此来调用类属性:cls.类属性名
静态方法与类方法都可以通过类或者实例来调用,其两个的特点都是不能够调用实例属性,静态方法不需要接收参数,使用类名.类属性,说白了静态方法与类方法都是针对类属性的,
class person():
country = '中国' #声明类属性,并且赋值
#实例属性通过构造方法来声明
#self不是关键字,代表的是当前对象
def __init__(self,name,age,sex,address,country): #构造方法
#构造方法不需要调用,在实例化的时候自动调用
self.name = name #通过self创建实例属性,并且赋值
self.age = age
self.sex = sex
self.__address = address #双下划线开头的属性是私有属性
person.country = country #类属性的申明,一般不用这种方式
#创建普通方法
def getName(self):
#类属性的使用通过类名.属性名使用 这是规范
#私有属性在类里面使用正常使用
print('我的名字叫:%s,我来自%s,我住在%s'%(self.name,person.country,self.__address)) #在方法里面使用实例属性
#创建一个静态方法
@staticmethod
def aa(): #不需要传递实例
#静态方法不能访问实例属性
#静态方法只能访问类属性
print('我的名字叫:%s'% person.country) #在方法里面使用实例属性
#类方法
@classmethod
def bb(cls,n): #cls 也不是关键字
#类方法不能访问实例属性
cls.country = n
print('我的名字叫:%s' %cls.country ) #就用cls.类属性
#实例化对象
people01 = person('joe',19,'男','上海','中国')
#通过对象来调用静态方法
#people01.aa()
#通过对象来调用类方法
#people01.bb('usa')
people01.getName() #输出为 我的名字叫:joe,我来自美国,我住在上海
#静态方法和类方法的调用,推荐使用类名的方式去调用
#通过类名来调用静态方法
people01.aa() #输出为 我的名字叫:中国
#通过类名来调用类方法
person.bb('usa') #输出为 我的名字叫:usa
|