python 内置函数和特殊方法关系_Python面向对象相关函数内置方法与反射

除了之前写的那些关于Python面向对象编程的基础知识外,还需要掌握几个在Python中与面向对象相关的内置函数及非常重要的只是反射。

在Python中与面向对象相关的常用内置函数有9个,见下图。

0x00 定义特殊方法的装饰器

property

@property是一个将用户计算的东西伪装成为一个属性。

from math import pi

class Circle():

def __init__(self,r):

self.r = r

@property

def area(self):

return pi*self.r**2

c = Circle(2)

print(c.area) #12.566370614359172

在外部看来,area就成为了对象c的一个属性了!!其实不是,只是“伪装”成了属性了,毕竟在起名方法的时候area的名字就听着就像个属性名称,而不是get_area()。这样在外部就可以和调用动态属性一样的就取到结果了!

为什么不直接在定义动态属性的时候直接定义一个self.area = pi*self.r**2呢?这样的缺点是,当你一单生成一个对象,不管你是否能用到这个对象的area属性,他都会在内存中生成一个area属性,因而浪费了系统资源,所以才有property这个装饰器函数!

当我们尝试去给c.area去赋值的时候,Python就会报错了!!!这里你就需要用到@xxx.setter了。

from math import pi

class Circle():

def __init__(self,r):

self.r = r

@property

def area(self):

return pi * self.r**2

@area.setter

def area(self,new_r):

self.r = new_r

c = Circle(2)

print(c.area) #12.566370614359172

c.area = 3

print(c.area) #28.274333882308138

若没有@xxx.setter方法当执行c.area = 3的时候,那么程序将报错!这里加入了装饰器,则可以给c.area赋值。这里注意的是,赋值是给area()中需要的变量赋值,这里只能有一个参数,如果定义self.area = new_r的话,那么会存在无限递归,这将会报错。

那么如何删除c.area的属性呢?也是通过@xxx.deleter来删除,几乎用不到~来段代码。

from math import pi

class Circle():

def __init__(self,r):

self.__r = r

self.r = r

@property

def area(self):

return pi * self.__r**2

@area.setter

def area(self,new_r):

self.__r = new_r

@area.deleter

def area(self):

del self.__r

c = Circle(2)

print(c.area) #12.566370614359172

c.area = 3

print(c.area) #28.274333882308138

del c.area

print(c.area) #AttributeError

这里要删除area属性的话,必须在外部调用del c.area之后,等于调用了被@area.deleter装饰的函数,这里一定要记住内部还要写del呢!!值得注意的一点,如果这个属性是property的话,如果需要删除(@xxx.deleter)的话,那么在property中需要使用的参数进行封装即为上面的self.__r。

classmethod

类方法是直接由类自己调用,方法可以传入多个参数,但是第一个必须是cls,即类本身。Python中用类方法比较少,不过一般在操作静态属性的时候,最好使用类方法。

class Goods():

__discount = 1

def __init__(self,name,price):

self.name = name

self.__price = price

def get_price(self):

return self.__price * Goods.__discount

@classmethod

def change_discount(cls,new_discount):

Goods.__discount = new_discount

apple = Goods('apple',100)

print(apple.get_price()) #100

Goods.change_discount(0.8)

print(apple.get_price()) #80.0

上面的例子中,假设商店打折都是所有商品一起打折,这种时候你单独用某个对象来仅仅操作折扣那么就不合适了,所以采用类方法。

staticmethod

怎么说呢?感觉classmethod和staticmethod很相似啊!不过其中最大的区别就是classmethod最少有一个参数cls,而staticmethod可以没有参数,一般情况下,该方法中参数和该类(对象)的属性没有什么关系(甚至没有参数的情况下),可以选用staticmethod。

class Login():

def __init__(self,username,passwd):

self.username = username

self.__passwd = passwd

def login(self):pass

@staticmethod

def inputInfo():

username = input('>>>')

passwd = input('>>>')

return Login(username,passwd)

a = Login.inputInfo() #xzy(username) moe(passwd)

print(a.username) #xzy

可以看出这个Login类,获取用户输入密码这个函数的参数与类(对象)本身的属性没有什么关系,不过需要创建一个对象的时候需要用到它,在使用它的时候也不需要什么参数,那么这种情况下可以选用@staticmethod。

0x01 判断对象与类之间关系的函数

有两个函数,都非常的简单。一个时候isinstance(obj,class)另一个是issubclass(subclass,base)。

class A():pass

class B(A):pass

a = A()

b = B()

print(isinstance(a,A)) #True

print(issubclass(B,A)) #True

第一个是判断这个对象是不是这个类的实例化,第二个方法是判断B类是不是A类的子类。

0x02 反射

反射是Python中很重要的内容,能用到的地方也是非常的多。反射就是通过利用字符串类型的名字,去操作一个变量。其实仔细想一下貌似和eval的功能有点类似,不过呢eval存在在安全隐患,一般都不推荐使用。

反射相关的方法主要有4个:

getattr

hasattr

setattr

delattr

class Person():

def __init__(self,name,age,sex):

self.name = name

self.age = age

self.sex = sex

def func1(self):

print('1' + self.name)

def func2(self):

print('2' + self.age)

p = Person('xzymoe',20,'man')

#用户输入属性名称就查询该属性

inp = input('>>>') #name

print(getattr(p,inp)) #xzymoe

#当用户输入方法名称就调用相应方法

inp = input('>>>') #name

#这里返回一个绑定方法,为一个内存地址

ret = getattr(p,inp) #>

ret() #1xzymoe

这里可以看到当用户输入一个字符串数据的类型的时候,可以不用去判断输入的内容是什么,然后在选择返回什么属性或者方法。而反射自动可以帮你完成这项工作。不过上面的代码不是很完美,因为当用户随意输入一个不存在的变量怎么办呢?这个时候就可以和hasattr搭配使用了。

#用户输入属性名称就查询该属性

inp = input('>>>')

if hasattr(p,inp):

print(getattr(p,inp))

else:

print('没有这个属性或者方法')

hasattr就可以判断传入的字符串是否在这个对象中有属性或者方法,有着返回True,没有就返回False。

相比hasattr和getattr,setattr和delattr用的就不是那么多。

setattr(p,'weight',100)

print(p.__dict__) #{'age': 20, 'weight': 100, 'name': 'xzymoe', 'sex': 'man'}

delattr(p,'weight')

print(p.__dict__) #{'age': 20, 'name': 'xzymoe', 'sex': 'man'}

从上面的代码可以看出,使用setattr可以给对象添加、更改属性;而使用delattr则可以给对象删除属性。

反射不仅仅可以使用在对象里,还可以使用在模块里。

这里有一个t5模块,将被t4调用。

t5代码如下:

class Foo():

def func(self):

print('this is Foo Moudle')

t4代码如下:

import t5

f = t5.Foo()

ret = getattr(f,'func')

ret() #this is Foo Moudle

这样就可以方便的反射到了t5的模块里。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值