面向对象之类和对象(一)
创始人
2024-05-26 09:25:08

1. 三大编程范式

  • 面向过程
  • 函数式编程
  • 面向对象设计

2. 编程进化论

  • 最开始无组织无结构,从简单控制流中按步骤写指令
  • 从上述指令中提取重复的代码看或逻辑,组织到一起(定义了一个函数),实现代码重用,由无结构走向了结构化,变得更具逻辑性。
  • 定义函数是独立函数外定义变量,然后作为参数传递给函数,意味着数据与动作是分离的。
  • 吧数据和动作封装到一个结构(函数或类),就有了个对象系统(对象就是数据与函数的封装)。

3. 类和对象

列表:数据封装、函数:语句层面的封装、对象:数据、函数的封装

  • 类:种类,将一类具有相同特性(抽象的)和动作的事物整合到一起就是类。

  • 基于类而创建的一个具体的事物(具体存在),也是特征和动作整合到一起。

现实世界是先有对象再有类,程序中先定义类,后再有对象

面向对象设计 OOD(object oriented design):将一类具体事务的数据和动作整合到一起

面向对象编程 OOP(object-oriented programming):用定义类+实例/对象的方式去实现面向对象的设计

实例化:由类抽象对象的过程实例化

不是只有用 class 定义类才是面向对象,def 定义函数就是函数相关,跟面向对象没有关系:

面向对象设计:

def school(name,addr,type):def init(name, addr, type):sch = {'name': name,'addr': addr,'type': type,'kao_shi': kao_shi,'zhao_sheng': zhao_sheng,}return schdef kao_shi(school):print('%s 学校正在考试' %school['name'])def zhao_sheng(school):print('%s %s 正在招生' %(school['type'],school['name']))return  init(name,addr,type)
s1 = school('清华大学', '中关村北大街', '公立学校')
print(s1)
print(s1['name'])
s1['kao_shi'](s1)
{'name': '清华大学', 'addr': '中关村北大街', 'type': '公立学校', 'kao_shi': .kao_shi at 0x0000000005382D90>, 'zhao_sheng': .zhao_sheng at 0x0000000005382BF8>}
清华大学
清华大学 学校正在考试

面向对象编程:

class School:def __init__(self, name, addr, types):self.name = nameself.addr = addrself.types = typesdef kao_shi(self):print('%s 正在考试' % self.name)def zhao_sheng(self):print('%s %s 正在招生' %(self.types, self.name))s1 = School('清华大学', '中关村北大街', '公立学校')
s1.kao_shi()
print(s1.__dict__)
清华大学 正在考试
{'name': '清华大学', 'addr': '中关村北大街', 'types': '公立学校'}

总结:

Python 是一门面向对象的语言,但是它不强制要求必须使用面向对象去设计代码,它不像 Java 一样万物皆是类。

3.1 类

类声明

class 类名:'类体字符串'类体def func():'函数文档字符串'函数体

3.2 实例化

self

如果把对象比作一个房子,那么 self 就是门牌号,有了 self 就可以轻松找到自己的房子。

当一个对象的方法被调用时,对象会将 自身的引用作为第一个参数传给该方法,那么 Python 就知道需要操作哪个对象的方法了。

class Students:def __init__(self, name, score):self.name = nameself.score = scoredef print_score(self):print('%s 分数是:%s' % (self.name, self.score))
s1 = Students('rose', 98)		# 相当于 s1 = Stuents.__init__(s1, 'rose', 98)
s1.print_score()rose 分数是:98

构造方法

通常把 __init__() 方法称为构造方法,只有实例化一个对象,这个方法就会在对象被创建时自动调用。实例化传入的参数自动传入 __init__() 中,可以通过重写这个方法来自定义对象的初始化操作:

class Students:def __init__(self, name):self.name = namedef print_score(self):print('名字 %s' % self.name)
s1 = Students('rose')		# 自动调用 __init__(),参数自动传入 __init__() 中
s1.print_score()

实例属性

对象只有数据属性,没有函数属性,用的时候找类要:

  • 类的数据属性是所有对象共享的
  • 类的函数属性是绑定给对象用的,在对象调用函数属性时,也能找到
# s1.__dict__ 查看对象属性
class Students:color = 'black'def __init__(self, name, score):self.name = nameself.score = scoredef print_score(self):print('%s 分数是:%s' % (self.name, self.score))
s1 = Students('rose', 98)
print(s1.__dict__)			# 查看对象属性字典,发现只有属性属性
print(id(Students.color))	# 对比发现类和对象的数据属性共享的
print(id(s1.color))
print(Students.print_score)		# 发现类的函数属性与实例的函数属性不一样,内存地址不一样
print(s1.print_score)
{'name': 'rose', 'score': 98}
82934784
82934784

>
# bound method :绑定方法(绑定了 类 Students 的 print_score 方法)

可以看出对象只有数据属性没有函数属性,类的函数属性与实例的函数属性不一样,内存地址不一样。

3.3 类属性增删改查

类属性又称为静态变量,或静态数据,这些数据与它们所属的类对象绑定,不依赖任何实例。如果是 java 程序员,这种类型数据相当于在一个变量声明前加上 static 关键字

类名:大写、函数属性:动词+名词

数据属性

class Chinese:country = 'China'	# 数据属性def __init__(self, name):self.name = namedef play_ball(self, ball):print('%s 正在打 %s' % (self.name))
p1 = Chinese('rose')
# 查看类属性
print(Chinese.country)
# 修改
Chinese.country = 'CHINA'
print(Chinese.country)
# 增加
Chinese.gender = 'male'
print(Chinese.__dict__)
# 删除
del Chinese.gender
print(Chinese.__dict__)
China
CHINA
{'__module__': '__main__', 'country': 'CHINA', '__init__': , 'play_ball': , '__dict__': , '__weakref__': , '__doc__': None, 'gender': 'male'}
{'__module__': '__main__', 'country': 'CHINA', '__init__': , 'play_ball': , '__dict__': , '__weakref__': , '__doc__': None}

函数属性

# 增加一个 eat 方法
def eat(self, food):print('%s 正在吃 %s' % (self.name, food))Chinese.test = eat		# test 指向 eat
p1.test('fish')
print(Chinese.__dict__)	
# Chinese.play_ball = ball		修改属性
rose 正在吃 fish
{'__module__': '__main__', 'country': 'China', '__init__': , 'play_ball': , '__dict__': , '__weakref__': , '__doc__': None, 'test': }

3.4 实例属性的增删改查

class Students:color = 'black'def __init__(self, name, score):self.name = nameself.score = scoredef print_score(self):print('%s 分数是:%s' % (self.name, self.score))
s1 = Students('rose', 98)
# 查看数据、函数属性
print(s1.__dict__)
print(s1.name)
print(s1.print_score)  # >  可以看出实例的函数属性绑定的是 类的函数属性(
{'name': 'rose', 'score': 98}
rose
>
{'name': 'rose', 'score': 98, 'age': 18}
{'name': 'rose', 'score': 98, 'age': 20}
{'name': 'rose', 'score': 98}

属性作用域

在 class 类中定义的数据属性,属于类的属性。在 __init__() 中定义的是实例的数据属性。不管是类的还是实例的数据属性,都只能使用点(.)方式访问,其他方式访问皆为普通变量

country = '中国》》》'
class Chinese:country = '中国'def __init__(self, name):self.name = nameprint('---->', country)			# 这里访问的就是普通变量,没有选择类的属性 country = '中国',而是选择了普通变量 country = '中国》》》'def eat(self):pass
p1 = Chinese('林雷')
# p1.country = '》》》中国'			# 其实这里是增加实例的数据属性
# print('类的数据属性:', Chinese.country)     类的数据属性: 中国
# print('实例的数据属性:', p1.country)        实例的数据属性: 》》》中国print(Chinese.country)
print(p1.country)----> 中国》》》
中国
中国

总结

  • 类的数据属性是所有对象都可以共享的,函数属性绑定给对象使用
  • 实例(对象)只有数据属性,没有函数属性,调用函数属性是对类的函数属性的引用

3.5 静态属性

我们知道类既有数据属性也有函数属性,而实例只有数据属性。在使用实例调用类的函数属性时,总要带上函数后面的括号才能运行,不然调用的是函数的内存地址:

class Room:def __init__(self, name, owner, width, heigh, length):self.name = nameself.owner = ownerself.width = widthself.heigh = heighself.length = lengthdef calc_area(self):print('%s 住的%s,总面积:%s' % (self.owner, self.name, self.width * self.length))r1 = Room('卧室', 'rose', 10, 3.5, 16)
r1.calc_area	# >

问题:那么有什么方法可以向调用数据属性一样调用函数属性呢?

类中提供了 @property 关键字,它的作用是在调用函数属性时,可以像调用数据属性一样并允许该函数,类似于函数中的装饰器。

class Room:def __init__(self, name, owner, width, heigh, length):self.name = nameself.owner = ownerself.width = widthself.heigh = heighself.length = length@property    def calc_area(self):print('%s 住的%s,总面积:%s' % (self.owner, self.name, self.width * self.length))
#         return self.width * self.length
r1 = Room('卧室', 'rose', 10, 3.5, 16)
# r1.calc_area()
r1.calc_area		# 省略括号

只需在需要被装饰的函数上面,加上 @property 即可。需要注意的是:被装饰的函数不能有除 self 参数以外的参数

3.6 类方法

如果不进行实例化,直接用类名调用类的函数属性,会报缺少位置参数:

class Room:def __init__(self, name, owner, width, heigh, length):self.name = nameself.owner = ownerself.width = widthself.heigh = heighself.length = length@propertydef calc_area(self):print('%s 住的%s,总面积:%s' % (self.owner, self.name, self.width * self.length))def open_door(self):print('打开%s的门' % self.name)Room.open_door()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
 in ()13         print('打开%s的门' % self.name)14 
---> 15 Room.open()TypeError: open_door() missing 1 required positional argument: 'self'

传入 self 做参数,也会报 name 'self' is not defined。这是因为 self 是特殊意义的,是实例本身,只有在实例化时才有效。为了解决这种问题,我们引入了 @classmethod ,:

class Room:size = 'small'def __init__(self, name, owner, width, heigh, length):self.name = nameself.owner = ownerself.width = widthself.heigh = heighself.length = length@propertydef calc_area(self):print('%s 住的%s,总面积:%s' % (self.owner, self.name, self.width * self.length))@classmethoddef open_door(cls, color):print(cls)		# cls 相当于 类本身,在定义类方法时自动补全print('请打开那扇 %s 的 %s门' % (color, cls.size))Room.open_door('red')---------------------------------------------------

请打开那扇 red 的 small门

可以看出一旦类的某个函数属性被定义为类方法时,可以直接使用类名调用类的函数属性,而不用担心参数的问题。在定义类方法时,Python 会自动补全一个名叫 cls 的参数,可以看出它就是类本身,在调用类函数属性时不需要手动传入,本身会自动传入,与 self 类似。

3.7 静态方法

如果有想在类中定义一个函数,要求该函数的参数与类、实例都无关(没有绑定),我们可以使用静态方法 @staticmethod

class Room:size = 'small'def __init__(self, name, owner, width, heigh, length):self.name = nameself.owner = ownerself.width = widthself.heigh = heighself.length = length@staticmethoddef close_door(position, color):print('请关闭 %s 的 %s 小门' % (position, color))r1 = Room('卧室', 'rose', 10, 20, 30)
Room.close_door('厨房', 'black')
r1.close_door('厕所', 'white')

被定义为静态方法的函数属性,名义上归类管理,但不能使用类变量和实例变量,只是类的工具包。

3.8 总结

  • **静态属性:**可以使用类、实例的数据属性,不能累调用(绑定实例)
  • **类方法:**不能使用实例的数据属性,可以用类、实例调用(与类绑定)
  • **静态方法:**不能使用类、实例的数据属性,可以用类、实例调用(与类、实例都不绑定)
  • **常规函数:**不能使用类、实例的数据属性,不能用实例调用(与类、实例都不绑定)
class Room:size = 'small'def __init__(self, name, owner, width, heigh, length):self.name = nameself.owner = ownerself.width = widthself.heigh = heighself.length = length@propertydef calc_area(self):print('%s 住的%s,总面积:%s' % (self.owner, self.name, self.width * self.length))@classmethoddef open_door(cls, color):#print(cls)print('请打开那扇 %s 的 %s门' % (color, cls.size))@staticmethoddef close_door(position, color):print('请关闭 %s 的 %s 小门' % (position, color))def test(a, b):print(a, '-->', 'b')r1 = Room('卧室', 'rose', 10, 20, 30) 
# 静态属性
Room.calc_area      # 不能调用
r1.calc_area 		# rose 住的卧室,总面积:300# 类方法
Room.open_door('white')		# 请打开那扇 white 的 small门
r1.open_door('white')		# 请打开那扇 white 的 small门# 静态方法
Room.close_door('卧室', 'black')		# 请关闭 卧室 的 black 小门
r1.close_door('卧室', 'black')		# 请关闭 卧室 的 black 小门# 常规函数
Room.test(1, 2)			# 1 --> b
r1.test(1, 2)    # 不能调用

4. 组合

组合就是把一个类实例化传入另一个类中使用。类与类之间相互关联,并且小的类组成大的类,这个时候可以用组合。

class Turtle:def __init__(self, x):self.x = x
class Fish:def __init__(self, x):self.x = xclass Pool:def __init__(self, x, y):self.tutle = Turtle(x)self.fish = Fish(y)def print_num(self):print('水池里总共有%s只乌龟,%s条鱼' % (self.tutle.x, self.fish.x))p1 = Pool(2, 3)
p1.print_num()
水池里总共有2只乌龟,3条鱼

选课系统:

class School:def __init__(self, name, addr):self.name = nameself.addr = addrdef zhao_sheng(self):print('%s正在招生' % self.name)class Course:def __init__(self, name, price, period, school):self.name = nameself.price = priceself.period = periodself.school = schoolclass Teacher:def __init__(self, name, gender, age):self.name = nameself.gender = genderself.age = ages1 = School('oldboy', '北京')
s2 = School('oldboy', '南京')
s3 = School('oldboy', '东京')t1 = Teacher('林老师', '男', '45')
t2 = Teacher('李老师', '女', '28')
t3 = Teacher('孙老师', '女', '32')c1 = Course('linux', '10000', '1', s1)
print(c1.__dict__)msg = """
1 老男孩 北京校区
2 老男孩 南京校区
3 老男孩 东京校区
4 林老师
5 李老师
6 孙老师
"""while True:print(msg)menu = {'1': s1,'2': s2,'3': s3,'4': t1,'5': t2,'6': t3}choice = input('请选择校区:')choice_teacher = input('请选择老师:')teacher_obj = menu[choice_teacher]school_obj = menu[choice]name = input('课程名:')price = input('课程费用:')period = input('课程周期:')new_course = Course(name, price, period, school_obj)  # school_obj = s1  print('课程【%s】属于【%s】学校' % (new_course.name, new_course.school.name)) # new_courese.school = s1    s1.name = name = oldboynew_teacher = Course(name, price, period, teacher_obj)print('%s由%s教' % (new_teacher.name, new_teacher.school.name))

相关内容

热门资讯

demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
阿西吧是什么意思 阿西吧相当于... 即使你没有受到过任何外语培训,你也懂四国语言。汉语:你好英语:Shit韩语:阿西吧(아,씨발! )日...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...