绑定方法
# 绑定方法分几种:
1. 绑定给对象的
2. 绑定给类的
## 绑定给对象的
class Student():
school = 'SH'
name = 'egon'
# 当调用类的时候自动触发的函数
def __init__(self, name, age ,gender): #self:谁来调就是谁
self.name = name
self.age = age
self.gender = gender
# 绑定给对象的方法, 对象来调用的时候,把对象自己当成第一个参数自动传递过来
def func(self):
# self 对象本身
# self.__class__ 产生对象的类
pass
stu = Student('egon', 18, 'male')
stu1 = Student('egon1', 18, 'male')
stu2 = Student('egon2', 18, 'male')
stu3 = Student('egon3', 18, 'male')
# 绑定给类的方法
class Student():
school = 'SH'
name = 'egon'
# 当调用类的时候自动触发的函数
def __init__(self, name, age ,gender):
self.name = name
self.age = age
self.gender = gender
# 绑定给类的方法, 类来调用的时候,把类自己当成第一个参数自动传递过来
@classmethod #
def func(cls):
pass
# 类来调用
Student.func()
非绑定方法
# 即不绑定给对象,也不绑定给类的方法
class Student():
school = 'SH'
name = 'egon'
# 当调用类的时候自动触发的函数
def __init__(self, name, age ,gender):
self.name = name
self.age = age
self.gender = gender
# 变成了静态方法,函数中不在有默认的参数, 对象和类都可以调用,但是都不会自动传递参数
@staticmethod
def func(name, age):
pass
@staticmethod
def create_id()
import uuid
return uuid.uuid4()
@staticmethod
def make_code()
import random
隐藏属性
# 隐藏属性的特点:
1. 类定义阶段,会发生一次变形, _类名__属性名
2. 隐藏属性对外不对内
3. 如果外部要想调用隐藏属性,在类内部开放可访问的接口, 目的是可以更好的限制外部调用者
# 如何隐藏属性?
class Student():
__school = 'SH' # _Student__school
name = 'egon'
def __init__(self, name, age):
self.__name = name # self._Student__name
self.age = age
def __func(self) # def _Student__func(self)
pass
def get_name(self):
return self.__school # self._Student__school
def set_name(self, v):
if type(v) is not str:
return
self.__name = v
# 类的名称空间 {'name':'egon', '_Student__school':'SH','_Student__func':''}
stu = Student()
stu.set_name('egon')
**隐藏属性特点**:
1. 在类定义阶段发生了变形: _类名__属性名(或者方法名)
2. 对内不对外,内部照样获取,外部拿不到
为什么要隐藏:
对内部的属性或者方法做隐藏,可以更好的限制外部使用者, 要想让外部访问,在类内部定义对外可访问的接口。
property装饰器
# 把函数伪装成属性
class Student():
school = 'SH'
__name = 'egon'
@property
def name(self):
# 一大堆的逻辑
return self.__name
@name.setter # 修改
def name(self, v):
self.__name = v
@name.deleter
def name(self):
pass
stu = Student()
stu.get_name() #
# stu.get_name
# stu.name
stu.name = 'xx'
#####################第二种写法##################################
class Student():
school = 'SH'
__name = 'egon'
def get_name(self):
# 一大堆的逻辑
return self.__name
def set_name(self, v):
self.__name = v
def del_name(self):
pass
name = property(get_name,set_name,del_name)
stu = Student()
stu.get_name() #
# stu.get_name
# stu.name
stu.name = 'xx'
今日内容详细
-
面向对象的三大特征
封装
继承
多态
-
继承的属性查找
- 单继承下的属性查找
- 多继承下的属性查找
-
super()和mro()
-
多态与多态性
-
组合
继承
# 1.什么是继承?
继承就是新建类的一种方式,新建出来的类我们称为子类或者叫派生类,被继承的类称为父类或者基类
# 子类可以遗传父类的属性
# 2. 为什么要用继承?
类解决的是对象与对象之间的代码冗余问题
继承解决类与类之间的代码冗余问题
# 3. 如何使用继承?
新式类:继承了object类的子子孙孙类都是新式类
经典类:不继承object类的子子孙孙类都是经典类
# 新式类和经典类只在python2中区分
在python3中都是新式类
"""
学会子类如何使用父类的属性
1. 指名道姓:People.__init__(self, name, age, gender)
2. super():
"""
class People():
school = 'SH'
def __init__(self, name, age, gender):
# self => stu
self.name = name
self.age = age
self.gender = gender
class Student(People):
def __init__(self, name, age, gender, course=None):
if course is None:
course = []
self.courses = course
# self => stu
People.__init__(self, name, age, gender) # 普通方法, 指名道姓的调用方法
def choose_course(self, course):
# stu_dic['course'].append(course)
# stu_obj['course'].append(course)
# stu_obj.courses.append(course)
# self.courses.append(course)
self.courses.append(course)
print("%s选课成功%s" % (self.name, self.courses))
stu = Student('egon', 19, 'male') # Student(stu, 'egon', 19, 'male')
单继承下的属性查找
# class Foo:
# def f1(self):
# print("Foo.f1")
#
# def f2(self):
# print("Foo.f2")
# self.f1() # self => obj
#
#
# class Bar(Foo):
# def f1(self):
# print("Bar.f1")
#
#
# obj = Bar()
# obj.f2()
class Foo:
def __f1(self): # def _Foo__f1()
print("Foo.f1")
def f2(self):
print("Foo.f2")
self.__f1() # self._Foo__f1()
class Bar(Foo):
def __f1(self): # def _Bar__f1()
print("Bar.f1")
obj = Bar()
obj.f2()
多继承下的属性查找
# 新式类中属性查找按照 广度优先查询
# 经典类中属性查找按照 深度优先查询
class G(object):
def test(self):
print('from G')
class F(G):
def test(self):
print('from F')
class C(F):
def test(self):
print('from C')
class D(G):
def test(self):
print('from D')
class E(G):
def test(self):
print('from E')
class B(E):
def test(self):
print('from B')
class A(B, C, D):
def test(self):
print('from A')
f1 = A()
f1.test()
f1 = A()
f1.test()
当类是经典类时,多继承情况下,在要查询属性不存在时,会按照深度优先的方式查找下去
当类是新式类时,多继承情况下,在要查询属性不存在时,会按照广度优先的方式查找下去
super()和mro()
class A:
def test(self):
print('A---->test')
super().aaa()
class B:
def test(self):
print('B---->test')
def aaa(self):
print('B---->aaa')
class C(A, B):
def aaa(self):
print('C----->aaa')
# c = C()
# c.test() # 打印结果:
# print(C.__mro__)
a = A()
# a.test()
print(A.__mro__)
class People():
school = 'SH'
def __init__(self, name, age, gender):
# self => stu
self.name = name
self.age = age
self.gender = gender
class Student(People):
def __init__(self, name, age, gender, course=None):
if course is None:
course = []
self.courses = course
# self => stu
# People.__init__(self, name, age, gender) # 普通方法, 指名道姓的调用方法
# super(Student, self).__init__(name, age, gender) # python2 super(Student, self) 返回的是一个特殊的对象
super().__init__(name, age, gender) # python3 super(Student, self) 返回的是一个特殊的对象
# 他遵从mro列表
def choose_course(self, course):
self.courses.append(course)
print("%s选课成功%s" % (self.name, self.courses))
stu = Student('egon', 18, 'male')
print(stu.name)
print(stu.age)
print(stu.gender)
class Teacher(People):
def __init__(self, name, age, gender, level):
self.level = level
People.__init__(self, name, age, gender) # 普通方法, 指名道姓的调用方法
def score(self, stu_obj, score):
stu_obj.score = score
print("%s给%s打了%s分" % (self.name, stu_obj.name, score))
class A(object):
def test(self):
print('from A')
class B(A):
def test(self):
print('from B')
class C(A):
def test(self):
print('from C')
class D(B,C):
pass
obj = D()
obj.test() # 结果为:from B
对于你定义的每一个类,Python都会计算出一个方法解析顺序(MRO)列表,该MRO列表就是一个简单的所有基类的线性顺序列表,如下
>>> D.mro() # 新式类内置了mro方法可以查看线性列表的内容,经典类没有该内置该方法
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。 而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类
所以obj.test()的查找顺序是,先从对象obj本身的属性里找方法test,没有找到,则参照属性查找的发起者(即obj)所处类D的MRO列表来依次检索,首先在类D中未找到,然后再B中找到方法test
ps:
1.由对象发起的属性查找,会从对象自身的属性里检索,没有则会按照对象的类.mro()规定的顺序依次找下去,
2.由类发起的属性查找,会按照当前类.mro()规定的顺序依次找下去,
多态与多态性
# 多态:一种事物的多种形态
水:固态水,液态水, 气态水
动物:人,猪, 狗
# 继承, 子类使用父类的属性
多态类中的继承:不是让子类遗传父类的属性
多态带来的特性:在不考虑对象的数据类型的情况下,直接调用方法
import abc # abstract 抽象类
# 抽象类只能被继承,不能被实例化
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod
def speak(self): pass
# def speak1(self):pass
# def speak2(self):pass
# def speak3(self):pass
# Animal()
# class People(Animal):
# def speak1(self):
# pass
# pass
#
# class Pig(Animal):
# def speak(self):
# print("哼哼哼哼")
# pass
#
#
# class Dog(Animal):
# def speak(self):
# print("汪汪汪")
# pass
# obj1 = People()
# obj2 = Pig()
# obj3 = Dog()
#
# obj1.speak()
# obj2.speak()
# obj3.speak()
# 在python中不推荐上面的写法, 推荐的是下面的写法
class People():
def speak(self):
pass
class Pig():
def speak(self):
print("哼哼哼哼")
pass
class Dog():
def speak(self):
print("汪汪汪")
pass
class Txt():
def speak(self):
print("汪汪汪")
pass
obj1 = People()
obj2 = Pig()
obj3 = Dog()
obj4 = Txt()
# obj1.speak()
# obj2.speak()
# obj3.speak()
# obj4.speak()
def animal(animal):
return animal.speak()
animal(obj1)
animal(obj2)
animal(obj3)
animal(obj4)
print("abc".__len__())
print([1, 2, 3].__len__())
print({'username':"egon"}.__len__())
def len(item):
return item.__len__()
len("abc")
len([1, 2, 3])
其他
class A(object):
def test(self):
print('from A')
class B(A):
def test(self):
print('from B')
class C(A):
def test(self):
print('from C')
class D(B,C):
pass
obj = D()
obj.test() # 结果为:from B
对于你定义的每一个类,Python都会计算出一个方法解析顺序(MRO)列表,该MRO列表就是一个简单的所有基类的线性顺序列表
D.mro()
# 新式类内置了mro方法可以查看线性列表的内容,经典类没有该内置该方法
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]