封装继承多态
文章目录
类和对象
定义
class 大写开头的类名:
pass
变量和方法
类成员的顺序没有影响,成员之间可以调用
- 变量:类变量,实例变量
- 方法
类变量 :定义在类里面的变量
实例变量:__init__方法里面的变量
动态语言,
类变量可以随时定义/赋值和删除
实例变量也是
实例方法至少定义一个参数,就是self
构造方法__init__()
在里面可以定义变量,必须有一个self参数
在这里插入代码片
类的作用:
- 定义变量
- 创建对象
- 派生子类
对象的产生和使用
p = P("zhang",22)
可以给对象添加实例变量,也可以随时删除。
p.skill = "swimming"
del p.name
增加方法:
def method(self):
pass
p.fuc = method
# 调用方法
p.fuc(p)
# 或者直接lambda表达式
p.bar = lambda self: print(self)
# 调用方法
p.bar(p)
# 或者自动绑定第一个参数,借助模块
def method(self):#可以有多个参数啊
print(self)
from types import MethodType
p.intro = MethodType(method, p)
p.intro()
方法
通过类调用实例方法
Person.test(p)# 此时需要传入self参数,可以是对象,也可以是字符串等
类方法和静态方法
区别:类方法的第一个参数会自动绑定类本身(cls),静态方法不会自动绑定
类方法:@classmethod
修饰
静态方法:@staticmethod
修饰
class Bird:
@classmethod
def fly(cls):
print(cls)
@staticmethod
def info(p):
print("静态方法",p)
Bird.fly()
Bird.info("abc")
b = bird()
一般可以用函数代替,但是如工厂模式下,会用到静态方法类方法
@函数装饰器
@函数A 修饰函数B,就是:
- B作为参数传给A
- 将函数B替换为上一步的返回值
类是一个命名空间,里面也可以放执行语句
成员变量
类变量和实例变量
定义在类内的变量
不能直接访问,通过类名来访问,通过对象也可以
在成员方法中不能修改类变量的值,这样会创建新的实例变量
使用property函数定义属性
property可以有四个参数:可读,可写,可删,文档
class Rect:
def __init__(self, length, height):
self.length = length
self.height = height
def setsize(self, size):
self.length,self.height = size
def getsize(self):
return self.length,self.height
def delsize(self):
self.length,self.height = 0,0
size = property(getsize, setsize, delsize , 'abc这是看长宽的方法')
print(Rect.size.__doc__)
r = Rect(3,3)
print(r.size)
r.size = 9,7
print(r.size)
也可以用@property修饰器修饰方法
@property修饰默认有get方法
具体略
隐藏和封装
成员命名以双下划线开头就是隐藏了
实际上还是可以可以调用:
u._User__hide()
class User:
def getname(self):
return self.__name
def setname(self, name):
if len(name)>8:
raise ValueError('太长了')
self.__name = name
name = property(getname, setname)
u =User()
u.name = "abcd"
类的继承
子类可以有多个父类
没有继承的默认继承Object类
class Son(Super1, Super2):
pass
重写
直接重写就可以了
子类中调用被重写的父类方法
# 子类中
def bar():
self.foo()# 重写的方法
Parent.foo(self)# 被重写的方法
super调用父类构造方法
子类重写了父类的构造方法,必须调用父类的构造方法
# 子类中
def __init__(self, s, f, a):
super().__init__(s)
Customer.__init__(self,f,a)
Python的动态性
动态属性和__slots__
如果类可以随意增加某个实例实例方法,不安全,可以通过slots属性改进
__slots__是元组,列出来可以增加的所有属性和方法的名字
class Dog:
__slots__=('name','age','walk')
可以是方法和变量
对子类无效,子类假如也设置slots属性为空,则和父类一样只能创建那几个
为所有实例添加方法:
通过为类添加方法实现
- 定义一个方法
- 关联到类
# 主方法中
def walk_func:
pass
Cat.walk = walk_func
slots不会限制这种通过类来动态添加属性或方法
使用type()函数定义类
type()函数可以创建type对象,type对象就是类
所以用type()函数定义类
def fn(self):
print(1123,self.age)
Dog = type('Dog', (object,), dict(walk = fn, age =6))
d = Dog()
print(type(d))
print(type(Dog))
d.walk()
print(Dog.age)
三个参数:
- 类名
- 父类元组,多个逗号
- 参数字典
使用meatclass
可以在创建类是约束类必须有哪些方法,略
多态
多态性
同一个变量x,可能在不同时候指向不同对象(比如鸟对象和猴子对象),从而执行一个同名方法实际的动作不同
类型检查
检查cls是不是后一个类或者后一个元组中的类的的子类
检查obj是不是后一个类或者后一个元组中的类的对象
issubclass(cls, class_or_tuple)
isinstance(cls, class_or_tuple)
issubclass(str, (list,tuple)) #False
返回True或者False
枚举类
入门
定义枚举类方法:
- 通过Enum直接列出枚举值—简单的
- 继承Enum基类派生出枚举类—复杂的
## 为什么报错了
import enum
Season = enum.Enum(Season,('SPRING','SUMMER','FALL'))
Season看作类,
Season.SPRING看作对象,也可以Season[[‘SPRING’], Season(1)
对象有两个属性:name
,value
(从一开始增加),
类的属性: __members__
(是一个包含所有枚举实例的字典)
for name , member in Season.__members__.items()
访问:
print(Season.SPRING)//
print(Season.SPRING.name)
print(Season.SPRING.value)
继承Enum,可以定义额外的方法
import enum
class Orientation(enum.Enum):
EAST = '东'
WEST = '西'
def info(self):
print(self.value,self.name)
print(Orientation.WEST.name)
Orientation.WEST.info()
枚举类的构造器
定义了构造器以后,定义实例时就必须指定值
import enum
class Orientation(enum.Enum):
EAST = '东','前面是东'
WEST = '西','后面是西'
def __init__(self, orient, disc):
self._orient = orient
self._disc = disc
@property
def orient(self):
return self._orient
@property
def disc(self):
return self._disc
def info(self):
print(self.value,self.name)
print("west的名字:",Orientation.WEST.name)
print('值:',Orientation.WEST.value)
print('orient:',Orientation.WEST.orient)
print('disc:',Orientation.WEST.disc)
'''
west的名字: WEST
值: ('西', '后面是西')
orient: 西
disc: 后面是西'''
其他
查看一个类的父类
查看子类
A.__bases__
A.__subclasses__