面向对象编程三大特性
封装
在属性名前面加两个连续的下划线, 这个属性就变成了私有属性
私有属性只能在类的内部使用, 不能在类的外部使用
'''
定义一个类, Person
有属性 姓名name, 体重weight
有方法run, 调用一次run方法weight少0.5公斤
有方法eat, 调用一次eat方法weight多1公斤
有方法show, 作用就是介绍自己, 其实就是显示name和weight的值
'''
class Person:
def __init__(self, name, weight):
self.name = name
self.weight = weight
def run(self):
self.weight -= 0.5
def eat(self):
self.weight += 1
def show(self):
print(f"我的名字叫{self.name}, 我的体重为{self.weight}")
xiaoming = Person("小明", 70) # 实例化小明对象, 体重是70公斤
xiaoming.show()
xiaoming.run()
xiaoming.run()
xiaoming.run()
xiaoming.show()
xiaoming.eat()
xiaoming.show()
xiaomei = Person("小美", 50)
xiaomei.show()
xiaomei.eat()
xiaomei.eat()
xiaomei.eat()
xiaomei.eat()
xiaomei.eat()
xiaomei.weight = 45 # 在类 的外部修改了属性的值
xiaomei.show()
'''
定义一个类, Person
有属性 姓名name, 体重weight
有方法run, 调用一次run方法weight少0.5公斤
有方法eat, 调用一次eat方法weight多1公斤
有方法show, 作用就是介绍自己, 其实就是显示name和weight的值
'''
class Person:
def __init__(self, name, weight):
self.name = name
self.__weight = weight # __weight属性是私有的, 只能在类的内部使用
def run(self):
self.__weight -= 0.5
def eat(self):
self.__weight += 1
def show(self):
print(f"我的名字叫{self.name}, 我的体重为{self.__weight}")
xiaoming = Person("小明", 70) # 实例化小明对象, 体重是70公斤
xiaoming.show()
xiaoming.run()
xiaoming.run()
xiaoming.run()
xiaoming.show()
xiaoming.eat()
xiaoming.show()
xiaomei = Person("小美", 50)
xiaomei.show()
xiaomei.eat()
xiaomei.eat()
xiaomei.eat()
xiaomei.eat()
xiaomei.eat()
xiaomei.__weight = 45 # 在类 的外部修改了属性的值, __weight是私有属性, 在类的外部修改无效
xiaomei.show()
- 私有方法, 在方法名前面加两个连续的下划线, 方法就成为了私有方法
class Person:
def __secret(self): # __secret为私有方法, 只能在类的内部调用
print("我的秘密是, 睡觉磨牙打呼噜")
# 只有正确的输入了密码后, 才能看到小秘密
def show(self, password):
if password == "123456":
self.__secret() # 调用私有方法
else:
print("密码不对, 不告诉你我的小秘密哦")
p = Person()
# p.__secret() # 不能在类的外部调用私有方法__secret
p.show(input("请输入密码"))
继承
class 父类:
pass
class 子类(父类):
pass
class Animal: # 有一个动物类
def eat(self):
print("吃")
def sleep(self):
print("睡")
class Dog(Animal): # Dog是子类, 继承自父类Animal
def run(self):
print("跑")
a = Animal()
a.sleep()
a.eat() # Animal类只有sleep和eat方法
d = Dog()
d.eat() # 继承自父类
d.sleep() # 继承自父类
d.run() # run是Dog自己的
# Dog类有eat, sleep和run三个方法
class Animal: # 有一个动物类
def eat(self):
print("吃")
def sleep(self):
print("睡")
class Dog(Animal): # Dog是子类, 继承自父类Animal
def run(self):
print("跑")
class Fish(Animal):
def swimming(self):
print("游水")
class Bird(Animal):
def fly(self):
print("飞")
'''
Animal类有两个方法, eat和sleep
Dog类有三个方法, eat和sleep还有run
Fish类有三个方法, eat和sleep还有swimming
Bird类有三个方法, eat和sleep还有fly
'''
a = Animal()
a.sleep()
a.eat()
d = Dog()
d.sleep()
d.eat()
d.run()
f = Fish()
f.sleep()
f.eat()
f.swimming()
b = Bird()
b.sleep()
b.eat()
b.fly()
class Animal: # 有一个动物类
def eat(self):
print("吃")
def sleep(self):
print("睡")
class Dog(Animal): # Dog是子类, 继承自父类Animal
def run(self):
print("跑")
class ErHa(Dog):
def chaijia(self):
print("拆家")
class LangGou(Dog):
def yaoren(self):
print("咬人")
'''
类ErHa有eat, sleep, run和chaijia
类LangGou有有eat, sleep, run和yaoren
'''
e = ErHa()
e.sleep() # 来自于爷爷
e.eat() # 来自于爷爷
e.run() # 来自于父亲
e.chaijia() # 自己定义的方法
l = LangGou()
l.sleep()
l.eat()
l.run()
l.yaoren()
Object类
- 在python3以上的版本中, 如果一个类没有明确的指定父类, 这个类继承自Object类
class A:
pass
# 类A继承自Object类
# python所有的类, 都是Object的子类
方法的重写
- 当父类的方法不能满足子类的需求, 那么子类就要修改方法
覆盖
- 子类把父类的同名方法覆盖
- 子类中如果出现和父类同名的方法, 那么在子类中父类的同名方法就被覆盖了
class Animal: # 有一个动物类
def eat(self):
print("吃")
def sleep(self):
print("睡")
class Dog(Animal): # Dog是子类, 继承自父类Animal
def eat(self): # 如果子类出现了和父类同名的方法, 那么在子类中, 父类的方法就不存在了
print("吃肉")
a = Animal()
a.eat() # Animal的eat没有任何改变
d = Dog()
d.sleep() # 这个是来自于父类Animal
d.eat() # 这个是来自于自己
扩展super()
class Animal: # 有一个动物类
def eat(self):
print("吃")
class Dog(Animal): # Dog是子类, 继承自父类Animal
def eat(self): # 如果子类出现了和父类同名的方法, 那么在子类中, 父类的方法就不存在了
super().eat() # 调用父类的eat方法
print("dog类自己的eat方法")
d = Dog()
d.eat()
属性的继承
class Animal: # 有一个动物类
def __init__(self, sex, age):
self.sex = sex
self.age = age
class Dog(Animal): # 由于父类Animal定义了__init__, 所以子类会自动继承这个父类的__init__
def show(self): # 显示属性sex和age
print(f"sex属性的值为{self.sex}, age属性的值为{self.age}")
# d = Dog() # 实例化的时候, 不提供__init__的实参, 语法会报错
d = Dog("男", 10)
d.show()
# 在Dog中由于自动继承了父类的__init__方法, 所以父类中定义的属性sex和age也继承给了子类
class Animal: # 有一个动物类, 有属性sex和age
def __init__(self, sex, age):
self.sex = sex
self.age = age
# 子类Dog不但要继承父类的属性, 还有自己特有的属性name
class Dog(Animal): # 由于父类Animal定义了__init__, 所以子类会自动继承这个父类的__init__
# Dog类有三个属性, sex和age来自于Animal, name来自于自己
def __init__(self, sex, age, name): # 这里的三个形参的作用是给三个属性提供初值
self.name = name
# 由于Dog类也有__init__, 所以会把Animal类的__init__覆盖
super().__init__(sex, age) # 调用父类的__init__
def show(self): # 显示属性sex和age
print(f"name属性的值为{self.name}, sex属性的值为{self.sex}, age属性的值为{self.age}")
d = Dog("男", 10, "tom")
d.show()
'''
类Animal有属性age
类Dog继承自Animal,有属性name
类Dog有方法show, 显示属性age和name
'''
class Animal:
def __init__(self, age):
self.age = age
class Dog(Animal):
def __init__(self, name, age): # 由于Dog有两个属性name和age, 所以__init__提供了两个对应的形参
self.name = name
super().__init__(age)
def show(self):
print(f"我的名字叫{self.name}, 我的年龄是{self.age}")
d = Dog("小狗", 3)
d.show()
父类的私有成员子类不能继承
- 父类中带有连续两个下划线的方法和属性都是私有的, 私有的成员不能继承给子类
class Animal:
def __init__(self):
self.__name = "动物" # __name是私有属性
def __my_func(self): # 私有方法
pass
class Dog(Animal):
pass
d = Dog()
# d.__my_func() # 语法报错, 错误的原因是父类的方法是私有的, 不会继承给Dog类
# print(d.__name) # 语法报错, 原因是父类的私有属性,不能继承给子类
多态
- 不同的子类对象, 调用相同的父类方法, 产生不同的执行结果
类A有方法show
类B1和B2都是继承自类A
B1的对象调用show方法
B2的对象调用show方法
两个对象调用的都是父类的show方法, 但执行的结果不一样
'''
class A:
def show(self):
print("show")
class B1(A):
pass
class B2(A):
pass
b1 = B1()
b1.show()
b2 = B2()
b2.show()
# 上面的代码不同的子类对象, 调用相同的父类方法, 执行结果也是一样, 这个不是多态
'''
class A:
def show(self):
self.my_func()
def my_func(self):
print("我是a")
class B1(A):
def my_func(self):
print("我是b1")
class B2(A):
def my_func(self):
print("我是b2")
b1 = B1()
b1.show() # 内部代码一定是调用了B1 的my_func方法
b2 = B2()
b2.show() # 内部代码一定是调用了B2 的my_func方法
类属性
- 不需要类的实例, 直接可以使用的属性
- 普通属性(实例属性)一定要在方法内部定义, 定义的时候self.属性名 = 值
- 类属性定义在类的内部, 但是在方法的外部, 定义的时候不需要使用self
- 类属性直接用类名.类属性名 使用
# 类A的name是普通属性, 所以一定要实例化为对象后, 通过对象使用
class A:
def __init__(self, name):
self.name = name
a = A("tom")
print(a.name) # 使用对象a的属性name
# 普通属性, 也叫实例属性, 这个属性必须通过类的实例来使用
# 类B的name是类属性, 所以不需要实例, 直接可以通过类名使用
class B:
name = "tom" # 定义了一个类属性name, 值为"tom"
def __init__(self):
pass
print(B.name) # 使用B类的类属性name
类方法
- 普通方法也叫实例方法,, 只能通过实例调用的方法
- 不需要实例, 直接通过类名.类方法名就能调用的方法
class 类名:
@classmethod # 定义类方法上面必须写
def 类方法(cls, 形参1, 形参2......): # 类方法的第一个形参必须是cls
pass
class A:
@classmethod
def my_func(cls):
print("我是类方法my_func")
A.my_func()
类方法的形参cls的作用
cls的作用一
class A:
age = 0 # 这里定义的类属性age
@classmethod
def show_age(cls):
# 在类方法内部显示类属性的值
print(cls.age) # 在类方法内部使用类属性
@classmethod
def set_age(cls, age): # age是形参
# 在类方法内部修改类属性的值
cls.age = age # 把形参age的值给类属性age
A.set_age(200)
A.show_age() # 调用类方法
cls的作用二
class A:
@classmethod
def my_func1(cls):
print("my_func1")
@classmethod
def my_func2(cls):
# 在这个类方法中调用my_func1类方法
cls.my_func1()
A.my_func2()
class A:
__tmp = None # __tmp是当做类的A对象来使用, 但代码在这里还不确定, 所以给个None
@classmethod
def create(cls): # 只要调用类方法create就会生成类A的实例, 不管调用多少次, 但实例只有一个
if cls.__tmp is None:
cls.__tmp = A() # 如果条件成立, 执行实例化的过程
return cls.__tmp
else:
return cls.__tmp
def __init__(self): # 为了证明这个类到底被实例化了多少次
print("类A被实例化了, 因为实例化的时候会自动调用__init__")
# 类属性tmp的值是None, 所以if cls.tmp is None这个条件成立, 所以执行了实例化的语句cls.tmp = A()
a = A.create()
# 类属性tmp的值已经是一个对象了, 不是None, if cls.tmp is None条件不成立, 没有执行实例化的代码
b = A.create()
# 类属性tmp的值已经是一个对象了, 不是None, if cls.tmp is None条件不成立, 没有执行实例化的代码
c = A.create()
# 不管调用多少次create, 但cls.__tmp = A()语句只执行过一次
静态方法
- 不需要实例, 直接可以通过类名.静态方法名 调用的方法
class 类名:
@staticmethod
def 静态方法名(形参1, 形参2........):
pass
class A:
@staticmethod
def help(): # 定义静态方法help
print("我是静态方法help")
A.help() # 调用静态方法help
- 使用场景
- 如果一个项目, 有很多函数, 函数多了, 名字会重名, 可以把一些和类确实无关, 但有担心重名的函数, 做为类的静态方法使用
- 目的是避免因为函数重名带来的冲突
class A:
@staticmethod
def my_func():
print("aaaaaaaaaaaaaaa")
class B:
@staticmethod
def my_func():
print("bbbbbbbbbbbbbbbbbb")
A.my_func() # 本意是想调用第一个my_func
总结