一、类的基础知识

  python 一切皆为对象。

  我们以前的str,list,int 都是对象。

1.1 类的定义 与 调用

  class 关键字用来定义类,注意类名首字母大写。

  类的调用,先实例化一个类,叫做对象或实例。使用这个实例调用其中的方法。

  其实在之前我们一直在使用面向对象,str本身就是一个类。

     s = ‘abc’  -》 s = str(abc)  # 看源码对= 进行了运算符的重载,生成一个对象。就是我们类的调用。

     s.upper()   调用里面的方法。

class Foo:
def run(self):
print('run')
obj = Foo()
obj.run()

1.2类 与 实例的存储 self 的含义

  在定义类的方法的时候,都需要写一个self,但是在调用的时候又不要写。

  其实self就是调用者本身。把self传递给类。self永远是调用者本身。这在继承的时候非常关键。

  在python运行的时候,

      类存储着本身的各种方法与一些类属性

      实例只存储自身的属性,与类的内存指针

  当两个实例去调用类里面的方法的时候,使用self传递本身,在调用类中同一个方法,这样在调用的时候就能区别,是谁调用了这个方法。

class Foo:
def run(self, arg):
print(self, arg) obj1 = Foo()
obj1.run(111)
print(obj1)

self

class F:

    def f1(self):
print('F.f1') def f2(self):
print('F.f2') class S(F):
def s1(self):
print('S.s1') obj = S() obj.s1()
obj.f1() # S中没有f1,F中有,obj去执行,上面的self还是obj

self 永远是调用者本身

二 、面向对象三大特征

  面向对象的三大特性:

    1. 封装

    2.继承

    3.多态

2.1 封装

  封装是把属性关联到实例(对象)中。下次调用的时候,直接去实例中调用。

  python封装分为两种(本质是一样的):

      使用构造函数__init__进行封装

      动态属性封装

2.1.1 构造方法 __init__

  类名+()  就会自动执行__init__

  在创建对象(实例化)的时候,类内部会自动调用__init__方法,别名构造方法。利用这个特性我们就可以把属性封装到里面。

  封装和构造方法是没有关系的,我们是利用构造方法的特性来封装。

  这样所有的实例,都有相同的属性,同时可以通过对象去调用。

class Foo:

    def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex obj = Foo()
obj.name

2.1.2 动态属性

  创建对象之后,动态的添加,但是这种添加只属于该实例本身。

class Foo:
def run(self, arg):
print(self, arg)
obj1 = Foo()
obj1.a = 1
obj1.b = 'abc'
print(obj1.a)
print(obj1.b)

  新加的属性,只是保存在这个实例的内存中,其他的实例的内存没有。

  但是这种方法,会造成实例属性的不一致,造成管理的难度。一般都是构造函数统一。

  在类中有个特殊方法__slots__,可以对动态属性进行了限制。

class Foo:
__slots__ = ('name', 'age', 'sex') # 实例只能有这些属性 def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex obj = Foo('li', 18, 'M')
obj.v = 'v'   # 报错,不能添加__slots__以外的动态属性

2.1.3 从封装角度去选择函数 or 面向对象

  如果多个函数中有一些相同参数时,就可以把函数转换为面向对象。

  如下例子,如果使用函数,ip,port,username,pwd等参数在每个函数中都要去写。

       如果转换为面向对象,那么把这些参数封装起来,下面的方法都可以 使用了。

    class DataBaseHelper:

        def __init__(self, ip, port, username, pwd):
self.ip = ip
self.port = port
self.username = username
self.pwd = pwd def add(self,content):
# 利用self中封装的用户名、密码等 链接数据
print('content')
# 关闭数据链接 def delete(self,content):
# 利用self中封装的用户名、密码等 链接数据
print('content')
# 关闭数据链接 def update(self,content):
# 利用self中封装的用户名、密码等 链接数据
print('content')
# 关闭数据链接 def get(self,content):
# 利用self中封装的用户名、密码等 链接数据
print('content')
# 关闭数据链接

2.2 继承

  继承就像老子传递给儿子一些东西。 比如金钱,一些习惯。但是一些坏习惯,还有媳妇是不能继承的。

  继承遵循开放和封闭原则(修改禁止,支持扩展)。如果一些web框架或其他模块,我们直接下载下来进行修改,部署到生产线上,我们要对所有的web框架的源代码进行修改。

  这样很麻烦,而且出现问题的时候,不知道是哪出错了,这时候我们就要使用继承来扩展功能了。

2.2.1 继承的表现形式

class F:

    def f1(self):
print('F.f1') def f2(self):
print('F.f2') class S(F):
def s1(self):
print('S.s1') obj = S() obj.s1()
obj.f1() # s中没有 f1方法,但是因为继承了,所以也能执行

2.2.2 重写

  重写类似与,我不想用父类的方法,想自己写这个方法。只要同名的就可以了。

class F:
def f1(self):
print('F.f1')
def f2(self):
print('F.f2')
class S(F):
def s1(self):
print('S.s1')
def f2(self): # 默认S如果没有重写f2,会执行父类的f2.现在重写了,执行自己的f2.
print('S.f2')
obj = S()
obj.s1()
obj.f1()

2.2.3  执行父类的方法。

  执行父类的方法。当我们重写了某个方法,但是又想在这个重写的函数中,执行下父类的该方法。

  (一般都这这么使用的,当然也可以执行父类的其他方法。因为默认都继承了父类的方法。只有重写了才需要执行父类的方法)

  那我们就可以使用super。

class F:
def f1(self):
print('F.f1')
def f2(self):
print('F.f2') class S(F):
def s1(self):
print('S.s1')
def f2(self):
print('S.f2')
super(S, self).f2() # 执行父类的方法,也可以执行,父类的其他方法
# F.f2(self) # 也可以主动执行,这种方法必须在函数运行时,必须主动传递self。 不推荐这种使用方法。
obj = S()
obj.f2() 运行结果:
S.f2
F.f2

2.2.4 多继承

  在java和php其他语言中是不支持多继承的。python和c++支持。

  多继承查找规则

    1.左侧的优先,一条路走到底,如果左侧没有,则在右边的执行

    2.如果有共同的跟,跟是查找所有之后,最后一步执行的

如上图,如果一个方法只存在Base和F2中,S执行该方法,优先查找F2。如下代码

class base:
def a(self):
print('base.a') class F0(base):
def a1(self):
print('F0.a') class F1(F0):
def a1(self):
print('F1.a') class F2(base):
def a(self):
print('F2.a') class S(F1, F2):
pass s = S()
s.a()

交叉继承实例

多继承一个案列解析(类似socketserver源码):

  self永远是执行者本身,调用方法的时候,要从self的类中开始查找该方法。

class BaseRequest():
def __init__(self):
print('BaseRequest.INit') class RequestHandler(BaseRequest): def __init__(self):
print('RequestHandler.init')
super(RequestHandler,self).__init__() def serve_forever(self):
print('RequestHandler.server_forver')
self.process_request() def process_request(self):
print('RequestHandler.process_request') class Minix: def process_request(self):
print('Minix.process_request') class Son(Minix, RequestHandler):
pass obj = Son()
obj.serve_forever() # ,进入到requestHandler中的serve_forver,但是该方法中有个process_request
#self是Son对象,所以又会重新开始查找,根据查找次序,左侧优先,Minix中有。

多继承类似socket源码揭破

2.3 多态

  python中不用考虑多态。python原生就是多态的。

  java中申明一个变量必须强指定一个类型,函数接受的时候必须严格指定接受参数的类型。

  python中一个变量的类型是根据内容进行转换的,在函数接受参数的时候也可以随意。

三、类成员

  一个类中有属性和方法,统称为成员。下面我们对类成员进行了简单的分类。

# 属性
  - 普通属性,保存在对象中,执行只能通过对象访问          对象实例化时候创建,每个对象有自己一份属性
  - 静态属性,保存在类中,   执行可以通过对象访问 也可以通过类访问      类初始化时候创建,所有人共用一份,节约内存

# 方法
  - 普通方法,保存在类中,由对象来调用,self=》对象
  - 静态方法,保存在类中,由类直接调用
  -    类方法,保存在类中,由类直接调用,cls=》当前类

class Province:
# 静态属性
country = '中国' def __init__(self, name):
# 普通属性
self.name = name
# 普通方法
def bar(self):
print(self.name)
# 静态方法
@staticmethod
def sta():
print('')
# 类方法
@classmethod
def stac(cls):
print('')

3.1 属性

  python中的属性就只有两种类型:普通方法 和 静态方法。

3.1.1 普通属性

  在我们利用__init__或动态添加实例的属性,这些都是普通属性,在对象实例化的时候产生,每个对象都有自己一份属性,相互之间不干扰。

3.1.2 静态属性

  静态属与类,保存在类中,对象和类都可以访问,在类初始化的时候创建。只保存一份。

  当一个对象修改了静态属性,其他看到的都是修改了(后面我们可以把其定义为私有的,避免修改)。

  应用场景:所有对象,都有共同的属性,如果用普通属性,每个对象中都会保存一份,大大的消耗内存,这样就可以使用静态属性了。

      比如国籍,学校的地址等

3.2 方法

  python的方法我们分为三类:普通方法,静态方法,类方法。

3.2.1 普通方法

  上面我们定义的都是普通方法,普通方法有两种调用形式:

方法1:
obj = Foo()
obj.run() # 有个self,自动把obj传递过去
方法2:
obj = Foo()
Foo.run(obj)   #
手动传递对象,一般都不使用这种方式

3.2.2 静态方法

定义形式:  

class Foo:
@staticmethod
def sta():
print('')

不需要传递对象self,就相当于一个普通方法。由类来调用,但是也可以用对象来调用,一般都不这么做。

在一些功能,不依赖于对象中的参数的时候,就可以这么来定义。类似函数,可以自己定义函数参数,不需要self传递东西

3.2.3 类方法

  类方法定义:

class Foo:
@classmethod
def stac(cls): # 需要传递一个类
print(''
)

四、 property

  property是一个比较有意思的东西。它是把一个方法 像 属性一样去调用。分页的场景中可以使用。(属性具有 查看,删除,设置方法。)

  property其实 就是指定的代码语法 映射到类中指定的方法去接受。  类方法中,想执行什么都是我们自己定义的。

  有两种实现方式:

第一种:使用装饰器的方法实现,方法名需要一致。

class Foo:
@property    # 映射取值
def per(self):
print('我是不伦不类的', '') @per.setter # 映射设值
def per(self, val):
print(val) @per.deleter # 映射删除
def per(self):
print('我执行了删除') obj.per # 取值
obj.per = '这是啥东西?' # 设值
del obj.per # 删

第二种实现:直接使用内置函数property。代码实现方式:在一些源代码中会这么写

class Foo:
def f1(self):
return 123 def f2(self, v):
print(v) def f3(self):
print('映射了删除') per = property(fget=f1, fset=f2, fdel=f3) obj = Foo()
obj.per
obj.per = '这是啥东西?'
del obj.per

面向对象:三大特性、类成员、property的更多相关文章

  1. day20面向对象三大特性 , 类嵌套

    #!/usr/bin/env python# -*- coding:utf-8 -*- # 1.简述面向对象三大特性并用代码表示."""封装:class Account: ...

  2. 面向对象编程(九)——面向对象三大特性之继承以及重写、Object类的介绍

    面向对象三大特性 面向对象三大特征:继承 :封装/隐藏 :多态(为了适应需求的多种变化,使代码变得更加通用!) 封装:主要实现了隐藏细节,对用户提供访问接口,无需关心方法的具体实现. 继承:很好的实现 ...

  3. [.net 面向对象编程基础] (11) 面向对象三大特性——封装

    [.net 面向对象编程基础] (11) 面向对象三大特性——封装 我们的课题是面向对象编程,前面主要介绍了面向对象的基础知识,而从这里开始才是面向对象的核心部分,即 面向对象的三大特性:封装.继承. ...

  4. [.net 面向对象编程基础] (12) 面向对象三大特性——继承

    [.net 面向对象编程基础] (12) 面向对象三大特性——继承 上节我们说了面向对象的三大特性之一的封装,解决了将对同一对象所能操作的所有信息放在一起,实现统一对外调用,实现了同一对象的复用,降低 ...

  5. [.net 面向对象编程基础] (13) 面向对象三大特性——多态

    [.net 面向对象编程基础] (13) 面向对象三大特性——多态 前面两节,我们了解了面向对象的的封装和继承特性,面向对象还有一大特性就是多态.比起前面的封装和继承,多态这个概念不是那么好理解.我们 ...

  6. JAVA基础——面向对象三大特性:封装、继承、多态

    JAVA面向对象三大特性详解 一.封装 1.概念: 将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问. 2.好处: 只能通过规定的方法访问数据. ...

  7. 夯实Java基础系列1:Java面向对象三大特性(基础篇)

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 [https://github.com/h2pl/Java-Tutorial](https: ...

  8. Java面向对象——三大特性

    Java面向对象——三大特性 摘要:本文主要介绍了面型对象的三大特性. 封装 什么是封装 封装,就是指一个类隐藏了对象的属性和实现细节,对自己的数据和方法进行访问权限控制,只允许某些类和对象进行访问和 ...

  9. JavaSE学习笔记(3)---面向对象三大特性

    JavaSE学习笔记(3)---面向对象三大特性 面向对象的三大特征:继承.封装.多态 1.封装 面向对象编程语言是对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界无法直接操作和修改.然 ...

  10. C++面向对象三大特性

    面向对象三大特性 继承 public protected private public继承 public protected 不可见 private继承 private private 不可见 pro ...

随机推荐

  1. java初学一

    1.区分大小写 public static void main String args[]  是类体中的一个方法,之后的两个大括号以及之间的内容叫做方法体,一个java应用程序中必须有一个类且只有一个 ...

  2. [原创]CSS 去掉点li 的点 使得LI前面的点不在显示

    我对博客的认识是:记录问题,解决问题,分享知识.如果有轮子,我不需要造轮子. 1.问题解决方式: 设置属性:li {list-style-type:none;} 2.更多属性参数参考 list-sty ...

  3. CentOS 6.3编译安装LAMP环境笔记

    转载地址:http://www.jb51.net/article/54969.htm 最近抽空在虚拟机上测试成功了LAMP各个最新版本的整合编译安装,算是把之前的博文整合精简,以下内容均在CENTOS ...

  4. MySQL-5.7 备份与恢复

    一.备份分类 按介质分类: 物理备份 指通过拷贝数据库文件方式完成备份,适用于数据库很大,数据重要且需要快速恢复的数据库. 逻辑备份 指通过备份数据库的逻辑结构和数据内容的方式完成备份,适用于数据库不 ...

  5. C/C++中RAND_MAX的用法

    RAND_MAX是C中stdlib.h中宏定义的一个字符常量: #define RAND_MAX Ox7FFF 其值最小为32767,最大为2147483647 通常在产生随机小数时可以使用RAND_ ...

  6. springmvc.xml配置图解

  7. Centos下ftp协议连接远程ftp server主机

    环境说明 [root@Check3 ~]# cat /etc/redhat-release CentOS release 6.9 (Final) [root@Check3 ~]# uname -a L ...

  8. com.mysql.jdbc.MysqlDataTruncation:Data Truncation:Data too long for column '字段name' at row 1

    1.问题描述: 在mysql插入数据的时候报错:Cause: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long fo ...

  9. ASP.NET OAuth Authorization - Difference between using ClientId and Secret and Username and Password

      What I don't fully understand is the use of ClientId and Secret vs Username and Password. The code ...

  10. LeetCode——Edit Distance

    Question Given two words word1 and word2, find the minimum number of steps required to convert word1 ...