类的三大特性
一、继承
1. 基本
私有变量 self.name
直接定义 属于类的方法 相当于 static
2. 继承
属性查找 就近原则
3. 派生
重写,以自己的为准
使用 父类方法 super().
4. 经典类与新式类
- 新式类: 继承 object 的类,以及该类的子类孙子类,都是新式类
- 经典类: 没有继承object的类,以及该类的子类,孙子类,都是经典类
5. 多继承属性查找
- 经典类:多继承情况下,再要查找属性不存在时,会按照深度优先的方式查找下去
- 新式类: 多继承情况下,再要查找属性不存在时,会按照广度优先的方式查找下去
属性查找方法: __mor__
class A(object):
def test(self):
print("form A")
class B(A):
def test(self):
print("form B")
class C(A):
def test(self):
print("form C")
class D(B):
def test(self):
print("form D")
class E(C):
def test(self):
print("form E")
class F(D, E):
pass
f1 = F()
f1.test()
print(F.__mro__)
# answer
form D
(<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
6. super() 继承查找
class X:
def test(self):
print('X')
def f1(self):
print('XF')
class A(X):
def test(self):
print('1 打印')
super().f1()
print('3 打印')
class B:
def f1(self):
print('2 from B')
class C(A, B):
pass
c = C()
c.test()
print(C.__mro__)
# answer
1 打印
XF
3 打印
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.X'>, <class '__main__.B'>, <class 'object'>)
super调用和用父类名字调用,各有优劣,不能混着用。
7. 组合
一个类产生的对象,该对象拥有一个属性,这个属性的只是来自于另外一个类的对象
class Date:
def __init__(self, year, mon, day):
self.year = year
self.mon = mon
self.day = day
def tell_birth(self):
print("出生年月<%s-%s-%s>" % (self.year, self.mon, self.day))
class People:
school = 'syau'
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class Teacher(People):
def __init__(self, name, age, gender, level, salary):
super().__init__(name, age, gender)
self.level = level
self.salary = salary
def change_score(self):
print("teacher %s is changing score " % self.name)
class Student(People):
def __init__(self, name, age, gender, course):
super().__init__(name, age, gender)
self.course = course
def choose(self):
print("student %s is chose course" % self.name)
teal = Teacher('Albert', 18, 'male', 10, 3.1)
date_obj = Date(2000, 1, 1)
date_obj.tell_birth()
teal.birth = date_obj
print(teal.birth)
teal.birth.tell_birth()
teal.change_score()
stu1 = Student('张三', 16, 'male', 'AI')
stu1.birth = Date(2000, 3, 3)
stu1.birth.tell_birth()
# answer
出生年月<2000-1-1>
<__main__.Date object at 0x7fcccb2c8210>
出生年月<2000-1-1>
teacher Albert is changing score
出生年月<2000-3-3>
解决代码重用问题的两种方案:继承、组合
二、封装
1. 封装基本介绍
封装的目的就是为了明确区分内外,对外不是隐藏的,对内部是开放的。
class Foo2:
__x = 111
def __init__(self, y):
self.__y = y
def __f1(self):
print('Foo.f1')
# x,y,f1 都访问不到了
obj2 = Foo2(222)
print(obj2.x)
print(obj2._x)
print(obj2.__x)
print(obj2.f1)
print(obj2.__f1)
print(obj2.y)
print(obj2.__y)
为一个属性名加__开头,会在类定义阶段将属性名变形:
__属性名 ==> _类名__属性名
注: 类定义阶段执行类体内的代码(类体内的函数只检测语法,不执行)
类的命名空间
在外部访问隐藏属性
不建议下面的访问方式,因为__ 就是为了隐藏内部变量
print(obj2._Foo2__x)
print(obj2._Foo2__f1)
print(obj2._Foo2__y)
# answer
111
<bound method Foo2.__f1 of <__main__.Foo2 object at 0x7fe0c0fd2950>>
222
使用 函数访问隐藏属性
class Foo3:
__x = 111
def __init__(self, y):
self.__y = y
def __f1(self):
print('Foo.f1')
def get__y(self):
return self.__y
obj3 = Foo3(222)
print(obj3.get__y())
# asnwer
222
父类不让子类覆盖自己的方法
class Foo:
def __f1(self):
print('Foo.f1')
def f2(self):
print('Foo.f2')
self.__f1()
class Bar(Foo):
def __f1(self):
print('Bar.f1')
obj4 = Bar()
obj4.f2()
# answer
Foo.f2
Foo.f1
2. Property方法
property 本质也是封装,不过现在是别人封装好了,相当于把一个对象的函数属性伪装成了变量属性,强大之处在于他可以动态变化
class People:
def __init__(self, name, weight, height):
self.name = name
self.weight = weight
self.height = height
@property
def bmi(self):
return self.weight / (self.height * self.height)
albert = People('albert', 68, 1.68)
print(albert.name)
print(albert.bmi)
albert.weight = 65
print(albert.bmi)
# asnwer
albert
24.092970521541954
23.030045351473927
3. 伪装属性的修改与删除
class People:
def __init__(self, name):
self.__name = name
@property
def name(self):
print('访问'.center(50, '='))
return self.__name
@name.setter
def name(self, x):
print('修改'.center(50, '='))
self.__name = x
@name.deleter
def name(self):
print('删除'.center(50, '='))
del self.__name
p = People('albert')
print(p.name)
p.name = 'Albert'
print(p.name)
del p.name
print(p.name)
# answer
========================访问========================
albert
========================修改========================
========================访问========================
Albert
========================删除========================
三、多态
多肽与多态性
- 函数名一样
- 四个函数缺一不可
import abc # abstract class
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod
def eat(self):
pass
@abc.abstractmethod
def drink(self):
pass
@abc.abstractmethod
def run(self):
pass
@abc.abstractmethod
def bark(self):
pass
class Cat(Animal):
def eat(self):
pass
def drink(self):
pass
def run(self):
pass
def bark(self):
print('喵喵')
class Dog(Animal):
def eat(self):
pass
def drink(self):
pass
def run(self):
pass
def bark(self):
print('汪汪')
class Pig(Animal):
def eat(self):
pass
def drink(self):
pass
def run(self):
pass
def bark(self):
print('哼哼')
c = Cat()
d = Dog()
p = Pig()
c.bark()
d.bark()
p.bark()
# asnwer
喵喵
汪汪
哼哼
# 追加
def BARK(animal):
animal.bark()
BARK(c)
BARK(d)
BARK(p)
# answer
喵喵
汪汪
哼哼
鸭子类型(Duck Type)
python 推崇这种方式
只要长得像,不是也是,用这种方式,既解开了耦合,又同一了标准
class Disk:
def read(self):
print('disk read')
def write(self):
print('disk write')
class Txt:
def read(self):
print('txt read')
def write(self):
print('txt write')
class Process:
def read(self):
print('process read')
def write(self):
print('process write')
obj1 = Disk()
obj2 = Txt()
obj3 = Process()
obj1.read()
obj2.read()
obj3.read()
# answer
disk read
txt read
process read
类的绑定方法
import LSettings
class People:
def __init__(self, name, age):
self.name = name
self.age = age
def tell(self):
print('%s %s' % (self.name, self.age))
@classmethod
def read_form_conf(cls):
return People(LSettings.NAME, LSettings.AGE)
p = People.read_form_conf()
p.tell()
# asnwer
James 35
类的静态(非绑定)方法
import hashlib
import time
import LSettings
class People:
def __init__(self, name, age):
self.name = name
self.age = age
def tell(self):
print('%s %s' % (self.name, self.age))
@classmethod
def read_form_conf(cls):
return People(LSettings.NAME, LSettings.AGE)
@staticmethod
def create_id():
m = hashlib.md5()
m.update(str(time.process_time()).encode('utf-8'))
return m.hexdigest()
p = People.read_form_conf()
p.tell()
print(People.create_id())
print(People.create_id)
print(p.create_id)
# answer
James 35
f8acdd09e3cf88f68069f62c5a2e924d
<function People.create_id at 0x7fcd48ac1560>
<function People.create_id at 0x7fcd48ac1560>
github仓库 https://github.com/yangxin6/python-basic.git