python0.16------构造函数/析构函数/self详解/重写/访问限制/对象属性和类属性/@property/运算符重载

构造函数:__init__()
引子:因为每个人一出生都是不一样的。因此,如果在Person类中直接给类元素赋值有问题,它会导致每个人的初始状态相同,这不符合大自然的逻辑。应该根据每个人的特点,给每个出生的人不一样的特性。可以通过构造函数实现这个想法。__init__()函数在使用类创建对象自动调用。注意:如果不显式写出构造函数,默认会添加一个空的构造函数。

使用构造函数:
def __init__(self,name,age,height,weight):#一般定义属性在构造函数里面定义。
  self.name=name #self.name表示给当前对象创造一个属性。
  self.age=age #self.age表示给当前对象创造一个属性。
  self.height=height #self.height表示给当前对象创造一个属性。
  self.weight=weight #self.weight表示给当前对象创造一个属性。
  #当在person后面加实参时,实际上是调用了__init__()函数。

#调用

per1=Person(‘qie‘,18,180,60)。
per2=Person(‘bob‘,22,170,65)。
这样,per1和per2在出生的时候就不一样了。

析构函数:(编程时用得很少)
__del__() 表示释放对象时自动调用。
对象释放的原理:引用计数器原理。在创建对象的时候,有一个属性num=1,当有一个地方要用它,就有一个强指针指向它,num+1,释放一个强指针,num-1。当num为0时,系统自动释放这个对象。然后会调用析构函数。
当程序结束时,对象会被释放,会调用析构函数。
若强制释放对象,用del指令。然后系统会调用析构函数。
再函数里面定义的对象,会在函数结束时自动释放,这样可以用来减少内存空间的浪费。然后调用析构函数。

self详解:
self不是关键字,self可以由任何标识符代替,但是一般都用self。
self代表类的实例而非类。
哪个对象调用方法,那么该方法中的self就代表哪个对象。
self.__class__ 代表类名,只能在类的定义里面使用哦
例如:
def run(self):
per=self.__class__(‘bob‘,1,1,1)
print(per)
表示在run方法里面创建一个对象叫做per。

重写:将类定义的方法重新写一遍。

引子:如果一个对象,有100个属性,想把它们都打印出来,那么一般来说应该写成:print(per.a,per.b,per.c,per.d,..........,per.n100)。但是属性太多,这样输出写代码很累。如果能够用print(per)直接打印出所有属性就好了。因此,重写__str__()和__repr__()就能够满足要求.

例如:重写__str__()和__repr__()方法
__str__()方法  #它是给程序员用的,在调用执行print(对象名)时会被自动调用。
__repr__() 方法  #它是给机器用的,在python解释器里直接敲对象名后回车调用的。例如:在黑屏终端里面,直接敲per对象,就会调用__repr__()。

注意:1: __str__(),__repr__()需要返回值,返回值直接取代print里面的per!!!同时,若是没有定义__str__()方法,只定义了__repr__()方法,那么调用print(per)时会调用__repr__()方法。

访问限制:
如果我这个对象有100块钱的属性,如果在类的外面可以直接修改,那么别人可以轻松篡改我的零钱金额。这样显然不合理.要让对象的属性不在外部直接访问.那么可以在属性前面加上两个下划线。在python中如果在属性前面加上两个下划线,那么这个属性就相当于变成了私有属性(private)。在外部不能访问私有变量,在类内部可以访问私有变量。
可以在类里面更改money,通过自定义的方法对私有属性赋值和取值:
例如:一个类有一个私有变量__money
def getMoney(self):
  return __money
def setMoney(self,money):
  if money<0:
    self.__money=0
  else:
    self.__money=money

不能直接访问 per.__money 是因为python解释器把 __money 解释成了 __Person__money ,若直接访问__Person__money,就可以成功。但是强烈建议不要这么做。而且不同版本的解释器可能存在解释的变量名不一致的忧患。

在python中 __XXX__ 属于特殊变量,不是私有变量,特殊变量的值可以直接访问。表示系统已经写好了,有一些特殊的含义。

在python中 _XXX 变量,外部也是可以访问的。但是,按照约定的规则,当我看到这样的变量时。意思是‘虽然我可以被访问,但是请把我视作为私有变量,不要直接访问我。

对象属性和类属性:

类属性:
class Person(object):
  name="person" #类属性
  def __init__(self,name):
    self.name=name #对象属性

对象属性的优先级高于类属性。不要将对象属性与类属性同名。因为对象属性会屏蔽掉类属性。但是当删除对象属性后,再使用又会调用类属性。这样类属性就不可控。

可以动态的给对象添加对象属性,只针对当前对象生效,对于类创建的其它对象没有作用。
例如:
class Person:
  pass
  person=Person()
#动态添加属性:
person.name=‘bob‘

#动态添加方法:
先引入types类的 MethodType()方法
from types import MethodType() #偏函数,相当于将对象自己传进去
def say(self):
  print(‘my name is ‘+self.name)
per.speak=MethodType(say,per) #此时per对象就有了speak方法。其实MethodType()函数就是一个偏置函数,让say函数self默认赋值为对象名,再将修改后的函数赋值给speak变量。

注:如果想要限制实例的属性只允许为name,age,weight,其它的属性不能添加。那么在定义类的时候,可以定义一个特殊的属性(__slots__)。可以限制动态添加的属性。
例如:
class Person:
  __slots__=(‘name‘,‘age‘) #这样只能动态地增加name,age两个属性,包括方法。例如:人不会飞,因此不能给人飞的方法。

property:
用 对象.属性 访问和改变对象属性 比 对象.方法() 去改变和访问对象的属性要方便。
例如:
class Person:
  def __init__(self,age):
    self.__age=age
@property #访问
def age(self):
  return self.__age
@age.setter #修改
def age(self):
  if self.__age<0
    self.__age=0
  else:
    self.__name=age

print(per.age)   #相当于getAge()
per.age=1   #相当于SetAge(1)
注意,这并不等于直接操作私有变量,因为私有变量的赋值是有限制的。

运算符重载(‘+’运算符重载最常用):

引子:print(1+2) 输出3
print(‘1‘+‘2‘) 输出‘12’  #说明不同类型用加法会有不同的解释,也就是‘+‘运算符在不同类型的对象中有不同的作用,即‘+‘运算符在每个类里面都进行了重载。

#然而,新建一个自定义的类person的实例,却不能进行相加,为什么呢?因为没有进行运算符重载!!!
per1=person(1)
per2=person(2)
print(per1+per2)   #输出错误,因为‘+‘没有对person类型的解释。

#解决方法:

def __add__(self,other):
  return Person(self.num+other.num)   #运算符重载,记住一定要返回一个值哦,这里返回的是一个初始值为3的对象哦。
def __str__(self):
  return ‘num=‘str(self.num)    #重写__str__()方法,目的是当调用print(对象)时,直接打印有关对象的一些值。

调用:print(per1+per2)等价于print(per1.__add__(per2))

原文地址:https://www.cnblogs.com/yulianggo/p/9219288.html

时间: 2024-10-16 14:06:37

python0.16------构造函数/析构函数/self详解/重写/访问限制/对象属性和类属性/@property/运算符重载的相关文章

Apache Spark源码走读之16 -- spark repl实现详解

欢迎转载,转载请注明出处,徽沪一郎. 概要 之所以对spark shell的内部实现产生兴趣全部缘于好奇代码的编译加载过程,scala是需要编译才能执行的语言,但提供的scala repl可以实现代码的实时交互式执行,这是为什么呢? 既然scala已经提供了repl,为什么spark还要自己单独搞一套spark repl,这其中的缘由到底何在? 显然,这些都是问题,要解开这些谜团,只有再次开启一段源码分析之旅了. 全局视图 上图显示了java源文件从编译到加载执行的全局视图,整个过程中最主要的步

详解AJAX核心 —— XMLHttpRequest 对象 (下)

继续上一篇的内容上一篇关于XMLHttpRequest 对象发送对服务器的请求只说到了用Get方式,没有说Post方式的.那是因为要说Post方式就需要先说另外一个东西,那就是DOM(Document Object Model)文档对象模型.JavaScript通过DOM读取.改变或者删除 HTML.XHTML 以及 XML中的元素,可以重构整个 HTML 文档.可以添加.移除.改变或重排页面上的项目,而且这样的操作会马上显示在页面上.另外,所有浏览器执行W3C 发布的 DOM 标准规范,DOM

详解AJAX核心 —— XMLHttpRequest 对象 (上)

我要说的内容都是非常基础的内容,高手就免看了,如果看了欢迎给点意见啊.新手或者对低层还不是很了解的人可以看看,帮助理解与记忆. XMLHttpRequest 对象是AJAX功能的核心,要开发AJAX程序必须从了解XMLHttpRequest 对象开始. 了解XMLHttpRequest 对象就先从创建XMLHttpRequest 对象开始,在不同的浏览器中创建XMLHttpRequest 对象使用不同的方法: 先看看IE创建XMLHttpRequest 对象的方法(方法1): var xmlht

PHP 中 16 个魔术方法详解

前言 PHP中把以两个下划线__开头的方法称为魔术方法(Magic methods),这些方法在PHP中充当了举足轻重的作用. 魔术方法包括: __construct(),类的构造函数 __destruct(),类的析构函数 __call(),在对象中调用一个不可访问方法时调用 __callStatic(),用静态方式中调用一个不可访问方法时调用 __get(),获得一个类的成员变量时调用 __set(),设置一个类的成员变量时调用 __isset(),当对不可访问属性调用isset()或emp

sql学习笔记(16)----------mysql存储过程详解

mysql存储过程详解 1.     存储过程简介   我们常用的操作数据库语言SQL语句在执行的时候需要要先编译,然后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用执行它. 一个存储过程是一个可编程的函数,它在数据库中创建并保存.它可以有SQL语句和一些特殊的控制结构组成.当希望在不同的应用程序或平台上执行相同的函数,或者封装特定功能时,存储过程是非常有用的.

详解C# Tuple VS ValueTuple(元组类 VS 值元组)

C# 7.0已经出来一段时间了,大家都知道新特性里面有个对元组的优化:ValueTuple.这里利用详尽的例子详解Tuple VS ValueTuple(元组类VS值元组),10分钟让你更了解ValueTuple的好处和用法. 如果您对Tuple足够了解,可以直接跳过章节"回顾Tuple",直达章节"ValueTuple详解",查看值元组的炫丽用法. 回顾Tuple Tuple是C# 4.0时出的新特性,.Net Framework 4.0以上版本可用. 元组是一种

详解 随机访问流

(请观看本人博文--<详解 I/O流>) RandomAccessFile 类 (随机访问流) 概述: RandomAccessFile 类 的实例支持对随机访问文件的读取和写入. 随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组. 存在指向该隐含数组的光标或索引,称为文件指针: 输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针.如果随机访问文件以读取/写入模式创建,则输出操作也可用: 输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针.写入隐

lua学习笔记16:table元表详解

一 table本质 Lua中table本质实际上是个类似HashMap东西. 其元素是很多的Key-Value对,类似iOS中的字典NSDictionary. 如果尝试访问了一个表中并不存在的元素时,就会触发Lua的一套查找机制. lua"面向对象"就是凭借这个机制实现的. 示例: local tab = {} print(tab.key) 输出:nil 因为tab中没有任何元素,当然视图访问其key元素时就会找不到,所以返回nil. 二 元表metatable 元表,即元素列表,是t

C++卷积神经网络实例:tiny_cnn代码详解(7)——fully_connected_layer层结构类分析

之前的博文中已经将卷积层.下采样层进行了分析,在这篇博文中我们对最后一个顶层层结构fully_connected_layer类(全连接层)进行分析: 一.卷积神经网路中的全连接层 在卷积神经网络中全连接层位于网络模型的最后部分,负责对网络最终输出的特征进行分类预测,得出分类结果: LeNet-5模型中的全连接层分为全连接和高斯连接,该层的最终输出结果即为预测标签,例如这里我们需要对MNIST数据库中的数据进行分类预测,其中的数据一共有10类(数字0~9),因此全全连接层的最终输出就是一个10维的