python中类与对象的命名空间(静态属性的陷阱)、__dict__ 和 dir() 在继承中使用说明

1. 面向对象的概念

  1)类是一类抽象的事物,对象是一个具体的事物;用类创建对象的过程,称为实例化。

  2)类就是一个模子,只知道在这个模子里有什么属性、什么方法,但是不知道这些属性、方法具体是什么;

    所以,我们要在这个模子的基础上 造出一个具体的实例(对象),这个实例就会具体化属性、方法

  3)所有的数据类型都是类,都是抽象的;根据数据类型定义变量,该变量就是一个具体的值(对象)。

面向过程 --> 面向对象的转变

  定义一个函数   《==》 定义一个类

  函数的返回值(字典)   《==》类的对象(类似字典,只不过调用方式发生了改变)

  函数的执行过程 《==》类的实例化

  请看 代码展示1 和 代码展示2

python中类与对象的命名空间(静态属性的陷阱)、__dict__ 和 dir() 在继承中使用说明

 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

python中类与对象的命名空间(静态属性的陷阱)、__dict__ 和 dir() 在继承中使用说明

 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)对象的命名空间

  实例化一个对象,就会自动创建一个该对象的命名空间,在该命名空间中存放对象的属性;同时,在实例化之后,就后产生一个指向类对象指针,用来指向当前对象所属类的命名空间,这样就可以访问类的静态属性与动态属性。

  在对象寻找属性的过程中,优先从对象的命名空间中搜索,然后去类的命名空间中查找,最后在父类的命名空间中查找...,若没有找到该属性,程序就会抛出异常。

  注:类与对象的命名空间是独立存储的

python中类与对象的命名空间(静态属性的陷阱)、__dict__ 和 dir() 在继承中使用说明

 完整代码展示:

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'}  """

 

发表评论

相关文章