【python语法】面向过程与面向对象

面向过程与面向对象

面向过程:根据流程从上往下执行;面向对象:通过新建的对象(类)实现对应的功能

对象由属性和行为构成

使用类的优点:数据可重用、数据的权限设计

动态绑定

动态绑定指的是在类外部给类增加对应的属性或者方法;在下面这个案例中,给类增加方法使用的是lambda函数

class sis:
    pass          # 定义一个空对象
lixin_sis = sis()
print(type(lixin_sis))      # 查看对象的属性<class sis>
# 动态绑定空对象的属性和行为
lixin_sis.name = '芙蓉姐姐'
# 使用匿名函数绑定行为
lixin_sis.kiss = lambda name : print(name,'kiss',lixin_sis.name)
print(lixin_sis.name)
lixin_sis.kiss('李欣')

在使用 python 的匿名函数 lambda 的时候,不能使用 self 指向对应类本身

重载运算符

重载运算符是在类中(对象中)对既定的运算符进行重新解释,比如我们想实现两个复数相加的功能

class complex:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def show(self, name):
        print('%s 的值为:' % name ,self.x, '+', self.y, 'i')

    # 重载:针对本类型,对 + 进行重新解释
    def __add__(self, other):
        # 使用匿名函数,用来接收并返回重载运算符的结果
        return complex(self.x + other.x, self.y + other.y)


c1 = complex(4, 5)
c2 = complex(1, 2)
c1.show('c1')
c2.show('c2')
print(type(c1))    # 重载运算符,只对本类型器作用,所以在c1 c2 和 c3 的类型都是:<class:complex>
print(type(c2))
c3 = c1 + c2 
# 等价于:c3 = c1.__add__(c2)
c3.show('c3')
print(type(c3))

重载运算符对 加法做了重新的解释,但是解释的作用仅仅局限于 complex 类中||

重载运算符的拓展类型

重载的拓展类型:比如我们需要针对对象中相同的运算符,设置不同的解释方法 时;可以采用重载的拓展,我们修改上述代码,让其实现复数与复数,复数与整数类型的运算

class complex:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def show(self, name):
        print('%s 的值为:' % name, self.x, '+', self.y, 'i')

    # 重载:针对本类型,对 + 进行重新解释
    def __add__(self, other):
        if type(other) == type(self):   # 重载 complex + complex ,判断类型
            return complex(self.x + other.x, self.y + other.y)
        elif type(other) == type(10):   # 重载 complex + int ,判断类型
            return complex(self.x + other, self.y + other)


c1 = complex(4, 5)
c2 = complex(1, 2)
c3 = c1 + 10          # 进入 complex + int 类型语句
c3.show('c3')
c4 = c3 + c1          # 进入 complex + complex 类型语句
c4.show('c4')

通过 类型判断,根据不同的 other参数类型判断__add__()方法的返回,(两种方法的解释方式不同)从而实现了在一个重载方法内实现两种运算法则的共存

类的浅拷贝与深拷贝

对象的浅拷贝

对象的赋值是浅拷贝:即两个对象同指向一个内存空间;修改之前的 complex类的代码,

class complex:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def show(self, name):
        print('%s 的值是:' % name, self.x, '+', self.y, 'i')

c1 = complex(4,5)
c2 = c1
c1.show('c1')
c2.show('c2')
# 在这里可以发现,两个变量同时指向一个内存空间
print(id(c1),id(c2))
print(c1,c2)
c1.x = 100
c1.show('c1')
c2.show('c2')

可以发现两个变量同时指向一个内存空间(内存空间和 id 号相同),修改 c1的值,变量 c2 的值也会发生改变

对象的深拷贝

可以通过调用类,进行复制变量的方法进行对象的深拷贝(不是通过 = 赋值);我们的上述浅拷贝代码的基础上,通过深拷贝的方法复制一个变量

# 进行类(对象)的深拷贝
c3 = complex(c1.x,c1.y)
print(c3,id(c3))
c1.x = 50
c1.show('c1')
c3.show('c3')

深拷贝复制的变量c3不会和原变量c1共享同一块内存空间,会在内存中开辟一块新的空间并复制变量c1的值。我们打印对象的id号发现不一样,打印对象发现内存空间的地址不同,修改c1不会对c3造成任何影响

**总结:**类的浅拷贝(节省内存空间)类的深拷贝(保证数据的相对隔离安全;消耗内存较大)

函数的副本机制

这个案例展现了函数接收参数的工作原理

def changenum(num):
    print('changenum',id(num))
    num = 1000
    print('changenum',id(num))

num = 50
changenum(num)
print(num)
print(id(num))

案例输出的结果为

changenum 140714334297280
changenum 2223319561264
50
140714334297280

列表作为参数的副本机制:

相当于在函数内新构建了一个变量,以上述案例为例;函数在接收到参数之后,在函数内部新建一个变量num 新建的变量与原函数的变量所占用的地址空间不一致;函数内部变量的变化不会对外部产生任何影响。也就是说:在函数开始的时候;只是拷贝了参数的地址,函数内修改变量的值,是新开辟了一个内存空间,不会对函数外的参数构成影响。

**针对列表的副本机制:**把列表当作参数;不会改变列表本来的地址,但是可以改变列表元素的内容:

def changelist(mylist):
    print('beforechange',id(mylist))     # 复制参数地址,这里打印的地址与函数外参数列表的地址相同
    mylist[1] = 20000
    print('changelist',mylist)           # 不可以修改参数列表的地址,打死你hi可以修改参数列表的内容(因为内容存放的位置是地址变量)
    mylist = {1,2,3,4,5,6}               # 改变类型,尝试修改列表地址|函数会新开辟一个内存空间,存放变量
    print('finally change',id(mylist),mylist)

mylist = [1, 2, 3, 4, 5]
print(id(mylist), mylist)
changelist(mylist)
print(id(mylist), mylist)

这个案例的输出结果:

1885836415680 [1, 2, 3, 4, 5]
beforechange 1885836415680
changelist [1, 20000, 3, 4, 5]
finally change 1885836853984 {1, 2, 3, 4, 5, 6}         # 注意在这里改变了列表参数类型,新开辟了一块内存空间
1885836415680 [1, 20000, 3, 4, 5]

对象作为参数的副本机制:

将对象作为参数传入函数的时候,函数会复制参数的地址,函数可以改变参数的属性内容但是函数不能改变参数的存储地址。

class data:
    num = 100
    def show(self):
        print(self.num)

def change(datas):
    print('change',id(datas))
    datas.num = 19999            # 在这里改变了变量值,但是没有改变变量的内存空间
    print('after change',id(datas))

d1 = data()
d1.show()
change(d1)      # 将对象作为参数传入函数中;
d1.show()

副本机制:总结

函数的副本机制:函数的参数通常使用:浅拷贝的方法,即直接指向参数的地址;

不能从函数的内部修改:数字、字符串 的值:因为数字,字符串是一个固定的存储空间;

不能从函数内部修改:列表、对象所在的内存地址;但是可以修改原来数据包含的内容(也就是这两个数据集合的地址变量的内容)

私有变量

python 是一门解释型语言;比那辆存在解释为:引用;变量不存在解释为:动态绑定

私有变量不允许外部直接访问(一般会通过使用类内的方法访问)

私有变量的写法:__变量名 ; (在变量名前插入两个下划线)

class money:
    def __init__(self):
        self.__money = 100000
    def show(self,name):
        print('%s ,的月收入:'%name,self.__money)


ls = money()
# ls.__money = 999        # 这里属于动态绑定:因为无法访问内部的变量,只能绑定一个新的外部属性
print(ls.__money)         # 打印的是外部属性的值;如果不绑定外部属性,就会报:AttributeError(没有属性)的错误
ls.show('ls')             # 通过类内的函数进行访问;这里的访问结果是类中定义的 100000
私有变量的意义

私有变量的意义是给对应的比那辆设置访问权限;不是简单的通过外部就可以直接访问这个私有变量

案例:

class money:
    def __init__(self):
        self.__money = 100000

    # 这是一个存钱的方法
    def drop(self, num):
        self.__money += num
        print(self.__money)

    # 这是一个取钱的方法
    def deposit(self, passwd, num):
        if passwd == "123456":
            self.__money -= num
            print(self.__money)
        else:
            print("密码错误")

    # 这是一个查询存款的方法
    def check(self, passwd):
        if passwd == "123456":
            print(self.__money)
        else:
            print("密码错误")

xiaoming = money()
xiaoming.drop(100000)
xiaoming.deposit("1234",2000)
xiaoming.deposit("123456",10000)
xiaoming.check("123456")
# print(xiaoming.__money)            # 无法通过外部直接访问私有变量

在这个案例中,我们只可以通过调用对应类中函数的方法访问私有变量,无法从外部直接访问,从外部修改__money 的值会解释为动态绑定一个新的属性,不会修改私有变量本身的值

私有方法

私有方法:指的是不可以在外部直接访问的方法;**写法:__函数名(参数)😗*作用:进行函数(方法)隔离,给函数设置权限:

class money:
    def __init__(self):
        self.money = 100000
	# 不可以外部访问
    def __setmoney(self, num):
        self.money = num
        return self.money
	# 不可以外部访问
    def __getmoney(self):
        return self.money
	# 不可以外部访问
    def __checkpass(self, passwd):
        if passwd == '123456':
            return True
        else:
            return False
    # 可以外部访问(查询账户)
    def checkAccount(self, passwd):
        if self.__checkpass(passwd):
            return self.__getmoney()
        else:
            return None
	# 可以外部访问(修改账户)
    def setAccout(self, passwd, num):
        if self.__checkpass(passwd):
            return self.__setmoney(num)
        else:
            return None

xiaoming = money()
print(dir(xiaoming))
print(xiaoming.checkAccount('123456'))
print(xiaoming.setAccout('123456',700000))

在这个案例中,我们打印 dir(xiaoming)查看这个对象的所有函数就可以发现如下结果

 ['__class__', '__delattr__', '__dict__', '__dir__', ...'_money__checkpass','_money__getmoney','_money__setmoney', 'checkAccount', 'money', 'setAccout']

其中_money__getmoney_money__setmoney'_money__checkpass'表示无法直接访问;在这个案例中,查询账户和修改账户的方法可以通过外部访问,调用:_money__checkpass 进行身份验证,如果返回值是true 则通过函数内部访问对应的私有方法;如果返回值是false 直接返回None

私有方法的意义:进行权限设计、加强数据隔离

私有变量、私有方法的本质

python 的私有变量和私有方法,是在函数外部给对应的变量或者方法前加上一个_类名 、哦我们可以对上述代码及西宁修改从而访问python的私有变量和私有方法:

# 访问私有方法|在__getmoney() 方法之前加上_money 的类名
print(xiaoming._money__getmoney())  
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值