Adminxe's Blog | 低调求发展 - 潜心习安全 ,技术永无止境 | 谢谢您对本站的支持,有什么问题或者建议请及时联系:点击这里给我发消息

0x013.Python学习-面向对象

Python Adminxe 937℃ 0评论

Python3 面向对象

话不多说,先来一堆理论知识,用到就ctrl+F

Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。本章节我们将详细介绍Python的面向对象编程。

如果你以前没有接触过面向对象的编程语言,那你可能需要先了解一些面向对象语言的一些基本特征,在头脑里头形成一个基本的面向对象的概念,这样有助于你更容易的学习Python的面向对象编程。

接下来我们先来简单的了解下面向对象的一些基本特征。


面向对象技术简介

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
  • 方法:类中定义的函数。
  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
  • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
  • 局部变量:定义在方法中的变量,只作用于当前实例的类。
  • 实例变量:在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟”是一个(is-a)”关系(例图,Dog是一个Animal)。
  • 实例化:创建一个类的实例,类的具体对象。
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

和其它编程语言相比,Python 在尽可能不增加新的语法和语义的情况下加入了类机制。

Python中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类,派生类可以覆盖基类中的任何方法,方法中可以调用基类中的同名方法。

对象可以包含任意数量和类型的数据。

类的专有方法:

  • __init__ : 构造函数,在生成对象时调用
  • __del__ : 析构函数,释放对象时使用
  • __repr__ : 打印,转换
  • __setitem__ : 按照索引赋值
  • __getitem__: 按照索引获取值
  • __len__: 获得长度
  • __cmp__: 比较运算
  • __call__: 函数调用
  • __add__: 加运算
  • __sub__: 减运算
  • __mul__: 乘运算
  • __truediv__: 除运算
  • __mod__: 求余运算
  • __pow__: 乘方
针对 __str__ 方法给出一个比较直观的例子:
class people:
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def __str__(self):
        return '这个人的名字是%s,已经有%d岁了!'%(self.name,self.age)

a=people('孙悟空',999)
print(a)
输出:
这个人的名字是孙悟空,已经有999岁了!
如果没有重载函数的话输出的就是一串看不懂的字符串:
<__main__.people object at 0x00000272A730D278>
最新的 Python3.7 中(2018.07.13),对类的构造函数进行了精简。
3.7 版本:
from dataclasses import dataclass
@dataclass
class A:
  x:int
  y:int
  def add(self):
    return self.x + self.y
相当于以前的:
class A:
  def __init__(self,x,y):
    self.x = x
    self.y = y
  def add(self):
    return self.x + self.y
静态方法: 用 @staticmethod 装饰的不带 self 参数的方法叫做静态方法,类的静态方法可以没有参数,可以直接使用类名调用。
普通方法: 默认有个self参数,且只能被对象调用。
类方法: 默认有个 cls 参数,可以被类和对象调用,需要加上 @classmethod 装饰器。
class Classname:
    @staticmethod
    def fun():
        print('静态方法')

    @classmethod
    def a(cls):
        print('类方法')

    # 普通方法
    def b(self):
        print('普通方法')



Classname.fun()
Classname.a()

C = Classname()
C.fun()
C.a()
C.b()
selfeasy
   selfeasy



反向运算符重载:
__radd__: 加运算
__rsub__: 减运算
__rmul__: 乘运算
__rdiv__: 除运算
__rmod__: 求余运算
__rpow__: 乘方
复合重载运算符:
__iadd__: 加运算
__isub__: 减运算
__imul__: 乘运算
__idiv__: 除运算
__imod__: 求余运算
__ipow__: 乘方
运算符重载的时候:
#!/usr/bin/python3

class Vector:
    def __init__(self, a, b):
        self.a = a
        self.b = b
    def __str__(self):
        return 'Vector (%d, %d)' % (self.a, self.b)

    def __repr__(self):
        return 'Vector (%d, %d)' % (self.a, self.b)

    def __add__(self,other):
        if other.__class__ is Vector:
            return Vector(self.a + other.a, self.b + other.b)
        elif other.__class__ is int:
            return Vector(self.a+other,self.b)

    def __radd__(self,other):
        """反向算术运算符的重载
        __add__运算符重载可以保证V+int的情况下不会报错,但是反过来int+V就会报错,通过反向运算符重载可以解决此问题
        """

        if other.__class__ is int or other.__class__ is float:
            return Vector(self.a+other,self.b)
        else:
            raise ValueError("值错误")

    def __iadd__(self,other):
        """复合赋值算数运算符的重载
        主要用于列表,例如L1+=L2,默认情况下调用__add__,会生成一个新的列表,
        当数据过大的时候会影响效率,而此函数可以重载+=,使L2直接增加到L1后面
        """

        if other.__class__ is Vector:
            return Vector(self.a + other.a, self.b + other.b)
        elif other.__class__ is int:
            return Vector(self.a+other,self.b)
v1 = Vector(2,10)
v2 = Vector(5,-2)
print (v1 + v2)
print (v1+5)
print (6+v2)
Python3 类方法总结
 普通方法:对象访问
 私有方法:两个下划线开头,只能在类内部访问
 静态方法:类和对象访问,不能和其他方法重名,不然会相互覆盖,后面定义的会覆盖前面的
 类方法:类和对象访问,不能和其他方法重名,不然会相互覆盖,后面定义的会覆盖前面的
 多继承情况下:从左到右查找方法,找到为止,不然就抛出异常
class People:

    # 定义基本属性
    name=''
    age=0
    # 定义私有属性外部无法直接访问
    __weight=0
    def __init__(self,n,a,w):
        self.name = n
        self.age = a
        self.__weight = w
    def speak(self):
        print("%s say : i am %d."%(self.name,self.age))
p = People('Python',10,20)
p.speak()
# __weight无法直接访问
print(p.name,'--',p.age)#,'--',p.__weight)
继承
单继承:
class Student(People):
    grade=''
    def __init__(self,n,a,w,g):
        People.__init__(self,n,a,w)
        self.grade = g

    # 覆写父类方法
    def speak():
        print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))

class Speak():
    topic=''
    name=''
    def __init__(self,n,t):
        self.name = n
        self.topic = t
    # 普通方法,对象调用
    def speak(self):
        print("我叫 %s,我是一个演说家,我演讲的主题是 %s"%(self.name,self.topic))

    # 私有方法,self调用
    def __song(self):
        print('唱一首歌自己听',self);

    # 静态方法,对象和类调用,不能和其他方法重名,不然会相互覆盖,后面定义的会覆盖前面的
    @staticmethod
    def song():
        print('唱一首歌给类听:静态方法');

    # 普通方法,对象调用
    def song(self):
        print('唱一首歌给你们听',self);
        
    # 类方法,对象和类调用,不能和其他方法重名,不然会相互覆盖,后面定义的会覆盖前面的
    @classmethod
    def song(self):
        print('唱一首歌给类听:类方法',self)
多继承:
class Sample(Speak,Student):
    a = ''
    def __init__(self,n,a,w,g,t):
        Student.__init__(self,n,a,w,g)
        Speak.__init__(self,n,t)
test = Sample('Song',24,56,7,'Python')
test.speak()
test.song()
Sample.song()
Sample.song()
test.song()

# test.__song() 无法访问私有方法
类的二元方法运算符重载介绍的并不全面,文中介绍的全是正向方法,其实还有反向方法,就地方法。下面补充一些。
当解释器碰到 a+b 时,会做以下事情:
从 a 类中找 __add__ 若返回值不是 NotImplemented, 则调用 a.__add__(b)。
若 a 类中没有 __add__ 方法,则检查 b 有没有 __radd__ 。如果如果有,则调用 b.__radd__(a),若没有,则返回 NotImplemented。
接上条,若 b 也没有 __radd__ 方法,则抛出 TypeError,在错误消息中知名操作数类型不支持。
比如:向量类 <Myvector> 应当有向量与整数的乘法:
>>>a = Myvector([1,2,3])
>>>print(a.value)
[1,2,3]
>>>b=3
>>>c = a*b   #此时调用Myvector.__mul__()
>>>print(c.value)
[3,6,9]
>>> d=b*a  #这句会出错。
期望得到 b*a 也返回一个向量,b*a 应该等于 a*b。此时就需要在 Myvector 类中定义一个__rmul__方法。
def __rmul__(self, other):
    if isinstance(other, int):
        return Myvector([a*other for a in self.m])
每个运算符都有正向方法重载,反向方法重载。有一些有就地方法(即不返回新的对象,而是修改原本对象)。
class Ren:
    name ="zhangsan"
    age =20
    sex ='man'
    def run(self):
        print 'basketball'
class Ren:
    name ="zhangsan"      #变量
    age =20
    sex ='man'
    def run(self,x):        #函数
        print 'basketball'
        print x
zhang =Ren()                  #创建对象的过程叫实例化,zhang为对象
print zhang.name
zhang.run('xxxxxxxxxx')       #对象的方法
zhang.age =40                 #设置属性
print zhang.age
zhang.job ='it'               #添加属性
print zhang.job
class Ren:
    name ="zhangsan"      #变量
    age =20
    sex ='man'
    __tt ='zs'
    def run(self,x):        #函数
        print 'basketball'
        print x
        print self.__tt       #内部调用私有属性
zhang =Ren()                  
print zhang.name
zhang.run('xxxxxxxxxx')     
zhang.age =40                 
print zhang.age
zhang.job ='it'               
print zhang.job
print zhang._Ren__tt          #调用内部私有类
#! /usr/bin/python
# ! -*- coding: UTF-8 -*-

class Ren:
    name = "zhangsan"  # 变量
    age = 20
    sex = 'man'
    __tt = 'zs'

    def run(self, x):  # 函数
        print 'basketball'
        print x
        print self.__tt  # 内部调用私有属性

    def __kk(self, x):  # 函数
        print 'running'
        print self.__tt  # 内部调用私有属性

    @classmethod #函数修饰符 或者声明称静态函数@staticmethod,静态函数就不需要加参数了,即无须self
    def hel(self): #@classmethod 相当于把run函数加载到classmethod里面运行,即run =@classmethod(run)
        print "hel man!"  # 使用私有方法进行调用测试


zhang = Ren()  # 创建对象的过程叫实例化,zhang为对象
print zhang.name
zhang.run('xxxxxxxxxx')  # 对象的方法
zhang.age = 40  # 设置属性
print zhang.age
zhang.job = 'it'  # 添加属性
print zhang.job
print zhang._Ren__tt  # 调用内部私有类
zhang._Ren__kk("私有方法调用")
zhang.hel()  # 公有方法
Ren.hel()    #私有方法调用

class Ren:

    class Badren: #内部类
        name =’huairen’
        @classmethod
        def badshi(self):
            print ‘papapa’
huairen =Ren.Badren #对内部类进行实例化
print huairen.name #对内部类里面的变量进行调用
huairen.badshi() #

class Ren:
    def __init__(self,x):
        print ‘构造函数:当实例化对象的时候,构造函数就会被默认执行,即实例化的时候,先调用构造函数’
        print ‘xxxxxxxxxx:’,x #实例化对象的时候,对其进行传参,通过构造函数实现
zhang =Ren(“zhangsan”)#实例化对象的时候,对其进行传参,通过构造函数实现

#f =open(‘c:\1.txt’,’r’) #以只读的形式,实例化函数f ,文件操作

class Ren:
    name = "zhangsan"  # 变量
    age = 20
    sex = 'man'
    __tt = 'zs'
    def __del__(self): #析构函数
        f = open('c:\1.txt', 'r')
        f.read()
        f.close()
class Parent:
    name ='lisi'
    parentAttr = 100
    def fulei(self):
        print '这是父类中的方法'
    def __init__(self):
        print "这是父类中构造函数,私有化方法"
class Child(Parent):#子类调用父类
    name ='lisi'
    def childMethod(self):
        print '这是子类中的方法'
child =Child()#实例化子类
child.fulei()#子类调用父类中的方法
child.childMethod()#调用子类中本身的方法
print child.name #(子类父类中同有的变量),子类调用时,优先权会高于父类,输出lisi 

lession13总代码:

#! /usr/bin/python
# ! -*- coding: UTF-8 -*-
#【继承】
#父类有的,继承后子类可以直接调用
#父类子类都有同一个重名函数,优先子类调用自己的
#父类只能调用自己的函数
class Ren:
    name = "zhangsan"  # 变量
    age = 20
    sex = 'man'
    __tt = 'zs'
    def __del__(self): #析构函数
        f = open('c:\1.txt', 'r')
        f.read()
        f.close()
'''
    def __init__(self,x):
        print '构造函数:当实例化对象的时候,构造函数就会被默认执行,即实例化的时候,先调用构造函数'
        print 'xxxxxxxxxx:',x #实例化对象的时候,对其进行传参,通过构造函数实现
zhang =Ren("zhangsan")#实例化对象的时候,对其进行传参,通过构造函数实现

#f =open('c:\1.txt','r') #以只读的形式,实例化函数f ,文件操作


     def run(self, x):  # 函数
        print 'basketball'
        print x
        print self.__tt  # 内部调用私有属性

    def __kk(self, x):  # 函数
        print 'running'
        print self.__tt  # 内部调用私有属性

    @classmethod #函数修饰符 或者声明称静态函数@staticmethod,静态函数就不需要加参数了,即无须self
    def hel(self): #@classmethod 相当于把run函数加载到classmethod里面运行,即run =@classmethod(run)
        print "hel man!"  # 使用私有方法进行调用测试

    class Badren: #内部类
        name ='huairen'
        @classmethod
        def badshi(self):
            print 'papapa'


zhang = Ren()  # 创建对象的过程叫实例化,zhang为对象
print zhang.name
zhang.run('xxxxxxxxxx')  # 对象的方法
zhang.age = 40  # 设置属性
print zhang.age
zhang.job = 'it'  # 添加属性
print zhang.job
print zhang._Ren__tt  # 调用内部私有类
zhang._Ren__kk("私有方法调用")
zhang.hel()  # 公有方法
Ren.hel()    #私有方法调用
huairen =Ren.Badren #对内部类进行实例化 或者是huairen=zhang.Badren
print huairen.name #对内部类里面的变量进行调用
huairen.badshi() #对内部类的方法进行调用
'''
class Parent:
    name ='lisi'
    parentAttr = 100
    def fulei(self):
        print '这是父类中的方法'
    def __init__(self):
        print "这是父类中构造函数,私有化方法"
class Child(Parent):#子类调用父类
    name ='lisi'
    def childMethod(self):
        print '这是子类中的方法'
child =Child()#实例化子类
child.fulei()#子类调用父类中的方法
child.childMethod()#调用子类中本身的方法
print child.name #(子类父类中同有的变量),子类调用时,优先权会高于父类,输出lisi
class sson(Child):
    print '我是孙子类,测试能否继承爷爷类'
sson =sson()#并且实例化对象时,会再次加载构造函数
sson.fulei()# 结果测试可以继承

转载请注明:Adminxe's Blog » 0x013.Python学习-面向对象

喜欢 (4)or分享 (0)
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址