1 了解面向对象

  • Python 就是一个面向对象的编程语言
  • 对象就是内存中用来存储指定数据的一块区间
  • 对象的结构:每个对象当中都保存了3种数据:
    1、id(标识):id是由我们的解析器生成的,在Cython中,id就是对象的内存地址。
    2、type(类型):用来标识当前对象所属的类型,类型就决定了对象有什么功能。
    3、value(值):就是对象中存储的具体数据。
  • 概念:
    (1)类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
    (2)方法:类中定义的函数。
    (3)类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
    (4)数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
    (5)方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
    (6)局部变量:定义在方法中的变量,只作用于当前实例的类。
    (7)实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
    (8)继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。
    例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
    (9)实例化:创建一个类的实例,类的具体对象。
    (10)对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

2 类

2.1 类的引入

  • Python中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类,派生类可以覆盖基类中的任何方法,方法中可以调用基类中的同名方法。
  • 对象可以包含任意数量和类型的数据。
  • 类(class):简单理解相当于一个图纸,在程序中我们需要根据类来创建对象
  • 学习的都是Python的内置对象,如int() str() list() tuple() set() dict()
  • 类是type类型的对象,定义类实际上就是定义了一个type类型对象
  • 可以通过类来创建一些自定义的对象
  • 使用class 关键字来定义类,语法:
class 类名([父类]):代码块

这里类名后面括号里的参数(即父类)可以省略,如果有父类传递过来,那就是继承

  • 类名一般采用驼峰命名法
  • 现在通过MyClass 创建的对象都是空对象
  • 可以向对象中添加变量,对象中添加变量我们称之为属性
    语法: 对象.属性名=属性值
  • 可以用isinstance()函数来检查一个对象是否是另一个类的实例,返回值是True或False
class MyClass():pass
print(id(MyClass),type(MyClass))    # 35759912 <class 'type'>
mc=MyClass()    # mc是通过类 MyClass来创建的,mc就是MyClass的实例
print(mc,type(mc))  # <__main__.MyClass object at 0x00000000028C2780> <class '__main__.MyClass'>
r= isinstance(mc,MyClass)
print(r)    # True
mc.name='hello'
print(mc.name)  # hello

2.2 类的定义

  • 类的定义:类和对象都是现实生活中的抽象
  • 实际上,所有的事物有两部分组成:
    1.数据(属性)
    2.行为(方法)
  • 在类中的代码块,我们可以定义变量和函数
  • 类对象创建后,类命名空间中所有的命名都是有效属性名。
  • 在类中定义的变量和函数将会成为所有实例的公共属性和公共方法,任何该类的实例都可以访问。
  • 方法调用和函数调用的区别:
    1.如果是函数调用,有几个形参,就传递几个实参;
    2.如果是方法调用,默认要指定一个形参,所以方法中至少要有一个形参

class Person():a=123b=456def speak(self):print('hahah')
# 创建Person的实例
p1=Person()
# 调用类的属性,语法:对象.属性名
print(p1.a,p1.b)  # 123 456
# 调用类的方法,语法:对象.方法名()
p1.speak()  #  hahah

2.3 属性和方法的查找流程

  • 当我们调用一个对象的属性时,解析器会先在当前的对象中寻找是否有该属性(方法):
    (1)如果有,则直接返回当前的对象的属性值(方法返回值);
    (2)如果没有,则去当前对象的类对象中去寻找,如果有则返回类对象的属性值(方法返回值),如果没有就报错。
class Text():c='haha'def spe(self):print('123')
p2=Text()
p2.c='wowo'
print(p2.c)     # 结果为 wowo,而不是 haha
  • 类对象和实例对象中都可以保存属性(方法),具体要保持到哪里,看实际需求:
    (1)如果这个属性(方法)是所以的实例共享的,则应该将其保存到类对象中;
    (2)如果这个属性(方法)是某个实例独有的,则应该保存到实例对象中,别的实例访问不到;
    (3)一般情况下,属性保存到实例对象中,而方法需要保存到类对象中。

2.4 方法的默认形参 self

  • self在定义时需要定义,但是在调用时会自动传入。
  • self的名字并不是规定死的,但是最好还是按照约定和规范用 self
  • self总是指调用时的类的实例。
  • 注意:
    (1)类方法必须包含参数 self, 且为第一个参数
    (2)在定义类的方法时,不能直接调用方法外的变量,这是和函数嵌套不同的地方。
  • 如果要调用,可以使用 self.属性名 的方式
class StrPrint():str='hello'def pri(self):print(self.str)
a=StrPrint()
b=StrPrint()
a.str='hey'
b.str='你好'
# 哪个实例调用,self就是哪个实例的对象
a.pri()     # 输出 hey
b.pri()     # 输出 你好
# self 代表的是类的实例,代表当前对象的地址
print(a.pri)    # 输出 <bound method StrPrint.pri of <__main__.StrPrint object at 0x00000000026D2668>>

2.5 特殊方法

  • 在类中可以定义一些特殊的方法,形如__mmm__,注意前后都是双下划线,比如初始化方法:init(self),该方法在类实例化时会自动调用。
  • 这些特殊方法不需要我们自己调用,创建实例时就已经调用,有多少个实例就会被调用多少次。
  • 类中的代码执行顺序(例如):先执行类里面的代码块,再执行__init__部分的代码块。
  • 当一个类创建了多个实例时,类里面的代码只执行一次,而特殊方法则会根据实例的个数执行多次。
class StrPrint():print('hello')def __init__(self):print('hahhah')
p1=StrPrint()
p2=StrPrint()
p3=StrPrint()

执行结果:

hello
hahhah
hahhah
hahhah
  • 类的基本结构:
class ClassName([父类]):公共属性1公共属性2……# 对象的初始化方法def __init__(self,...):代码块# 其他的方法def methodname(self,...)代码块……
  • 定义一个车的类
    属性:name、color
    方法:run()
class Car():name=''color=''def __init__(self,name,color):self.name=nameself.color=colordef run(self):print('The car is running.')
car=Car()

3 面向对象的三大特性

  • 面向对象的三大特性:
    1.封装:确保对象中数据的安全
    2.继承:保证对象的扩展性
    3.多态:一个对象可以以不同的形态去呈现

3.1 封装

3.1.1 封装的引入

  • 出现封装的原因:我们需要一种方式来增强数据的安全性
  • 要求:1、属性不能随意修改;2、属性不能改为任意的值
  • 封装是指隐藏对象中一些不希望被外部所访问到的属性或方法:
    1、将对象属性名修改为一个外部不知道的名字:
class Dog():def __init__(self,name):self.hidden_name=namedef speak(self):print('大家好,我是%s'%self.hidden_name)
d=Dog('大狼狗')
d.name='大柴狗'
d.speak()   # 输出结果为:大家好,我是大狼狗   说明类的属性值没有被修改

2、外部使用getter()和setter()方法访问到类的属性并修改:
getter()获取对象中指定的属性
setter()用来设置对象指定的属性

class Dog():def __init__(self,name):self.hidden_name=namedef speak(self):print('大家好,我是%s'%self.hidden_name)# get_name()用来获取类的name属性值def get_name(self):return self.hidden_name# set_name()用来修改类的name属性值def set_name(self,name):self.hidden_name=name
d=Dog('大狼狗')
print(d.get_name())     # 输出:大狼狗
d.set_name('二哈')
print(d.get_name())     # 输出:二哈
d.speak()       # 输出:大家好,我是二哈

3.1.2 封装的作用

  • 使用封装,确实增加了类的定义的复杂程度,但也确保了数据的安全:
    (1)隐藏属性名,是调用者无法随意修改类的属性。
    (2)增加getter()和setter()方法,控制属性是否是只读的。
    (3)使用setter()设置属性,可以验证数据的准确性。
    (4)使用getter()方法获取属性,使用setter()方法设置属性可以在读取属性和修改属性的同时做一些其他的处理。
class Dog():def __init__(self,name,age):self.hidden_name=nameself.hidden_age=agedef speak(self):print('大家好,我是%s'%self.hidden_name)# get_name()用来获取类的name属性值def get_name(self):return self.hidden_name# set_name()用来修改类的name属性值def set_name(self,name):self.hidden_name=namedef get_age(self):print('用户读取了属性...')return self.hidden_agedef set_age(self,age):print('用户修改了属性。。。')if age > 0:self.hidden_age= age
d=Dog('大狼狗',2)
d.get_age()
d.set_age(3)

3.1.3 基本属性、隐藏属性、私有属性

  • 其属性名不包含任何下划线的属性为基本属性。
  • 双下划线开头的属性,形如__***,是对象的隐藏属性,隐藏属性只能在类的内部访问,无法通过对象访问。
  • 其实隐藏属性只不过是Python自动为属性改了一个名字 --> _类名__属性名,例如 __name --> _Person__name,然而这种方式实际上依然可以在外部访问,所以这种方式我们一般不用。因此我们使用单个下划线_开头定义私有属性,一般情况下,使用_开头的属性都是私有属性,没有特殊情况下不要修改私有属性。
    示例1:
class Person():def __init__(self,name):# 定义隐藏属性self.__name=namedef get_name(self):return self.__namedef set_name(self,name):self.__name=name
p1=Person('张三')
# p1.__name  会报错 AttributeError: 'Person' object has no attribute '__name',隐藏属性只能在类的内部访问,无法通过对象访问。
print(p1._Person__name)   #  通过这种方式依然可以获取类的属性,输出结果为:张三

示例2:

class Person():def __init__(self,name):# 定义私有属性self._name=namedef get_name(self):return self._namedef set_name(self,name):self._name=name
p2=Person('李四')
# print(p2._Person_name)    # 访问不了,会报错AttributeError: 'Person' object has no attribute '_Person_name'
print(p2._name)   # 访问私有属性,输出结果为:李四,没有特殊情况下不要修改私有属性

3.1.4 类的装饰器

  • 类的装饰器:扩展方法的功能
  • property装饰器:
    (1)我们可以使用 @property装饰器来创建只读属性。
    (2)@property装饰器会将方法转换为相同名称的只读属性,可以与所定义的属性配合使用,这样可以防止属性被修改。
    (3)@property装饰器应用场景:当定义的方法内容比较庞大,且不需要传递参数,同时方法只需要一个返回值的时候。
class Person():def __init__(self,name):self._name=name# getter()方法@propertydef get_name(self):print('getter()方法执行了')return self._name# getter 和 setter 方法的定义:  @方法名.getter  和  @属性名.setter
p3=Person('王五')
# 调用Person类的get_name()方法,虽然是在调用方法,但加了@property装饰器之后,方法已经转换为属性,访问时方法名后面不需要加括号
print(p3.get_name)  # 输出结果为: getter()方法执行了   王五

3.2 继承

  • 继承:子类会继承父类的所有属性和方法,包括特殊方法。
  • Python同样支持类的继承,如果一种语言不支持继承,类就没有什么意义了。类提高了代码的复用性。
  • 在创建类的时候,如果省略了父类,则默认父类为object,object是所有类的父类。
  • 基类(BaseClassName)必须与派生类定义在一个作用域内。
  • super()函数可以获取当前类的父类,并且通过super()返回对象调用父类方法时,不需要传递self。

3.2.1 单继承

派生类(derivelclass)的定义语法如下:

class DerivelclassName(BaseClassName1):代码块

除了类,还可以用表达式,基类定义在另一个模块中时,这一点非常有用:

class DerivedClassName(modname.BaseClassName):
# 定义基类
class PersonInformation():# 定义基本属性name=''age=0# 以单下划线开头,定义私有属性,私有属性在类外部无法直接进行访问_weight =0# 定义初始化方法(构造方法)def __init__(self,name,age,weight):self.name= nameself.age=ageself._weight=weightdef print_infor(self):print('name:%s age:%d  weight:%d'%(self.name,self.age,self._weight))
# 单继承示例:
class PersonOne(PersonInformation):# 添加新的基础属性city=''def __init__(self,name,age,weight,city):调用父类的构造方法,PersonInformation.__init__(self,name,age,weight)  # 等价于super().__init__(name,age,weight)self.city=city# 重写父类的方法def print_infor(self):print('name:%s age:%d  weight:%d  city:%s'%(self.name,self.age,self._weight,self.city))
p1=PersonOne('李四',23,55,'hangzhou')
p1.print_infor()     # 输出结果为  name:李四 age:23  weight:55  city:hangzhou
issubclass(子类名,父类名)函数:检查一个类是不是另一个类的子类,如果是 则返回True,如果不是 则返回false
print(issubclass(PersonOne,PersonInformation))      # 输出:True
print(issubclass(PersonOne,object))      # 输出:True
print(issubclass(PersonInformation,object))      # 输出:True

3.2.2 多继承

  • Python同样有限的支持多继承形式。多继承的类定义形如:
class DerivedClassName(Base1,Base2,Base3,...):代码块
  • 注意:圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找父类中是否包含方法。
# 定义另一个基类
class JobInformation():job=''_salary=0def __init__(self,job,salary):self.job=jobself._salary=salarydef print_infor(self):print('job:%s  salary:%d'%(self.job,self._salary))
# 多重继承示例:
class PersonTwo(JobInformation,PersonInformation):def _init__(self,name,age,weight,job,salary):# 调用父类的构造方法PersonInformation.__init__(self,name,age,weight)JobInformation.__init__(self,job,salary)
p2=PersonTwo('teacher',6000)
p2.print_infor()  # 方法名同,默认调用的是在括号中排前地父类的方法,输出结果为: job:teacher  salary:6000
# 类名.__bases__  这个属性可以获取当前类的所有父类
print(PersonTwo.__bases__)      # 输出结果:  (<class '__main__.JobInformation'>, <class '__main__.PersonInformation'>)

3.2.3 方法重写

  • 如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法。
  • 如果在子类中有何父类重名的方法,则通过子类的实例去调用该方法时,会先调用子类的方法,这个特点我们称之为方法的重写(覆盖)。
  • 方法的查找顺序:先在子类找,没有找到则去继承的父类找,以此类催,直到找到object,如果依然没有找到则会报错。
# 定义父类
class Parent():def myMethod(self):print('调用父类方法')
# 定义子类
class Child(Parent):def myMethod(self):print('调用子类方法')
# 创建子类实例
c=Child()
# 子类调用重写方法
c.myMethod()    # 输出结果为: 调用子类方法

3.3 多态

  • 例如:len()函数,len()函数的参数可以是列表、字符串等等,其用法就是一种多态的表现。
  • len()函数之所以可以获取不同对象的长度,是因为对象中有一个特殊方法 len

4 属性和方法(总结)

4.1 实例属性和类属性

  • 实例属性:通过实例对象添加的属性属于实例属性
  • 实例属性只能通过实例对象来访问和修改,类对象无法访问修改
  • 类属性:直接在类中定义的属性是类属性.
  • 类属性可以通过类或类的实例访问到。但是类属性只能通过类对象来修改,无法通过实例对象修改。
class ClassName():# 定义类属性num=10
a=ClassName()
# 定义实例属性
a.str='haha'
a.num=20
print('类的num属性值:',ClassName.num)        # 输出结果:  类的num属性值: 10
print('实例的num属性值:',a.num)       # 实例的num属性值: 20
print('实例的str属性值:',a.str)       # 实例的str属性值: haha
ClassName.num=30
print('类的num属性值:',ClassName.num)        # 输出结果:  类的num属性值: 30
print('实例的num属性值:',a.num)       # 实例的num属性值: 20

4.2 实例方法和类方法

  • 实例方法:在类中定义,以self为第一个参数的方法都是实例方法。
  • 实例方法在调用时,Python会将调用对象以self传入。
  • 实例方法可以通过类实例和类去调用:
    (1)当通过实例调用时,会自动将当前调用对象作为self传入。
    (2)当通过类调用时,不会自动传递self,我们必须手动传递当前实例对象。
  • 类方法:在类的内容以@classmethod 来修饰的方法属于类方法。
  • 类方法第一个参数是cls,也会自动被传递。cls就是当前的类对象。
  • 类方法和实例方法的区别:实例方法的第一个参数是self,类方法的第一个参数是cls。
  • 类方法可以通过类去调用,也可以通过实例调用。
class ClassName():# 定义类属性num=10# 定义实例方法,第一个参数为self,会自动传入def test(self):print('这是实例方法。')# 定义类方法@classmethoddef test1(cls):print('这是类方法。')# 类方法和实例方法调用属性的方式差不多print(cls.num)
a=ClassName()
# a.test()  等价于  ClassName.test(a)
a.test()    # 输出结果为:这是实例方法。
ClassName.test(a)   # 括号里的a是当前的实例对象,输出结果为:这是实例方法。
# a.test1() 等价于  ClassName.test1()
a.test1()       # 输出结果为:这是类方法。
ClassName.test1()       # 输出结果为:这是类方法。

4.3 静态方法

  • 静态方法:在类中用@staticmethod来修饰的方法属于静态方法。
  • 静态方法不需要指定任何的默认参数,并且静态方法可以通过类和实例调用。
  • 静态方法,基本上是一个和当前类无关的方法,它只是一个保存到当前类中的函数。
  • 静态方法一般都是些工具方法,和当前类无关。
class A():@staticmethod# 静态方法需要指定任何的默认参数,包括实例方法的self和类方法的clsdef statmeth():print('这是静态方法。')
a=A()
# 以下两种调用方式的输出结果均为:  这是静态方法。
a.statmeth()
A.statmeth()

4.4 类的私有方法和专有方法

  • __private_method:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用。
    调用方式:self.__private_methods
    示例:
class Per():def __init__(self,name,age):self.name=name  # 公共属性self.__age=age   # 私有属性def public(self):      # 公共方法print('这是公共方法。')def __private(self):print('这是私有方法。')
p=Per('张三',23)
p.public()      # 正常输出
p.__private() # 会报错 AttributeError: 'Per' object has no attribute '__private'
  • 类的专有方法:
    init : 构造函数,在生成对象时调用
    del : 析构函数,释放对象时使用
    repr : 打印,转换
    setitem : 按照索引赋值
    getitem: 按照索引获取值
    len: 获得长度
    cmp: 比较运算
    call: 函数调用
    add: 加运算
    sub: 减运算
    mul: 乘运算
    truediv: 除运算
    mod: 求余运算
    pow: 乘方

4.5 运算符重载

Python同样支持运算符重载,我们可以对类的专有方法进行重载,实例如下:

class Vector:def __init__(self, a, b):self.a = aself.b = bdef __str__(self):return 'Vector (%d, %d)' % (self.a, self.b)def __add__(self, other):return Vector(self.a + other.a, self.b + other.b)
v1 = Vector(2, 10)
v2 = Vector(5, -2)
# 相加过程:  Vertor(  2+5 , 10+(-2) )
print(v1 + v2)      # 输出结果为:Vector (7, 8)

Python学习-面向对象(类)相关推荐

  1. Python学习 - 面向对象之多态

    Python学习 - 语法入门:https://blog.csdn.net/wanzijy/article/details/125287855 Python学习 - 数据类型:https://blog ...

  2. Python之面向对象类和对象

    Python之面向对象类和对象 定义一个类:class 定义类的语法: class Test(object):"""类里定义一类事物共同的技能.可以是变量,也可是函数.& ...

  3. python学习------面向对象的程序设计

    一 面向对象的程序设计的由来 1940年以前:面向机器最早的程序设计都是采用机器语言来编写的,直接使用二进制码来表示机器能够识别和执行的指令和数 据.简单来说,就是直接编写 0 和 1 的序列来代表程 ...

  4. python学习面向对象_Python小白必学的面向对象

    我们已经知道在Python中"一切皆对象",每个对象都有特定的类型,现在让我们来尝试创建自己的类型--这需要使用class关键字来定义新的"类"(Class), ...

  5. Python学习笔记④——类、面向对象的三大特征 [封装+继承+多态]

    ✅ Blogger Learns Python is for learning the "Deep Learning". 文章目录 一.面向对象编程的简介 二.类与对象 -- 基础 ...

  6. Python学习---面向对象的学习[深入]

    类的深入学习    a. Python中一切事物都是对象     b. class Foo:             pass                obj = Foo()         # ...

  7. python学习面向对象Day11(P116~~126)

    b站达内python课学习笔记 P116 Python面向对象–3.1 课程回顾 一.day10复习 """day10 复习类和对象类:抽象 向量 class Vecto ...

  8. python学习面向对象Day09(P96~~106)

    b站达内python课学习笔记 P96~97 Python面向对象-1.1&1.2 课程内容回顾01&02 一.Day08复习 """day08 复习函数 ...

  9. python游戏房间_使用 Python 学习面向对象的编程 | Linux 中国

    使用 Python 类使你的代码变得更加模块化.-- Seth Kenlon 在我上一篇文章中,我解释了如何通过使用函数.创建模块或者两者一起来使 Python 代码更加模块化.函数对于避免重复多次使 ...

最新文章

  1. XamarinAndroid组件教程RecylerView适配器设置动画
  2. 客服机器人源码_快速搭建对话机器人,就用这一招!
  3. [libjingle学习笔记]编译注意事项
  4. 使用Disentangling形式的损失函数回归2D和3D目标框
  5. 运行Java应用必须通过main()方法吗?
  6. dom4j解析xml获取所有的子节点并放入map中
  7. asp.net调用前台js调用后台代码分享
  8. 【jquery】fancybox 是一款优秀的 jquery 弹出层展示插件
  9. 同花顺开放接口api_接口大师,即刻构建你的OpenAPI+开放平台
  10. android-常用部件
  11. php对字符数组进行排序,php数组去重_php对数组中字符串去重并排序例子
  12. SPSS多元线性回归及逐步回归学习笔记
  13. 【修真院“正直”系列之三】【修真神界】【修行卷】【第一章】修真院入场券...
  14. java socket连接超时_Java中Socket设置连接超时的代码
  15. JDK 动态代理之源码解析
  16. 镭速介绍关于高速数据传输!
  17. 神经网络模型画图工具,神经网络模型图怎么画
  18. wps两列数据分别作为xy轴_一图胜千字:科研论文插图/数据处理和图表制作学习会(2019年12月2729日 上海)...
  19. 深度学习之格式转换笔记(三):keras(.hdf5)模型转TensorFlow(.pb) 转TensorRT(.uff)格式
  20. php开发多用户商城用什么技术,php多用户商城系统有什么特点?

热门文章

  1. Python CSV Reader/Writer
  2. 《2040大预言:高科技引擎与社会新秩序》——2.4 在芯片上建造大金字塔
  3. 第四节 单因素、多因素方差分析
  4. 模板式表单与响应式表单关系
  5. SEAL全同态加密开源库(十二) CKKS-源码浅析
  6. android ----- goldfish内核编译
  7. 一周新闻纵览:工信部组织召开综合整治骚扰电话专项行动;智能锁百万指纹泄密;4G不会降速5G网速会更快
  8. List集合遍历for循环优化
  9. 【扫盲贴】常见电影片源格式
  10. 流体力学基本流动复势推导