文章目录
python面向对象1
面向对象(属性,方法)
类的定义
-
关键字
class
-
格式
class 类名
class MyClass: pass
类的内部和外部
- 类的内部:从类的定义
class
开始,到类的定义结束,这个范围内都称为类的内部。 - 除类定义的范围外的所有位置都叫类的外部,即使是同一个
py
文件中也是类的外部。
属性
类属性
公有类属性
- 定义在类中,定义在方法外,不使用双下划线
__
打头的变量。- 在类内部的方法中使用时 self.public_attr。
- 在类外,可以使用
类名.public_attr
或者实例名.public_attr
访问
class MyClass:
public_para = 10 #公有变量,类外可以方法
私有类属性
- 两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。
- 在类内部的方法中使用时 self.private_attrs
- 在类外不可以访问
class MyClass:
__private_para = 100 #私有变量,类外不可以访问
举例
class MyClass:
public_para = 10 #公有属性
def fun(self):
self.public_para += 1
obj1 = MyClass()
obj2 = MyClass()
pub_para_res1_by_className1 = MyClass.public_para #类外可以访问,使用 类名.公有属性名 10
MyClass.public_para += 5 #通过类名访问公有属性,并对其重新赋值,则类的公有属性被新的值覆盖 15
pub_para_res1_by_obj1 = obj1.public_para #类外可以方法,使用 对象名.公有属性名 15
obj1.public_para += 5 #通过对象名访问公有属性,并对其重新赋值,则只会修改该对象中的 public_para
pub_para_res1_by_obj2 = obj2.public_para #类外可以方法,使用 对象名.公有属性名 15
print('pub_para_res1_by_className1:%s' % pub_para_res1_by_className1) #10+5 → 15
print('pub_para_res1_by_obj1:%s' % pub_para_res1_by_obj1) #15+5 → 20
print('pub_para_res1_by_obj2:%s' % pub_para_res1_by_obj2) #15
obj1.fun() #修改自身的public_para,20+1→21
obj2.fun() #修改自身的public_para,15+1→16
pub_para_res2_by_className2 = MyClass.public_para #类外可以访问,使用 类名.公有属性名 15
pub_para_res2_by_obj1 = obj1.public_para #类外可以访问,使用 对象名.公有属性名 21
pub_para_res2_by_obj2 = obj2.public_para #类外可以访问,使用 对象名.公有属性名 16
print('pub_para_res2_by_className2:%s' % pub_para_res2_by_className2)
print('pub_para_res2_by_obj1:%s' % pub_para_res2_by_obj1)
print('pub_para_res2_by_obj2:%s' % pub_para_res2_by_obj2)
# 结果
pub_para_res1_by_className1:10
pub_para_res1_by_obj1:15
pub_para_res1_by_obj2:15
pub_para_res2_by_className2:15
pub_para_res2_by_obj1:21
pub_para_res2_by_obj2:16
class MyClass:
__private_para = 10 #公有属性
def fun(self):
self.__private_para += 1
def fun_ret(self):
return self.__private_para
obj1 = MyClass()
obj2 = MyClass()
obj1.fun()
obj2.fun()
obj2.fun()
pri_res1 = obj1.fun_ret()
pri_res2 = obj2.fun_ret()
print(pri_res1)
print(pri_res2)
# 结果
11
12
class MyClass:
__private_para = 10 #公有属性
def fun(self):
self.__private_para += 1
def fun_ret(self):
return self.__private_para
obj = MyClass()
prv_res_byObjName = obj.__private_para #试图从类的外部,访问私有类属性,会抛异常
prv_res_byClassName = MyClass.__private_para #试图从类的外部,访问私有类属性,会抛异常
# 结果
AttributeError: 'MyClass' object has no attribute '__private_para'
小结
- 类属性的访问
- 在类内,无论是公有属性还是私有属性,总是可以通过类名或者通过对象名访问
- 在类外,公有属性可以通过类名或者通过对象名访问;私有属性都不可以访问
- 类属性的修改
- 通过类名修改后的类属性,会更新类属性的值。
- 通过对象名修改的类属性,只会更新属于对象本身中的类属性,其值的修改不会影响通过类获取的类属性的值。
- 通过对象名最开始获取的类属性
对象名.类属性
总得到先从类的类属性最新值
- 通过对象名最开始获取的类属性
- 在编写程序的时候,千万不要对实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性。
实例属性
-
每个实例都可以有自己的变量用来保存对象自己的数据,称为实例变量(也叫属性)
-
给实例绑定属性的方法是通过实例变量,或者通过
self
变量 -
定义和访问的方式
- 定义
self.实例属性=值
- 访问
self.实例属性
- 赋值规则同变量的赋值规则
- 首次为属性赋值,则创建此属性
- 再次为属性赋值,则改变此属性的绑定关系
- 定义
非私有实例属性
class MyClass:
def __init__(self, objAttrPara):
self.objAttr = objAttrPara #这里的self.objAttr为实例属性,为当前调用者所有。
#通过self.objAttr进行访问
def fun(self):
self.objAttr += 1 #通过 对象名.实例属性 在类内访问并修改
def funRet(self):
return self.objAttr
obj1 = MyClass(30)
obj2 = MyClass(3)
print('通过对象名obj直接访问的方式获得实例obj1属性:%s' % obj1.objAttr)#通过 对象名.实例属性 访问
print('-'*40)
obj1.fun()
obj2.fun()
obj2.fun()
obj2.objAttr +=3 #通过 对象名.实例属性 在类外访问并修改
print('通过对象名obj1直接访问的方式获得实例obj1属性:%s' % obj1.funRet())
print('通过对象名obj1直接访问的方式获得实例obj1属性:%s' % obj2.objAttr)
# 结果
通过对象名obj直接访问的方式获得实例obj1属性:30
----------------------------------------
通过对象名obj1直接访问的方式获得实例obj1属性:31
通过对象名obj1直接访问的方式获得实例obj1属性:8
私有实例属性
class MyClass:
def __init__(self, objAttrPara):
self.__objAttr = objAttrPara #这里的self.objAttr为实例属性,为当前调用者所有。
#在类内通过self.objAttr进行访问
#在类外无法通过self.objAttr进行访问
def fun(self):
self.__objAttr += 1 #通过 对象名.实例属性 在类内访问并修改
def funRet(self):
return self.__objAttr
obj = MyClass(30)
obj.fun()
print('通过对象名obj直接访问的方式获得实例obj1属性:%s' % obj.funRet())
print('通过对象名obj直接访问的方式获得实例obj1属性:%s' % obj.__objAttr)#通过 对象名.私有实例属性 访问,会报异常
# 结果
通过对象名obj直接访问的方式获得实例obj1属性:31
File "G:/testSele.py", line 18, in <module>
print('通过对象名obj直接访问的方式获得实例obj1属性:%s' % obj.__objAttr)#通过 对象名.实例属性 访问
AttributeError: 'MyClass' object has no attribute '__objAttr'
方法
类方法
- 使用
def
关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数self
,且为第一个参数,sel
f 代表的是当前实例。- self 的名字并不是规定死的,也可以使用 this,但是最好还是按照约定是用 self。
一般方法
-
调用方式
-
在类内通过
self.方法名(实参列表)
调用 -
在类外用通过
对象名.方法名(实参列表)
调用
-
class MyClass:
def generalMethod(self, para): #定义一个一般方法
print('这是一个一般方法')
print('传入的para参数为:%s' % para)
def callGenMethod(self):
print('内部调用一般方法')
self.generalMethod(100)
obj = MyClass()
obj.generalMethod(10) #在外部通过 对象名.方法名(实参列表) 调用
obj.callGenMethod()
# 结果
这是一个一般方法
传入的para参数为:10
内部调用一般方法
这是一个一般方法
传入的para参数为:100
私有方法
- 个下划线开头的方法,声明该方法为私有方法。
def __privateMethod(参数列表)
- 调用方式
- 在类的内部通过
self.私有函数名(实参列表)
调用 - 在类的外部库可以调用
- 在类的内部通过
class MyClass:
def __privatelMethod(self, para): #定义一个一般方法
print('这是一个私有方法')
print('传入的para参数为:%s' % para)
def callGenMethod(self):
print('内部调用私有方法')
self.__privatelMethod(100) #在类内部通过 self.__privateMethod(实参列表) 调用
obj = MyClass()
obj.callGenMethod()
obj.__privateMethod # 在类外调用私有方法,会抛异常
# 结果
内部调用私有方法
Traceback (most recent call last):
这是一个私有方法
传入的para参数为:100
File "G:/testSele.py", line 15, in <module>
obj.__privateMethod
AttributeError: 'MyClass' object has no attribute '__privateMethod'
类专有方法
- 以双下划线开始且以双下划线结尾的方法为类的专用方法,
__变量__
。这样的专有方法个数有限,有各自的特殊作用。 - 有些
__变量__
不是类专有方法,而是一些特殊变量。如__name__
,__main__
等
专有方法举例
_init__ : 构造函数,在生成对象时调用
__del__ : 析构函数,释放对象时使用
__call__: 函数调用
__cmp__: 比较运算
__add__: 加运算
__sub__: 减运算
__mul__: 乘运算
__truediv__: 除运算
__mod__: 求余运算
__pow__: 乘方
__repr__ : 打印,转换
__setitem__ : 按照索引赋值
__getitem__: 按照索引获取值
__len__: 获得长度
运算符重载
- 需要借用类专有方法才能实现
class MyClass:
def __init__(self, a, b):
self.a = a
self.b = b
def __str__(self):#自定义用于打印的字符串数据
return '使用__str__返回的字符串值为:(%d, %d)' % (self.a, self.b)
def __add__(self, otherObj): #重载 加法+ 运算符,
#其中otherObj为加法后面的同属于MyClass类型的对象
return MyClass(self.a + otherObj.a, self.b + otherObj.b)
v1 = MyClass(2, 10)
v2 = MyClass(5, -12)
v3 = v1 + v2
print(v3)
# 结果
使用__str__返回的字符串值为:(7, -2)
Python中的下划线
- 前后没有下划线的是公有方法或属性
- 前边有一个下划线的为私有方法或属性,子类无法继承
- 前边有两个下划线的 一般是为了避免于子类属性或者方法名冲突,无法在外部直接访问
- 前后都有双下划线的为系统方法或属性
- 后边单个下划线的可以避免与系统关键词冲突