面向对象基础
继承
如何使用继承
class 类名(父类1,父类2):
pass
本质
是一种新建类的方式,继承了一个类,类中的属性和方法就在子类中
父类/基类
子类/派生类
新式类
只要继承了object类,就是新式类,在python3中,默认继承object类
python2中,需要显示的指定继承object
经典类
没有继承object的类,就是经典类
python3中没有经典类
继承重用父类
方法一:指名道姓(跟继承没有关系)
class A:
def __init__(self, name, age):
self.name = name
self.age = age
self.course = None
class B(A):
#没有自己的__init__,直接继承A的
def create_course(self, course_name):
self.course = course_name
class C(A):
#C有自己的__init__,需要声明A的__init__才能使用A的
def __init__(self, name, age, gender):
A.__init__(self, name, age): #指名道姓A使用它的__init__方法
self.gender = gender #派生
方法二:super关键字
-
严格以继承属性查找关系(.mro列表中的顺序)
-
super()会得到一个特殊的对象,该对象就是专门用来访问父类中的属性(按照继承的关系)
-
super的完整用法是super(自己的类名,self), python3中可以简写
-
super.init()不用为self传值
class A;
def __init__(self, name, age):
self.name = name
self.age = age
def t(self)
print('这是A的t方法')
class B(A):
def __init__(self, name, age, sex):
#super(B,self).(name, age)#完整的写法,在python2中会用到,python3中按下面的写
super().__init__(name, age) # 直接继承了父类的两个属性,必须要写两个
self.sex = sex
def t(self):
#A.t(self)#和下面的语句具有相同的意思
super().t # 调用该方法打印出 这是A的t方法
组合
通俗来讲,我有一个黑色书包,那么我是人类的对象,黑色书包是书包类的对象,则“我有黑色书包这句话就是组合:即一个对象的属性是另一个对象”
class Person:
def __init__(self, bag):
self.bag = bag
class Bag:
def __init__(self, pencil, pen):
self.pencil = pencil
self.pen = pen
p = Person('nike')
b = Bag('pencil', 'pen')
p.b = b
print(p.b.pencil) #pencil 相当于b对象
print(p.b)#<__main__.Bag object at 0x0000017299CDD518>#打印b对象的内存地址
print(p.bag)#打印书包的名称 nike
多态和多态性
多态: 一类事物的多种形态
例如:动物类有猪,狗,人
多态性: 不考虑实例类型的情况下使用实例,比如‘讲话’这个属性,可以有‘人讲话’、‘猪讲话’、‘狗讲话’
注意python中崇尚鸭子类型:即不会强制执行,看起来、叫声、走路像鸭子就是鸭子,就是在每个派生类里面写相同名字的方法
方式一:
用abc实现接口统一化,约束代码(用的比较少)
import abc
#第一在括号中写metaclass=abc.ABCMeta
class Animal(metaclass=abc.ABCMeta):
#第二在要约束的方法上,写abc.abstractmethod装饰器
@abc.abstractmethod
def speak(self):
pass
class Pig(Animal):
def speak(self):
print('哼哼哼')
class Dog(Animak):
def aa(self):
print('旺旺旺')
pig = Pig()
pig.speak() #正常打印
dog = Dog()
dog.aa()# 会报错
方式二:
用异常处理来实现(常用)
class Animal():
def speak(self):
#主动抛出异常
raise Exception('你得给我重写它啊')
class Pig(Animal):
def speak(self):
print('哼哼哼')
class People(Animal):
def speak(self):
print('say hello')
pe=People()
pe.speak() # say hello
class Animal():
def speak(self):
#主动抛出异常
raise Exception('你得给我重写它啊')
class Pig(Animal):
def spk(self):
print('哼哼哼')
class People(Animal):
def sak(self):
print('say hello')
pe=People()
pe.speak() # Exception: 你得给我重写它啊
方式三:
最常用(约定俗成写一样的方法名)
#都写speak方法
class Pig:
def speak(self):
print('哼哼哼')
class People:
def speak(self):
print('say hello')
封装
就是汉语封装,把所有东西装在一个容器内,隐藏起来
1. 隐藏属性(为了安全)
class Person:
def __init__(self,name,age):
self.__name=name #__变量名来隐藏
self.__age=age
def get_name(self):
# print(self.__name)
return '[----%s-----]'%self.__name
p=Person('nick',89)
print(p.age) #报错 AttributeError: 'Person' object has no attribute 'age'
print(p._Person__name)# 可以访问 或者通过p.__dict__取出值
2.隐藏方法(隔离复杂度)
class Person:
def __init__(self,name,age):
self.__name=name
self.__age=age
def __speak(self):
print('6666')
p=Person('nick',89)
p.__speak() #报错 AttributeError: 'Person' object has no attribute '__speak'
print(Person.__dict__)
p._Person__speak() # 用对象的字典可以拿出来
property装饰器:把方法包装成数据属性
#property装饰器:把方法包装成数据属性
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)
# return self.weight/(self.height*self.height)
p=Person('lqz',1.82,70)
# # print(p.bmi())
print(p.bmi) #bmi直接返回数值 21.132713440405748
property之setter
class Person:
def __init__(self,name,height,weight):
self.__name=name
self.__height=height
self.__weight=weight
@property
def name(self):
return '[我的名字是:%s]'%self.__name
#用property装饰的方法名.setter #可以限制属性的修改,规定标准
@name.setter
def name(self,new_name):
# if not isinstance(new_name,str):
if type(new_name) is not str:
raise Exception('改不了')
if new_name.startswith('sb'):
raise Exception('不能以sb开头')
self.__name=new_name
# 用property装饰的方法名.deleter
@name.deleter
def name(self):
# raise Exception('不能删')
print('删除成功')
# del self.__name
p=Person('lqz',1.82,70)
p.name=123
print(p.name) #Exception: 改不了
类的绑定方法
绑定给类的,类来调,会把类自身传过去
一般用在不需要通过对象,只需要通过类就能获得一些东西,可以由对象调用,但不建议
class Person:
def __init__(self,name,age):
print(self)
self.name=name
self.age=age
@classmethod
def test(cls):
print(cls)
print('类的绑定方法')
#类实例化产生对象,返回
return cls('lqz',19)
per1=Person.test()
print(per1) #打印的是: 类的绑定方法
类的非绑定方法
staticmethod 非绑定方法,定义在类内部,普通方法,谁都不绑定对象/类都可以调用,但是不会自动传值
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def object_method(self):
print('我是对象绑定方法,对象来调用我')
@classmethod
def class_method(cls):
print('我是类的绑定方法,类来调用我')
#当成一个普通函数,只不过是写在类内部的
@staticmethod
def static_method():
print('我是静态方法,谁都不绑定')
#静态方法(非绑定方法)
#类来调用
Person.static_method() #我是静态方法,谁都不绑定
# 对象来调用
p=Person('nick',19)
p.static_method() #我是静态方法,谁都不绑定
静态方法(非绑定方法)的作用跟类和对象都没有关系的时候,可以定义成静态方法,一般在类内部使用,类外部也可以使用就是一个普通函数,想把它拿到类中管理,就可以定义成静态方法
class Person:
def __init__(self,name, age):
self.id=self.get_uuid()
self.name = name
self.age = age
#当成一个普通函数,只不过是写在类内部的
@staticmethod
def static_method():
print('我是静态方法,谁都不绑定')
@staticmethod
def get_uuid():
import uuid
return uuid.uuid4()
p=Person('nick',19)
print(Person.get_uuid()) # 15ee76bf-930d-4297-87ba-036771e3e3de