1. 面向对象的概念
1)类是一类抽象的事物,对象是一个具体的事物;用类创建对象的过程,称为实例化。
2)类就是一个模子,只知道在这个模子里有什么属性、什么方法,但是不知道这些属性、方法具体是什么;
所以,我们要在这个模子的基础上 造出一个具体的实例(对象),这个实例就会具体化属性、方法
3)所有的数据类型都是类,都是抽象的;根据数据类型定义变量,该变量就是一个具体的值(对象)。
面向过程 --> 面向对象的转变
定义一个函数 《==》 定义一个类
函数的返回值(字典) 《==》类的对象(类似字典,只不过调用方式发生了改变)
函数的执行过程 《==》类的实例化
请看 代码展示1 和 代码展示2
1 # 用面向对象的思想、面向过程的语法 去实现 Rectangle的计算 2 def Rectangle(length=0, width=0): 3 self = {} # 存储属性值 4 def __init__(*args): # 初始化函数 -- 完成对矩阵rectangle的长、宽初始化,以及面积、周长的调用方式 5 self['length'] = args[0] 6 self['width'] = args[1] 7 self['area'] = area 8 self['perimeter'] = perimeter 9 def area(): 10 return self['length'] * self['width'] 11 def perimeter(): 12 return 2 * (self['length'] + self['width']) 13 __init__(length, width) # 调用初始化函数 14 return self 15 16 rec_obj = Rectangle(10,5) # rec_obj 相当于类的一个实例 17 print(rec_obj) # rec_obj中存放了实例的属性、方法,通过实例可以查看属性 与 调用方法 18 print('length:%s, width:%s, area:%s, perimeter:%s' 19 %(rec_obj['length'], rec_obj['width'], rec_obj['area'](), rec_obj['perimeter']()))
代码展示1
1 class Rectangle: 2 temVar = 'over' #定义静态属性,共享于类中的每个对象 3 def __init__(self, *args): # 创建对象后执行的第一个函数,self就是类创建的对象,该函数返回类的对象self 4 self.length = args[0] 5 self.width = args[1] 6 def area(self): 7 return self.length * self.width 8 def perimeter(self): 9 return 2 * (self.length + self.width) 10 11 rec_obj1 = Rectangle(10, 5) # 实例化一个具体对象 12 13 # 通过 对象 查看属性(包括静态属性)与调用方法 14 print('length:%s, width:%s, area:%s, perimeter:%s' 15 %(rec_obj1.length, rec_obj1.width, rec_obj1.area(), rec_obj1.perimeter())) 16 print(rec_obj1.temVar) # 静态属性 17 18 # 通过 类名 调用方法 、类中的静态属性 19 print('area:%s, perimeter:%s'%( Rectangle.area(rec_obj1), Rectangle.perimeter(rec_obj1))) 20 print(Rectangle.temVar) # 静态属性 21 22 # 通过对象名修改属性(若self里 存在该属性,是修改;若self里 不存在该属性,是添加新属性) 23 # rec_obj1.length = 20 24 # rec_obj1.temVar = 'object_over' # 给对象中添加一个新属性 'temVar': 'object_over' 25 # 通过类名修改属性(若类里 存在该属性<静态属性>,是修改;若类里 不存在该属性,是添加新属性,<静态属性>) 26 # Rectangle.length = 50 # 在类中添加一个新属性 'length': 50 27 # Rectangle.temVar = 'class_over' 28 29 # __dict__的使用 30 print(rec_obj1.__dict__) # 查看对象的所有属性,即self属性 31 print(Rectangle.__dict__) # 查看类的所有静态属性、方法 32 # __dict__ 对于 对象的 增删改查操作都可以通过字典的语法进行 33 # __dict__ 对于 类中的名字只能看 不能操作
代码展示2
22 # 通过对象名修改属性(若self里 存在该属性,是修改;若self里 不存在该属性,是添加新属性)
23 # rec_obj1.length = 20
24 # rec_obj1.temVar = 'object_over' # 给对象中添加一个新属性 'temVar': 'object_over'
25 # 通过类名修改属性(若类里 存在该属性<静态属性>,是修改;若类里 不存在该属性,是添加新属性,<静态属性>)
26 # Rectangle.length = 50 # 在类中添加一个新属性 'length': 50
27 # Rectangle.temVar = 'class_over'
总结:
# 对象 = 类名()
# 实例化的过程:
# 类名() -> 会创造出一个对象,即创建了一个self变量
# 调用__init__(self)方法,类名括号里的参数会被这里接收
# 执行__init__(self)方法
# 返回self
# 对象能做的事:
# 查看属性(自己的属性 和 类中静态属性)
# 调用方法
# __dict__ 对于对象的增删改查操作都可以通过字典的语法进行
# 类名能做的事:
# 实例化
# 调用类中的属性,也就是调用静态属性
# 调用方法 : 只不过要自己传递self参数
# __dict__ 对于类中的名字只能看 不能操作
2. 类与对象的关系(类与对象的命名空间问题)
(1)类的命名空间
创建一个类,就会自动创建一个该类的命名空间,在该命名空间中存储类的属性(静态属性、动态属性(方法));
静态属性:直接在类中定义的变量;(静态属性属于类,即属于所有对象)
动态属性:在类中定义的函数;(动态属性绑定到所有对象)
(2)对象的命名空间
实例化一个对象,就会自动创建一个该对象的命名空间,在该命名空间中存放对象的属性;同时,在实例化之后,就后产生一个指向类对象指针,用来指向当前对象所属类的命名空间,这样就可以访问类的静态属性与动态属性。
在对象寻找属性的过程中,优先从对象的命名空间中搜索,然后去类的命名空间中查找,最后在父类的命名空间中查找...,若没有找到该属性,程序就会抛出异常。
注:类与对象的命名空间是独立存储的
完整代码展示:
class Family: ''' 定义一个公共账号 ,只要有人上班,就将钱存到这个账号上 ''' share_money = 0 # 不可变数据类型做静态属性 native_place = ['china'] # 可变数据类型做静态属性 def __init__(self, role, name, salary): self.role = role self.name = name self.salary = salary def work(self): Family.share_money += self.salary # 将每个的钱都存放到这个公共账号上 print('the account remains ¥%s '%Family.share_money) member1 = Family('father', 'lilei', 1000) member2 = Family('mother', 'zhanghua', 500) member1.work() # the account remains ¥1000 member2.work() # the account remains ¥1500 member1.share_money = 200 # 为自己独立开了个小金库,并存入200元 -- 在对象member1中添加这一属性 member1.share_money += 100 # 以后就可以在自己的小金库中存放私房钱,即总金额=200+100=300 member2.share_money += 400 # 将公有账号作为自己的私有账号,并存入400元,即总金额=1000+500+400=1900 print(Family.share_money) # 1000+500=1500 print(member1.share_money) # 200+100=300 print(member2.share_money) # 1000+500+400=1900 """ 可变数据类型做静态属性的影响: Family.native_place = 'america' # member1.native_place[0] = 'america' # 修改的是类中的native_place,会影响所有对象(同上) # member2.native_place[0] = 'america' # 修改的是类中的native_place,会影响所有对象(同上) print(member1.__dict__) print(member2.__dict__) print(Family.__dict__) {'role': 'father', 'name': 'lilei', 'salary': 1000, 'share_money': 300} {'role': 'mother', 'name': 'zhanghua', 'salary': 500, 'share_money': 1900} {'__module__': '__main__', '__doc__': 'n 定义一个公共账号 ,只要有人上班,就将钱存到这个账号上n ', 'share_money': 1500, 'native_place': ['america'], '__init__': <function Family.__init__ at 0x0000021C360084C8>, 'work': <function Family.work at 0x0000021C3629C048>, '__dict__': <attribute '__dict__' of 'Family' objects>, '__weakref__': <attribute '__weakref__' of 'Family' objects>} """ """ 可变数据类型做静态属性的影响: member1.native_place = 'america' # 重新赋值,在当前对象的命名空间中添加这个属性,不会影响其它对象 print(member1.__dict__) print(member2.__dict__) print(Family.__dict__) {'role': 'father', 'name': 'lilei', 'salary': 1000, 'share_money': 300, 'native_place': 'america'} {'role': 'mother', 'name': 'zhanghua', 'salary': 500, 'share_money': 1900} {'__module__': '__main__', '__doc__': 'n 定义一个公共账号 ,只要有人上班,就将钱存到这个账号上n ', 'share_money': 1500, 'native_place': ['china'], '__init__': <function Family.__init__ at 0x000002E4747684C8>, 'work': <function Family.work at 0x000002E4749FC048>, '__dict__': <attribute '__dict__' of 'Family' objects>, '__weakref__': <attribute '__weakref__' of 'Family' objects>} """
对类中静态属性访问规则:
(1)对于不可变数据类型来说,最好用类名操作静态属性;
若用对象名操作静态属性,其修改 和 重新赋值 都是独立的(独立的:对象与类的命名空间分开存放)
1)若用对象名第一次修改静态属性,首先会到类的命名空间中找到该静态属性的属性值,然后在当前对象的命名空间中再做修改
2)若用对象名直接给静态属性重新赋值,那么直接会在当前对象的命名空间中添加这一属性
(2)对于可变数据类型来说,用对象名修改是 共享的, 用对象名重新赋值是 独立的
因为修改的是指针变量所指向内存中的值,故是 共享的
!!!总结,操作静态属性,最好用类名操作静态属性;
补充:python中不可变数据类型与可变数据类型
不可变数据类型:对于相同的值对应的内存地址是不变的;
1 a = 1 2 b = 1 3 c = 2 4 d = a + b 5 print(" id(a) = %dn id(b) = %dn id(c) = %dn id(d) = %dn" 6 % (id(a), id(b), id(c), id(d))) 7 8 """ 9 id(a) = 1461563616 10 id(b) = 1461563616 11 id(c) = 1461563648 12 id(d) = 1461563648 13 """
可变的数据类型:对于相同值的内存地址是可变的;
1 al = [1, 2, 3] 2 bl = [1, 2, 3] 3 print(" id(al) = %dn id(bl) = %dn" % (id(al), id(bl))) 4 al.append(4) 5 bl += [4] 6 print(" id(al) = %dn id(bl) = %dn" % (id(al), id(bl))) 7 print(" al:%sn bl:%sn" % (al, bl)) 8 9 """ 10 id(al) = 2353965003720 11 id(bl) = 2353964735816 12 13 id(al) = 2353965003720 14 id(bl) = 2353964735816 15 16 al:[1, 2, 3, 4] 17 bl:[1, 2, 3, 4] 18 """
类属性的补充
一:我们定义的类的属性到底存到哪里了?有两种方式查看 dir(类名):查出的是一个名字列表 类名.__dict__:查出的是一个字典,key为属性名,value为属性值 二:特殊的类属性 类名.__name__ # 类的名字(字符串) 类名.__doc__ # 类的文档字符串 类名.__base__ # 类的第一个父类 类名.__bases__ # 类所有父类构成的元组 类名.__dict__ # 类的字典属性 类名.__module__ # 类定义所在的模块 类名.__class__ # 实例对应的类(仅新式类中)
3 __dict__ 与 dir() 的使用
""" 对象名.__dict__:查看对象的属性(self对象中存储的变量) 类名.__dict__:查看类的属性(在类中能看到的静态属性与动态属性) dir(对象名):查看对象的所有属性(此时包括self对象、类属性、内置方法) dir(类名):查看类的所有属性(不包括self对象) 注:在继承中,子类名.__dict__中看不到父类中的类属性,但实际上包括父类的类属性 """
案例分析
class Family: ''' 定义一个公共账号 ,只要有人上班,就将钱存到这个账号上 ''' share_money = 0 # 不可变数据类型做静态属性 native_place = ['china'] # 可变数据类型做静态属性 def __init__(self, role, name, salary): self.role = role self.name = name self.salary = salary def work(self): Family.share_money += self.salary # 将每个人的钱都存放到这个公共账号上 print('the account remains ¥%s '%Family.share_money) def fun(self): pass class NewFamily(Family): new_account = 0 def __init__(self, role, name, salary, kind): super(NewFamily, self).__init__(role, name, salary) self.kind = kind def work(self): pass # 使用__定义私有属性 # python中不存在严格的私有属性,在类的外部可通过正真的函数名【_类名__函数名,即 _NewFamily__expenditure】间接调用 def __expenditure(self): pass f = Family('father', 'lilei', 1000) nf = NewFamily("son", "liwei", 2000, "salesman") print("-"*20, "nf.__dict__ 与 f.__dict__ 对比", "-"*20) print(f.__dict__) print(nf.__dict__) print(set(nf.__dict__) - set(f.__dict__)) print("-"*20, "NewFamily.__dict__ 与 Family.__dict__ 对比", "-"*20) print(Family.__dict__) print(NewFamily.__dict__) print(set(NewFamily.__dict__) - set(Family.__dict__)) print("-"*20, "dir(nf) 与 dir(f) 对比", "-"*20) print(dir(f)) print(dir(nf)) print(set(dir(nf)) - set(dir(f))) print("-"*20, "dir(NewFamily) 与 dir(Family) 对比", "-"*20) print(dir(Family)) print(dir(NewFamily)) print(set(dir(NewFamily)) - set(dir(Family)))
输出结果:
""" -------------------- nf.__dict__ 与 f.__dict__ 对比 -------------------- {'role': 'father', 'name': 'lilei', 'salary': 1000} {'role': 'son', 'name': 'liwei', 'salary': 2000, 'kind': 'salesman'} {'kind'} -------------------- NewFamily.__dict__ 与 Family.__dict__ 对比 -------------------- {'__module__': '__main__', '__doc__': 'n 定义一个公共账号 ,只要有人上班,就将钱存到这个账号上n ', 'share_money': 0, 'native_place': ['china'], '__init__': <function Family.__init__ at 0x000001EC8159D288>, 'work': <function Family.work at 0x000001EC8159D318>, 'fun': <function Family.fun at 0x000001EC8159D3A8>, '__dict__': <attribute '__dict__' of 'Family' objects>, '__weakref__': <attribute '__weakref__' of 'Family' objects>} {'__module__': '__main__', 'new_account': 0, '__init__': <function NewFamily.__init__ at 0x000001EC8159D438>, 'work': <function NewFamily.work at 0x000001EC8159D4C8>, '_NewFamily__expenditure': <function NewFamily.__expenditure at 0x000001EC8159D558>, '__doc__': None} {'_NewFamily__expenditure', 'new_account'} -------------------- dir(nf) 与 dir(f) 对比 -------------------- ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'fun', 'name', 'native_place', 'role', 'salary', 'share_money', 'work'] ['_NewFamily__expenditure', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'fun', 'kind', 'name', 'native_place', 'new_account', 'role', 'salary', 'share_money', 'work'] {'_NewFamily__expenditure', 'new_account', 'kind'} -------------------- dir(NewFamily) 与 dir(Family) 对比 -------------------- ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'fun', 'native_place', 'share_money', 'work'] ['_NewFamily__expenditure', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'fun', 'native_place', 'new_account', 'share_money', 'work'] {'_NewFamily__expenditure', 'new_account'} """