python----类,面向对象(封装、继承、多态)(属性,方法)
2024-09-07 07:13:42
什么是对象?
- 对象是内存中专门用来存储数据的一块区域
- 对象中可以存放各种数据(数字、代码等)
- 对象由三部分组成(1,对象标识(id)2,对象类型(type)3,对象的值(value))
面向对象编程是最有效的编写方法之一;在面向对象编程中,编写表现和实现世界中的事物和情景的类,并根据这些"类"来创造"对象";使用"类"几乎可以模仿任何东西。
面向对象的三大特性:
- 封装:顾名思义将属性和方法封装到一个抽象的类当中,创建对象时再去调用;
- 继承:面向对象中的继承就是继承的类直接拥有被继承类的属性而不需要在自己的类体中重新再写一遍;继承实现代码的重用,相同的代码不需要重复的编写;
- 多态:多态就是不同的对象可以调用相同的方法然后得到不同的结果,(在python中处处体现着多态,比如不管你是列表还是字符串还是数字都可以使用+和*)
类的定义
所有的事物由两部分组成
- 数据(属性)
- 方法(动作)---(定义在类中的函数)
创建Dog类
创建的Dog类 有属性 有方法
- 属性:年龄(age) 名字(name)
- 动作:跑 叫
规定:定义类函数需用驼峰命名法(首字母大写)
class Dog(object):
def __init__(self,name,age): #初始化属性name和age
self.name = name
self.age = age
def run(self): #定义跑动作
print('%s is running.......' % self.name)
def bark(self): #定义叫的动作
print('%s is barking............' % self.name)
def __str__(self): #可以设定返回值
return 'dog_name %s \ndog_age %s岁' %(self.name,self.age)
wangcai = Dog('wangcai',2)
print(wangcai)
wangcai.run()
wangcai.bark()
.......................................................运行结果
#Dog为类,wancai是根据Dog类实例出来的一个对象;
dog_name wangcai
dog_age 2岁
wangcai is running.......
wangcai is barking............
类交叉
士兵突击
- 士兵许三多有一把AK47
- 士兵可以开火
- 枪能发射子弹
- 枪能装填子弹
class Gun(object):
def __init__(self,model):
self.model = model
self.count = 0
def add_bullet(self,count):
self.count+=count
def shoot(self):
if self.count >= 3:
self.count-=3
print('tututu>>>\n枪里还有%s发子弹'%self.count)
else:
print('没有子弹了!!!')
class Soldier(object):
def __init__(self,name):
self.name = name
self.gun = None
def fire(self):
if self.gun:
self.gun.shoot()
print('%s冲啊!!!'%self.name)
else:
print('没枪!没枪!')
def add(self):
self.gun.add_bullet(30)
def __str__(self): #__str__ 魔术方法return加print两个功能
return '士兵:%s 好同志!!!'%self.name
ak47 = Gun('AK47')
xusanduo = Soldier('xusanduo')
# xusanduo.fire()
xusanduo.gun = ak47
xusanduo.add()
xusanduo.fire()
................................运行结果
tututu>>>
枪里还有27发子弹
xusanduo冲啊!!!
封装
封装是面向对象的三大特性之一
封装指的是隐藏对象中一些不希望被外部所访问到的属性或方法
如何隐藏一个对象中的属性?
- 将对象的属性名,修改为一个外部不知道的名字
如何获取(修改)对象中的属性?
- 需要提供一个getter和setter方法使外部可以访问到属性
- getter 获取对象中的指定属性(get_属性名)
- setter 用来设置对象的指定属性(set_属性名)
使用封装,确实增加了类的定义的复杂程度,但是它也确保了数据的安全性
1.隐藏了属性名,使调用者无法随意的修改对象中的属性
2.增加了getter和setter方法,很好的控制的属性是否是只读的
如果希望属性是只读的,则可以直接去掉setter方法
如果希望属性不能被外部访问,则可以直接去掉getter方法
3.使用setter方法设置属性,可以增加数据的验证,确保数据的值是正确的
4.使用getter方法获取属性,使用setter方法设置属性
可以在读取属性和修改属性的同时做一些其他的处理
5.使用getter方法可以表示一些计算的属性
class Dog:
'''
表示狗的类
'''
def __init__(self , name , age):
self.hidden_name = name
self.hidden_age = age
def say_hello(self):
print('大家好,我是 %s'%self.hidden_name)
def get_name(self):
'''
get_name()用来获取对象的name属性
'''
# print('用户读取了属性')
return self.hidden_name
def set_name(self , name):
# print('用户修改了属性')
self.hidden_name = name
def get_age(self):
return self.hidden_age
def set_age(self , age):
if age > 0 :
self.hidden_age = age
d = Dog('旺财',8)
# d.say_hello()
# 调用setter来修改name属性
d.set_name('小黑')
d.set_age(-10)
# d.say_hello()
print(d.get_age())
隐藏属性
# 双下划线开头的属性,是对象的隐藏属性,隐藏属性只能在类的内部访问,无法通过对象访问
# 其实隐藏属性只不过是Python自动为属性改了一个名字
# 实际上是将名字修改为了,_类名__属性名 比如 __name -> _Person__name
# class Person:
# def __init__(self,name):
# self.__name = name
# def get_name(self):
# return self.__name
# def set_name(self , name):
# self.__name = name
# p = Person('孙悟空')
# print(p.__name) __开头的属性是隐藏属性,无法通过对象访问
# p.__name = '猪八戒'
# print(p._Person__name)
# p._Person__name = '猪八戒'
# print(p.get_name())
# 使用__开头的属性,实际上依然可以在外部访问,所以这种方式我们一般不用
# 一般我们会将一些私有属性(不希望被外部访问的属性)以_开头
# 一般情况下,使用_开头的属性都是私有属性,没有特殊需要不要修改私有属性
class Person:
def __init__(self,name):
self._name = name
def get_name(self):
return self._name
def set_name(self , name):
self._name = name
p = Person('孙悟空')
print(p._name)
setter方法和getter方法的装饰器
class Person:
def __init__(self,name,age):
self._name = name
self._age = age
# property装饰器,用来将一个get方法,转换为对象的属性
# 添加为property装饰器以后,我们就可以像调用属性一样使用get方法
# 使用property装饰的方法,必须和属性名是一样的
@property
def name(self):
print('get方法执行了~~~')
return self._name
# setter方法的装饰器:@属性名.setter
# setter方法的装饰器使用的前提要有property装饰器,因为必须要可以调用才可以更改
@name.setter
def name(self , name):
print('setter方法调用了')
self._name = name
@property
def age(self):
return self._age
@age.setter
def age(self , age):
self._age = age
p = Person('猪八戒',18)
p.name = '孙悟空'
p.age = 28
print(p.name,p.age)
继承
编写类时,并非总要从空白开始,如果你要编写的类是另一个类的特殊版本,可使用继承。一个类继承另一个类时他将自动获得父类的所有属性和动作,同时还可以有自己的属性和方法,发生冲突时以自己为准。
检查方法
# issubclass() 检查一个类是否是另一个类的子类
# print(issubclass(Animal , Dog))
# print(issubclass(Animal , object))
# print(issubclass(Person , object))
# isinstance()用来检查一个对象是否是一个类的实例
# 如果这个类是这个对象的父类,也会返回True
# 所有的对象都是object的实例
print(isinstance(print , object))
实例:
class Dog(object):
def __init__(self,name,age): #初始化属性name和age
self.name = name
self.age = age
def run(self): #定义跑动作
print('%s is running.......' % self.name)
def bark(self): #定义叫的动作
print('%s is barking............' % self.name)
def __str__(self): #__str__魔术方法,可以设定返回值
return 'dog_name %s \ndog_age %s岁' %(self.name,self.age)
class XiaoTianQuan(Dog):
def bark(self):
print('%s barking >>>>>>>>>>' % self.name)
def fly(self):
print("%s is flying.........."% self.name)
feitianwangcai = XiaoTianQuan('feitianwangcai',500)
print(feitianwangcai)
feitianwangcai.bark()
feitianwangcai.fly()
..........................................运行结果
dog_name feitianwangcai
dog_age 500岁
feitianwangcai barking >>>>>>>>>>
feitianwangcai is flying..........
使用super()继承父类属性
class Animal:
def __init__(self,name):
self._name = name
def run(self):
print('动物会跑~~~')
def sleep(self):
print('动物睡觉~~~')
@property
def name(self):
return self._name
@name.setter
def name(self,name):
self._name = name
# 父类中的所有方法都会被子类继承,包括特殊方法,也可以重写特殊方法
# 当我们需要继承父类中__init__属性时,还有需求添加一些属性
class Dog(Animal):
def __init__(self,name,age):
# 希望可以直接调用父类的__init__来初始化父类中定义的属性
# Animal.__init__(self,name) #可以继承父类的__init__属性,
# 但是此方法耦合性比较高,super() 可以用来获取当前类的父类,
# 并且通过super()返回对象调用父类方法时,不需要传递self
super().__init__(name)
self._age = age
def bark(self):
print('汪汪汪~~~')
def run(self):
print('狗跑~~~~')
@property
def age(self):
return self._age
@age.setter
def age(self,age):
self._age = name
d = Dog('旺财',18)
print(d.name)
print(d.age)
多继承
- 编写类时,可以继承多个父类的属性和动作,发生冲突时以前面的亲爹为主
- 多重继承,会使子类同时拥有多个父类,并且会获取到所有父类中的方法
- 在开发中没有特殊的情况,应该尽量避免使用多重继承,因为多重继承会让我们的代码过于复杂
- 如果多个父类中有同名的方法,则会现在第一个父类中寻找,然后找第二个,然后找第三个。。。
- 前边父类的方法会覆盖后边父类的方法
实例:
class Dog(object):
def __init__(self,name,age): #初始化属性name和age
self.name = name
self.age = age
def run(self): #定义跑动作
print('%s is running.......' % self.name)
def bark(self): #定义叫的动作
print('%s is barking............' % self.name)
def __str__(self): #可以设定返回值
return 'dog_name %s \ndog_age %s岁' %(self.name,self.age)
class Humen(object):
def __init__(self,name,age,power):
self.name = name
self.age = age
self.power = power
def talk(self):
print('I can talking!!')
def __str__(self):
return 'name %s \nage %s岁 \n战力值:%s' % (self.name, self.age, self.power)
class XiaoTianQuan(Humen,Dog): #大家可以尝试着换下位置
def fly(self):
print("%s is flying.........."% self.name)
feitianwangcai = XiaoTianQuan('feitianwangcai',500,10000)
print(feitianwangcai)
feitianwangcai.bark()
feitianwangcai.fly()
feitianwangcai.talk()
........................................................运行结果
name feitianwangcai
age 500岁
战力值:10000
feitianwangcai is barking............
feitianwangcai is flying..........
I can talking!!
类中的属性和方法
# 定义一个类
class A(object):
# 类属性
# 实例属性
# 类方法
# 实例方法
# 静态方法
# 类属性,直接在类中定义的属性是类属性
# 类属性可以通过类或类的实例访问到
# 但是类属性只能通过类对象来修改,无法通过实例对象修改
count = 0
def __init__(self):
# 实例属性,通过实例对象添加的属性属于实例属性
# 实例属性只能通过实例对象来访问和修改,类对象无法访问修改
self.name = '孙悟空'
# 实例方法
# 在类中定义,以self为第一个参数的方法都是实例方法
# 实例方法在调用时,Python会将调用对象作为self传入
# 实例方法可以通过实例和类去调用
# 当通过实例调用时,会自动将当前调用对象作为self传入
# 当通过类调用时,不会自动传递self,此时我们必须手动传递self
def test(self):
print('这是test方法~~~ ' , self)
# 类方法
# 在类内部使用 @classmethod 来修饰的方法属于类方法
# 类方法的第一个参数是cls,也会被自动传递,cls就是当前的类对象
# 类方法和实例方法的区别,实例方法的第一个参数是self,而类方法的第一个参数是cls
# 类方法可以通过类去调用,也可以通过实例调用,没有区别
@classmethod
def test_2(cls):
print('这是test_2方法,他是一个类方法~~~ ',cls)
print(cls.count)
# 静态方法
# 在类中使用 @staticmethod 来修饰的方法属于静态方法
# 静态方法不需要指定任何的默认参数,静态方法可以通过类和实例去调用
# 静态方法,基本上是一个和当前类无关的方法,它只是一个保存到当前类中的函数
# 静态方法一般都是一些工具方法,和当前类无关
@staticmethod
def test_3():
print('test_3执行了~~~')
a = A()
# 实例属性,通过实例对象添加的属性属于实例属性
# a.count = 10
# A.count = 100
# print('A ,',A.count)
# print('a ,',a.count)
# print('A ,',A.name)
# print('a ,',a.name)
# a.test() 等价于 A.test(a)
# A.test_2() 等价于 a.test_2()
A.test_3()
a.test_3()
特殊方法
官网:https://docs.python.org/3/reference/datamodel.html
# 特殊方法,也称为魔术方法
# 特殊方法都是使用__开头和结尾的
# 特殊方法一般不需要我们手动调用,需要在一些特殊情况下自动执行
# 定义一个Person类
class Person(object):
"""人类"""
def __init__(self, name , age):
self.name = name
self.age = age
# __str__()这个特殊方法会在尝试将对象转换为字符串的时候调用
# 它的作用可以用来指定对象转换为字符串的结果 (print函数)
def __str__(self):
return 'Person [name=%s , age=%d]'%(self.name,self.age)
# __repr__()这个特殊方法会在对当前对象使用repr()函数时调用
# 它的作用是指定对象在 ‘交互模式’中直接输出的效果
def __repr__(self):
return 'Hello'
# object.__add__(self, other)
# object.__sub__(self, other)
# object.__mul__(self, other)
# object.__matmul__(self, other)
# object.__truediv__(self, other)
# object.__floordiv__(self, other)
# object.__mod__(self, other)
# object.__divmod__(self, other)
# object.__pow__(self, other[, modulo])
# object.__lshift__(self, other)
# object.__rshift__(self, other)
# object.__and__(self, other)
# object.__xor__(self, other)
# object.__or__(self, other)
# object.__lt__(self, other) 小于 <
# object.__le__(self, other) 小于等于 <=
# object.__eq__(self, other) 等于 ==
# object.__ne__(self, other) 不等于 !=
# object.__gt__(self, other) 大于 >
# object.__ge__(self, other) 大于等于 >=
# __len__()获取对象的长度
# object.__bool__(self)
# 可以通过bool来指定对象转换为布尔值的情况
def __bool__(self):
return self.age > 17
# __gt__会在对象做大于比较的时候调用,该方法的返回值将会作为比较的结果
# 他需要两个参数,一个self表示当前对象,other表示和当前对象比较的对象
# self > other
def __gt__(self , other):
return self.age > other.age
# 创建两个Person类的实例
p1 = Person('孙悟空',18)
p2 = Person('猪八戒',28)
# 打印p1
# 当我们打印一个对象时,实际上打印的是对象的中特殊方法 __str__()的返回值
# print(p1) # <__main__.Person object at 0x04E95090>
# print(p1)
# print(p2)
# print(repr(p1))
# t = 1,2,3
# print(t) # (1, 2, 3)
# print(p1 > p2)
# print(p2 > p1)
# print(bool(p1))
# if p1 :
# print(p1.name,'已经成年了')
# else :
# print(p1.name,'还未成年了')
最新文章
- ios更新UI时请尝试使用performSelectorOnMainThread方法
- Resume简历中装B的词汇总结大全
- 不支持的关键字:“provider connection string”报错信息及解决方案
- struts 模型驱动
- 笑谈ArcToolbox (3) ArcToolbox的一亩三分地
- jmeter通过org.sqlite.JDBC驱动连接db数据库
- vue-router自动判断左右翻页转场动画
- Flume - Kafka日志平台整合
- alpha-咸鱼冲刺day7(后续一波)-紫仪
- Python——Flask框架——程序的结构
- java发送soapui格式的报文
- # 20175311 2018-2019-2 《Java程序设计》第2周学习总结
- Enum扩展特性,代替中文属性
- 使用Python进行并发编程
- HTML禁止右键复制【两行代码实现】
- Redis Cluster日常操作命令梳理
- PL/SQL第四章 where子语句
- Java url爬虫
- CSS 设置网页中选中文字的背景色
- 自己封装的ajax
热门文章
- spring boot集成mybatis-plus插件进行自定义sql方法开发时报nested exception is org.apache.ibatis.binding.BindingException: Invalid bound statement (not found):
- 今天写了一个SSM小项目,运行之后,前端页面的CSS、js样式显示不出来,具体操作如下:
- Yaml spring boot 二维数组写法
- Hbase学习Hbase基础介绍
- ABP vNext EventBus For RabbitMQ 分布式事件总线使用注意事项_补充官网文档
- Let’s Encrypt 通配符证书,泛域名证书申请配置
- 【Flutter】布局类组件之对齐和相对定位
- LeetCode220 存在重复元素 III
- 通过写n本书的积累,我似乎找到了写好技术文章的方法(回复送我写的python股票电子书)
- leetcode1637-两点之间不包括任何点的最宽垂直面积