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) = %d\n id(b) = %d\n id(c) = %d\n id(d) = %d\n"
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) = %d\n id(bl) = %d\n" % (id(al), id(bl)))
4 al.append(4)
5 bl += [4]
6 print(" id(al) = %d\n id(bl) = %d\n" % (id(al), id(bl)))
7 print(" al:%s\n bl:%s\n" % (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'} """

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

  1. python中类与对象及其绑定方法的定义

    面向对象编程 什么是面向对象? 面向过程:将需要解决的问题按步骤划分,一步一步完成每一个步骤,而且          步骤之间有联系. 优点:复杂问题可以分步完成 缺点:扩展性很差,维护性差.如果中间 ...

  2. Python学习第十六课——静态属性(property, classmethod, staticmethod)

    计算所居住房子的面积 普通写法 class Room: def __init__(self,name,owner,width,length,heigh): self.name=name self.ow ...

  3. python 类、对象、方法、属性

    在python中,一个对象的特征也称为属性(attribute).它所具有的行为也称为方法(method) 结论:对象=属性+方法 在python中,把具有相同属性和方法的对象归为一个类(class) ...

  4. python类、对象、方法、属性之类与对象笔记

    python中一切皆为对象,所谓对象:我自己就是一个对象,我玩的电脑就是对象,坐着的椅子就是对象,家里养的小狗也是一个对象...... 我们通过描述属性(特征)和行为来描述一个对象的.比如家里的小狗, ...

  5. python中类与对象之继承

    面对对象的三大特性之继承 1.什么是继承? 在程序中,继承指的是class与class之间的关系 继承是一种关系,必须存在两个class才能产生这种关系:被继承的class称为父类,继承的class称 ...

  6. Python中类和对象在内存中是如何保存?

    类以及类中的方法在内存中只有一份,而根据类创建的每一个对象都在内存中需要存一份,大致如下图: 如上图所示,根据类创建对象时,对象中除了封装 name 和 age 的值之外,还会保存一个类对象指针,该值 ...

  7. Python进阶-XV 类和对象的命名空间 组合

    一.类和对象命名空间 1.类中可以定义两种属性 静态属性和动态属性 class Course: language = 'Chinese' # 静态属性 def __init__(self, name, ...

  8. Python()-类命名空间和对象/实例命名空间

    类命名空间和对象/实例命名空间: 创建类, 就会创建一个类的名称空间, 空间:存储类的属性 属性: 静态属性:直接定义在类下面 & 和类名关联 的变量 对象属性:在类内和self关联 & ...

  9. 不可或缺 Windows Native (19) - C++: 对象的动态创建和释放, 对象的赋值和复制, 静态属性和静态函数, 类模板

    [源码下载] 不可或缺 Windows Native (19) - C++: 对象的动态创建和释放, 对象的赋值和复制, 静态属性和静态函数, 类模板 作者:webabcd 介绍不可或缺 Window ...

随机推荐

  1. docker Compose 部署springboot+vue前端端分离项目

    温馨提示:如果有自己的服务器最好不过了,这样部署网项目就可以上线了.没有的话,只能使用localhost 本机访问啦,记得替换 ngixn 中的ip地址.域名为localhost. (一) 准备工作 ...

  2. 基于Docker-compose搭建Redis高可用集群-哨兵模式(Redis-Sentinel)

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_110 我们知道,Redis的集群方案大致有三种:1)redis cluster集群方案:2)master/slave主从方案:3) ...

  3. 配置 Druid 数据源及密码加密-SpringBoot 2.7 实战基础

    在SpringBoot中配置 Druid 数据源及密码加密的方法 前文集成 MyBatis Plus,实现了一组增删改查接口.在启动服务时,从控制台中可以看出 Spring Boot 默认使用 Hik ...

  4. MYSQL的Java操作器——JDBC

    MYSQL的Java操作器--JDBC 在学习了Mysql之后,我们就要把Mysql和我们之前所学习的Java所结合起来 而JDBC就是这样一种工具:帮助我们使用Java语言来操作Mysql数据库 J ...

  5. java学习第四天高级数组.day13

    正则表达式 冒泡排序 二分法查找 线性查找:从头找到尾,性能比较低. 二分法查找(折半查找):前提数组元素是有序的,性能非常优异. Arrays

  6. 275. H 指数 II--Leetcode_二分

    来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/h-index-ii 著作权归领扣网络所有.商业转载请联系官方授权,非商业转载请注明出处. 题目的大意是 ...

  7. 【Go实战基础】创建并完成第一个可执行的 go 程序

    实战需求:创建并完成第一个可执行的 go 程序.项目目录:go-001具体实战步骤如下: 一.进入工程目录 cd go-001/ 二. 创建 g001.go 文件 /* * @Author: 菜鸟实战 ...

  8. Springboot+MybatisPlus多数据源比对数据

    欢迎关注博主公众号「Java大师」, 专注于分享Java领域干货文章https://www.javaman.cn/ 基于不同的数据源进行数据比对,比较两个数据库的表之间数据的总量,以及处理后的总量,按 ...

  9. immutable 与 stable 函数的差异

    Stable 函数不能修改数据库,单个Query中所有行给定同样的参数确保返回相同的结果.这种稳定级别允许优化器将多次函数调用转换为一次.在索引扫描的条件中使用这种函数是可行的,因为索引扫描只计算一次 ...

  10. Netty使用手册翻译

    前言 痛点 时至今日,我们通常会使用应用程序或第三方库去提供通信功能.比如:我们通常使用HTTP客户端库去Web服务器检索信息;通过web服务调用一个远程程序.然而,一个通用协议或者它的实现往往不能适 ...