命名空间不能直接包含字段或方法之类的成员是什么意思_Python 学习笔记之类与实例...
Python 学习笔记之类与实例
一、定义
1.1、定义
类 (class) 封装一组相关数据,使之成为一个整体,并使用一种方法持续展示和维护。
这有点像把零件组装成整车提供给用户,无须了解汽车的内部结构和工作原理,只要知道方向盘,刹车和油门这些外部接口就可以正常行驶。
类存在两种关系
- 继承(inheritance,is-a)自某个族类
继承可以用来表达本车属于某厂的哪个车族系列,除了继承原车系的技术和优势,还可基于某些环境进行改进。 - 组合(composition,has-a)了哪些部件
组合可用来表述该车使用了哪些零部件,比如最新的发动机。
类与模块的不同之处
- 类可生成多个实例。
- 类可被继承和扩展。
- 类实例的生命周期可控。
- 类支持运算符,可按需重载。
这些特性模块没有或者不需要,同时,模块粒度大,模块可用来提供游戏场景级别的解决方案,而类则是该场景下的特定家族和演员。
1.2、创建
定义类,以此为个体为例。关键字 class 同样是运行期指令,用于完成类型对象的创建。
class User:pass
可在函数内定义,以限制其作用范围。
类型与实例
如果类在模块中定义,那么其生命周期与模块等同,如果被放在函数内,那么每次都是新建。即便名字和内容相同,也属于不同类型。
def test():class X:passreturn X()>>> a,b = test(),test()>>> a.__class__ is b.__class__Out[1]: False
函数内定义的类型对象,在所有实例死亡后,会被垃圾回收。
类型对象除了用来创建实例,也为所有实例定义了基本操作接口,其负责管理整个家族的可共享数据和行为目标。
实例只保存私有特征,其以内部引用从所属类型或其它所属祖先类查找所需的方法,用来驱动展现个体面貌。
名字空间
类型有自己的名字空间,存储当前类型定义的字段和方法。这其中并不包括所继承的祖先成员,其同样以引用关联祖先类型,无须复制到本地。
class A:a = 100 #类字段def __init__(self, x): #实例初始化方法self.x = x #实例字段def_get_x(self): #实例方法return self.xclass B(A): #继承自Ab = "hello"def __init__(self, x, y):super().__init__(self,x) #调用父类的初始化方法self.y = ydef get_y(self):return self.y
实例 instance o 会保存所有继承层次的实例字段,因为这些都属于其私有数据。
>>> o = B(1,2)>>> print(A.__dict__){'a': 100,'__init__': <function A.__init__ at 0x109d04f28>, '_get_x': <function A._get_x at 0x109d046a8>, ...}>>> print(B.__dict__){'b': 'hello', '__init__': <function B.__init__ at 0x109d272f0>, 'get_y': <function B.get_y at 0x109d27378>, ...}
当通过实例或类访问某个成员时,会从当前对象开始(instance o 开始查找),依次由近到远向祖先类查找
(即 o --> class B --> class A 进行成员查找)。
如此做的好处就是祖先类的新增功能可以直接 【广播】给所有后代。
在继承层次的不同名字空间中允许有同名成员,并按顺序优先命中。
二、字段
依照所处空间不同,我们将字段分为类型字段和实例字段。
官方将成员统称为 Attribute,我们可按例将数据当做字段。
2.1、类型字段
【类型字段】在 class 语句块内直接定义,而实例字段必须通过实例引用(self)赋值定义。
仅从执行方式来看,无论实例方法存在于哪级类型,其隐式参数 self 总指向当前调用实例。
class A:def test(self): #self 总是指向引用的当前实例,这与继承层次无关print(self)self.x = 100class B(A):passif __name__=="__main__":o = B()print(hex(id(o)))print(o.test())0x109d2f358 <__main__.B object at 0x109d2f358>
实例参数 self 只是约定成俗的名字,这类似于其它语言中的 this,换成 this 同样有效。
2.2、字段赋值
可使用赋值语句为类型或实例添加的新字段。
class A: passif __name__=="__main__":A.x = 100 #新增类型字段print(A.x)print(vars(A))'''100{x': 100, ...}'''
可一旦实例重新赋值,就将会在其名字空间建立同名字段,并会遮蔽原字段。
a = A()a.b = 200print(a.b)print(vars(a))'''200{'b': 200}'''
2.3、私有字段
将私有字段暴露给用户是很危险的。因为无论是修改还是删除都无法截获,由此可能引发意外错误。因为语言没有严格意义上的访问权限设置,所以只好将它们隐藏起来。
如果成员名字以双下划线开头,但没有以双下划线结尾,那么编译器会自动对其重命名。
class X:__table = "user" #类型变量def __init__(self,name):self.name = name #实例变量def get_name(self):return self.name
同时双下划线开头课结尾的,通常是系统方法,比如 __ init __ ,__ hash __ ,__ main __等。
所谓重命名,就是编译器附加了类型名称前缀。虽然这种做法不能真正阻止用户访问,但基于名字的约定也算一种提示。这种方式让继承类也无法访问。
重命名机制总是针对当前类型,继承类型无法访问重命名后的基类成员。
可将双下划线前缀改为单下划线,这样虽然不能自动重命名,不过提示作用依旧。
class A:__name = "user" #双下划线成员class B(A):def test(self):print(self.__name)>>> B().test()'''AttributeError: 'B' object has no attribute '_B__name''''class A:_name = "user" #单下划线成员class B(A):def test(self):print(self._name)>>> B().test()'''user'''
三、属性
对私有字段会进行重命名保护,那公开字段如何处理呢?
问题是核心在于访问拦截,必须由内部逻辑决定如何返回结果。而属性(property)机制就是将读、写和删除操作映射到指定的方法调用上,从而实现操作控制。
class C:def __init__(self, name):self.__name = name@propertydef name(self): #读return self.__name@name.setterdef name(self, value): #写self.__name = value @name.deleterdef name(self): #删除raise AttributeError("can't delete attribute")c = C("user")print(c.name)# user c.name = "abc"print(c.name)# abcdel c.nameprint(c.name)#can't delete attribute
这种 @ 语法被称作装饰器(decorator)。
多个方法名必须相同,默认从读方法尅是定义属性,随后以属性名定义写和删除。
如果实现只读,或禁止删除,则只需去掉对应的方法即可。
四、方法
方法是一种特殊函数,其与特定对象绑定,用来获取或修改对象状态。
实际上,无论是对象构造,初始化,析构还是运算符,都以方法实现。根据绑定目标和调用方法的不同,方法可分为实例方法,类型方法,以及静态方法。
名字以上下划线开始和结束的方法,通常有特殊用途,其由解释器和内部机制调用。
实例方法
实例方法与实例对象绑定,在其参数列表中,将绑定对象作为第一参数,以便在方法中读取或修改数据状态。在以实例引用调用方法时,无须显式传入第一实参,而由解释器自动完成。
官方建议参数名用 self,同样以 cls 作为类型方法的第一参数名。
class W:def __init__(self, name):self.__name = namedef get(self): #以实例引用调用,自动传入 self 参数return self.__namedef set(self, value):self.__name = value>>> w = W("python")>>> w.get() #忽略第一参数'''python'''
类型方法
类型方法用来维护类型状态,面向族群提供服务接口。除绑定的第一参数名称不同外,还需添加专门的装饰器,以便解释器将其实例方法区分开来。
class D:__data = "D.data"@classmethod #定义为类型方法def get(cls): #解释器自动将类型对象 D 作为 cls 参数传入return cls.__data@classmethoddef set(cls, value):cls.__data = value>>> D.get() #同样忽略 cls 参数'''D.data'''
静态方法
静态方法,则更像是普通函数。其既不接收实例引用,也不参与类型处理,所以就没有自动传入第一参数。使用静态方法,更多原因是将类型作为一个作用域,或者当前类型添加便捷接口。
class DES:def __init__(self, key):self.__key = keydef encrypt_bytes(self, value):return str(self.__key) + str(value)@staticmethoddef encrypt(key, s):return DES(key).encrypt_bytes(s.encode("utf-8"))>>> DES.encrypt("key", "value")'''keyb'value''''
特殊方法
下面又解释器自动调用,与对象生命周期相关的方法。
- __ new __:构造方法,创建对象实例
- __ init __:初始化方法,设置实例的相关属性
- __ del __:析构方法,实例被回收时调用
创建实例时,会先调用析构方法和初始化方法。
class E:def __new__(cls, *args): #与__init__接收相同的调用函数print("__new__", args)return super().__new__(cls)def __init__(self, *args): ##self 由 __new__创建并返回print("__init__", args)>>> E(1,2)'''__new__ (1, 2)__init__ (1, 2)'''
如果 __ new __ 返回实例与 cls 类型不符,将导致 __ init __ 无法执行。
五、总结
学习到此,我总算把类的创建,属性和方法等弄清楚了,我最想强调一点,希望读者把 实例 self 参数弄明白,后续编码过程中使用较多。
还要清楚实例方法和静态方法的区别。
命名空间不能直接包含字段或方法之类的成员是什么意思_Python 学习笔记之类与实例...相关推荐
- 命名空间不能直接包含字段或方法之类的成员_Linux内存取证:解析用户空间进程堆(中)...
上文我们对解析用户空间进程堆的动机和历史,做了一个简要的概述.另外,我们Glibc堆的3层结构也做了一些概述,这些结构是解析用户空间进程堆的关键.至于每个结构所起的作用,请看本文的分析. 内存视图 本 ...
- Q:C#命名空间不能直接包含字段或方法之类的成员
一定是把什么代码写在类的外面了.我的问题就是在编代码时,无意间按到键盘上,多出个s... 转载于:https://www.cnblogs.com/sjxiaoe/p/5020636.html
- php video标签使用方法,HTML_HTML5 video标签(播放器)学习笔记(一):使用入门,近有在学习html5中video标签(播 - phpStudy...
HTML5 video标签(播放器)学习笔记(一):使用入门 近有在学习html5中video标签(播放器)的使用,这里做一些学习笔记,方便自己查阅和记录,本文是第一篇,将介绍的是使用该标签初始化该做 ...
- python查看方法作用_python学习笔记1,新手小白也能看得懂
这是酸菜在风变编程上学习python时积累的学习笔记,希望能帮到同样也在学习中的小伙伴.持续更新~ 第0关 Print()函数 (1)不带引号:让计算机读懂括号里的内容,打印最终的结果 例:print ...
- python基本模块中的对象_Python 学习笔记 -- OS模块的常用对象方法
1 #这里列举在os模块中关于文件/目录常用的函数使用方法 2 3 #这里需要注意下,在使用这些方法前记得导入os模块 4 import os #导入os模块 5 """ ...
- python from用法_python学习笔记1_import与from方法总结
python常用模块的命名约定 import numpy as np import pandas as pd import matplotlib.pyplot as plt import seabor ...
- python中如何创建一个空列表_Python学习笔记(1):列表的四种创建方法
我的电脑安装的是Anaconda 3开源的Python发行版本,其中是集合3.6版本的Python与可视化编程工具采用的是Spyder. 打开Spyder可视化工具,新建一个空白文件,做好备注为&qu ...
- python引用类 魔法方法_Python 学习笔记 -- 类的魔法方法
常用魔法方法 含义 __new__(cls[,...]) 1.__new__在对象被实例化时调用 2.第一个参数是类本身,其他参数传入__init__中 3.__new__如果没有返回值,则不会调用_ ...
- python基本随机生成函数_Python学习笔记(三):随机生成函数方法
本文是在Python2下总结! Python中的random模块用于生成随机数,如果想生成随机数需要先导入random的模块然后才能使用其中的方法,下面简单介绍一下常用的结果函数方法: 1·.rand ...
最新文章
- python编程试题定位列表元素的函数是_笨办法学Python 习题 34: 访问列表的元素
- 香港居民换领新智能身份证 市民对办理过程表满意
- leetcode_最长回文字符串
- BZOJ1423 : Optimus Prime
- 日志文件设计学习(一)
- c语言中不能编译,为什么`int;`可以在C语言中很好地编译,而在C ++中却不能?
- 2018北大计算机复试线,北京大学历年考研复试分数线_2018考研分数线
- android listview 预加载动画,Android - 使用预加载的数据库填充ListView
- 如何成为一名卓越的数据科学家——第一剑之再谈问题定义
- 计算机职业素养论文1500字,职业素养论文1500字 [职业素养教育论文]
- 购物中心弱电智能化系统工程施工方案
- 2019.11.28工作记录——InstallShield制作windriver驱动安装包
- tolua unity 报错_Unity Editor + tolua 在 Linux 下的 runtime 问题
- 高一被清华姚班录取,一个重度网瘾少年到理论计算机科学家的蜕变
- 一位10年 Java 工作经验的架构师聊 Java 和工作经验
- 什么软件测试苹果手机循环电池,如何检查iPhone电池的电池循环次数,看完你就明白了...
- [附源码]Python计算机毕业设计SSM基于的影评系统(程序+LW)
- POI读取word里面的表格并处理数据
- 初级——如何进行Android单元测试
- Android 读取CPU/GPU运行参数(MTK平台)
热门文章
- 运行时异常和检查性异常区别
- C++读取文本文件中以TAB作为分隔符,且中间字段有为空的情况的方法?
- Java中获取当前函数名
- mysql udb_MySQL InnoDB的一些参数说明
- aix 的c库为什么都是静态库_卢卡库:若梅罗、莱万都在努力突破极限,为什么我不能做到呢...
- 教你玩转CSS 媒体类型
- echarts的词云图表类型有哪些_数据可视化之常见12种图表类型分析
- linux 查看文件哈希码,使用linux的sha1sum命令查看效验文件哈希值命令
- java 什么是耦合_什么是耦合、解耦
- 测试社交软件有哪些,性格测试:测你适合哪个社交平台