面向对象简介
- Python是一门面向对象的编程语言
- 面向对象关注的是对象而不是过程
- 把功能保存到对象中,需要使用时直接找到对应功能的对象即可
- 便于阅读和维护以及复用,但编写时比较复杂
类(class)
- 之前学习的对象都是python的内置对象,但有时候并不能满足我们的所有需求,因此需要自定义的对象
- 类是一个模板(图纸),我们可以通过一个类来创建多个具体的对象,这个过程叫做“实例化”
- 类也是对象,通过同一类创建的多个实列称为同一类对象
类的创建
class MakeClass: # 命名一般用驼峰(大驼峰)
pass
m = MakeClass() # 类的调用也叫实例化,需要赋值给具体变量名(实例名)
属性和方法
在类代码块中,我们可以定义变量(属性)和函数(方法)
- 变量会成为该类实例的公共属性,所有的该实例都可以通过 对象.属性名 的形式访问
class Student:
name = '张三'
age = '18'
gender = '男'
a = Student()
print(a.name, a.age, a.gender)
>>> 张三 18 男
- 函数会成为该类实例的公共方法,所有该类实例都可以通过 对象.方法名() 的形式访问
class Student:
def test(self):
print(self)
def test1(self):
print('你好')
a = Student()
a.test()
a.test1()
>>> <__main__.Student object at 0x000002180CE018D0>
>>> 你好
参数self
- 属性和方法
- 类中定义的属性和方法都是公共的,任何该类实例都可以访问
- 属性和方法的查找流程
- 当我们调用一个对象的属性时,解析器会先在当前的对象中寻找是否还有该属性,如果有,则直接返回当前的对象的属性值。如果没有,则去当前对象的类对象中去寻找,如果有则返回类对象的属性值。如果没有就报错
- 类对象和实例对象中都可以保存属性(方法)
- 如果这个属性(方法)是所有的实例共享的,则应该将其保存到类对象中
- 如果这个属性(方法)是某个实例独有的。则应该保存到实例对象中
- 一般情况下,属性保存到实例对象中 而方法需要保存到类对象中
- self
- self在定义时需要定义,但是在调用时会自动传入。
- 习惯用self 表示实例本身
class Students:
def print_self(self):
print(self.name,self.age)
ls = Students()
ls.name = "李四"
ls.age = 18
ls.print_self()
>>> 李四 18
特殊方法
• 在类中可以定义一些特殊方法也称为魔术方法
• 特殊方法都是形如 _ _ xxx _ _() 这种形式
• 特殊方法不需要我们调用,特殊方法会在特定时候自动调用
_ _ init _ _ 方法在实例创建的时候默认调用 (类的初始化)
class Person:
# 在__init__方法的形参中,self之后的参数都需要在实例化的时候传入实参
def __init__(self, name):
self.name = name
def speak(self):
print('大家好,我是%s' % self.name)
p1 = Person('张三')
p1.speak()
>>> 大家好,我是张三
p2 = Person('张三')
p2.name = '李四'
p2.speak()
>>> 大家好,我是李四
p3 = Person('李四')
p3.__init__('张三')
p3.speak()
>>> 大家好,我是张三
静态方法
- 在类中用@staticmethod来修饰的方法属于静态方法
- 静态方法不需要指定任何的默认参数,静态方法可以通过类和实例调用
- 静态方法,基本上是一个和当前类无关的方法,它只是一个保存到当前类中的函数
- 静态方法一般都是些工具方法,和当前类无关
class Demo:
def __init__(self):
self.name = "rose"
self.age = 18
def test(self):
print(self.name)
@staticmethod # 通过@staticmethod装饰器 将 方法 转为 静态方法
def stat_test(gender): # 静态方法 self并不是必须添加的 加了也不代表对象
print("我是静态方法")
print(gender)
d = Demo()
d.test()
>>> rose
Demo.stat_test("female") # 一般通过类名调用
>>>
我是静态方法
female
封装
class Car():
def __init__(self, name, color):
# 属性名称 值
# 这种方式告诉别人这个是私有属性,不要轻易修改
self.hidden_name = name
self.hidden_color = color
car = Car('奔驰', '黑色')
# 语法: 对象.属性名 = 属性值 : 设置或者修改属性值
car.hidden_name = '五菱宏光'
car.name = '宝马' # 类对象里没有的属性,相当于重新创建了一个属性
print(car.hidden_name)
>>> 五菱宏光
print(car.name)
>>> 宝马
getter()和setter()方法是外部可以访问到属性
- getter() 获取对象中指定的属性
- setter() 用来设置对象指定的属性
- getter方法用于查看私有属性 如果只有一个getter方法,没有setter方法,那这个属性是一个只读属性
class Car():
def __init__(self, name):
#.__name 叫做完全封装 私有属性
self.__name = name
def get_name(self):
return self.__name
# setter方法是用来修改私有属性
def set_name(self, name):
self.__name = name
return '名字已修改!'
car = Car('奔驰')
# car.__name = '雪佛兰' 这种方式不要用,不专业
print(car.get_name())
>>> 奔驰
print(car.set_name('宝马'))
>>> 名字已修改!
print(car.get_name())
>>> 宝马
- _ 类名_ _属性名,print(car._Car__name) 这种方法也可以强行查看完全封装的属性,但是不要这样用,尽量用getter() 和 setter() 方法
property装饰器
- python提供了一个内置的属性函数:property 和 属性名.setter 两个装饰器,前者装饰get方法,后者装饰set方法,这样装饰后的 get 和 set 方法称为属性方法,可以像使用属性一样查看和修改
class Person():
def __init__(self, name):
self._name = name
# getter 方法
# property装饰器
@property
def name(self):
print('get 方法执行了')
return self._name
# setter方法的装饰器
@name.setter
def name(self, name):
print('set 方法执行了')
self._name = name
p1 = Person('张三')
print(p1.name)
# get 方法执行了
# 张三
p1.name = '李四'
# set 方法执行了
print(p1.name)
# get 方法执行了
# 李四
继承
在实际应用中,我们常会遇到如下问题
- 创建一个新的类会出现大量重复的代码
- 直接在原类上面修改,违反ocp原则(对扩展开放,对修改关闭)
- 想要直接从原类中拿到属性和方法
这时就需要用到类的继承
- 继承的方式就是在定义类名之后的括号里写上继承的父类(超类)
- object 是所有类的父类
- 继承了其他类的新类称为子类
# 定义一个父类
class Animal(object):
def sleep(self):
print('动物会睡觉')
def run(self):
print('动物会跑')
# 定义一个子类
class Dog(Animal):
pass
dog = Dog()
dog.run()
>>> 动物会跑
dog.sleep()
>>> 动物会睡觉
方法重写
- 方法的重写: 子类重写父类的方法,会将父类中的方法所覆盖掉 发扬光大的作用才会重写方法
class A(object):
def test(self):
print('A.....')
class B(A): # B继承A类
def test(self):
print('B......')
class C(B): # C继承B类
def test(self):
print('C......')
c = C()
c.test()
>>> C......
super()
class Animal(object):
def __init__(self, name):
self._name = name
def sleep(self):
print('动物会睡觉')
def get_name(self):
print('get 方法调用了')
return self._name
class Dog(object):
def __init__(self, gender):
self.gender = gender
class ZhongHua(Animal, Dog):
def __init__(self, name, age, gender):
super().__init__(gender)
super().__init__(name)
self.gender = gender
self._name = name
self.age = age
dog = ZhongHua('中华田园犬', 18, '公')
dog.sleep()
>>> 动物会睡觉
print(dog.get_name())
>>>
get 方法调用了
中华田园犬
多继承
- 提高问题的解决概率
- 提高问题的解决效率
- 提高解决问题的速度
- 降低爆发隐患的可能性
因此多继承在编程中应尽量减少使用
多态
- 封装:确保对象中数据的安全
- 继承:保证了对象的扩展性
- 多态:保证了程序的灵活性
- 只关心对象的实例方法是否同名,不关心对象所属的类型;
- 对象所属的类之间,继承关系可有可无;
- 多态的好处可以增加代码的外部调用灵活度,让代码更加通用,兼容性比较强;
- 多态是调用方法的技巧,不会影响到类的内部设计。
'''
定义时的类型和运行时的类型不一样,此时就称为多态
'''
class Perspon(object):
def print_info(self):
print("我是父类")
class Man(Perspon):
def print_info(self):
print("我是男人类")
def print_info(obj):
obj.print_info()
ace = Perspon()
ace.print_info()
>>> 我是父类
print_info(ace)
>>> 我是父类
jack = Man()
jack.print_info()
>>> 我是男人类
print_info(jack)
>>> 我是男人类
单例模式
- 单例模式是一种常用的软件设计模式,也就是说该类只包含一个实例
- 通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
- 通常应用在一些资源管理器中,比如日志记录等。
class single(object):
__isinstance = None
def __new__(cls, *args, **kwargs):
# 当对象不存在时,创建对象
# 当对象存在时,永远返回当前已经创建对象
if cls.__isinstance is None:
cls.__isinstance = super().__new__(cls)
return cls.__isinstance
else:
return cls.__isinstance
a = single()
b = single()
print(id(a))
>>> 2074957183296
print(id(b))
>>> 2074957183296 # 地址相同,说明a和b是同一个实例
_ _ new _ _() 方法
- _ _ new _ _() 方法用于创建与返回一个对象,在类准备将自身实例化时调用
- _ _ init _ _() 方法在对象创建的时候,自动调用
- _ _ init _ _ 实例方法 , _ _ new _ _ 静态方法
class Demo(object):
def __init__(self):
print("__init__")
def __new__(cls, *args, **kwargs):
# 此处重写了父类的__new__()方法,覆盖了父类__new__()创建对象的功能,所以对象并没有创建成功。所以仅执行__new__()方法内部代码
print("__new__")
d = Demo()
>>> __new__
对象创建执行顺序
- 通过 _ _ new _ _ () 方法创建对象
- 并将对象返回,传给 _ _ init _ _ ()
class Demo(object):
def __init__(self):
print("__init__")
def __new__(cls, *args, **kwargs):
# 重写父类__new__()方法
# 并且在该方法内部,调用父类的__new__()方法
print("__new__")
return super().__new__(cls)
d = Demo()
>>>
__new__
__init__
注意:
- 在创建对象时,一定要将对象返回,在会自动触发 _ _ init _ _ () 方法
- _ _ init _ _ () 方法当中的self,实际上就是 _ _ new _ _ 返回的实例,也就是该对象