快速掌握——python类 封装[私有属性方法]、继承【python进阶】(内附代码)
1.类的定义 与 实例化对象
在python中使用class关键字创建一个类。
举例子
class Stu(object):
id = '1001'
name = '张三'
def __init__(self):
pass
def fun1(self):
pass
# 实例化对象
s1 = Stu()
s2 = Stu()
print(s1.name)
print(s2.name)
第一个方法 __init__是一种特殊的方法,称为构造函数或者初始化函数,并不是必须的,需要的时候添加即可。
第二个 self参数表示的是实例化对象的id号,每次调用的时候self和对象的id号进行自动绑定。
1.1.访问属性/方法
使用符号 . 进行访问
# 访问属性
对象名.属性
# 访问方法
对象名.方法名()
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
print(f"我的名字是 {self.name},我今年 {self.age} 岁。")
# 创建Person类的一个实例
person1 = Person("张三", 30)
# 调用实例的方法
# 访问属性
person1.age=60 #对象名.属性
# 访问方法
person1.introduce() #对象名.方法名()
还可以使用以下函数的方式来访问属性:
- getattr(obj, name[, default]) : 访问对象的属性。
- hasattr(obj,name) : 检查是否存在一个属性。
- setattr(obj,name,value) : 设置一个属性。如果属性不存在,会创建一个新属性。
- delattr(obj, name) : 删除属性。
1.2 对象与类的关系
- 对象拥有 类 的 所有属性和方法
- 对象的 属性和方法 可以 单独添加、删除、修改
- 对象与对象之间的属性和方法不可共享
- 对象不能独自创建,必须依托于类,类可以实例化N个对象
class Stu(object):
id = '1001'
name = '张三'
def fun1(self):
pass
# 实例化对象
s1 = Stu()
s2 = Stu()
# 对象的属性可以单独修改、添加、删除
s1.name = '李四'
s1.age = 18
del s1.age
print(s1.name)
# print(s1.age)
print(s2.name)
# print(s2.age)
1.3 魔方方法——构造函数 与 析构函数
魔方方法是一种特殊的命名约定,它们以双下划线开始和结束。这些方法在特定的条件下会被Python解释器自动调用,为Python类添加了动态的、面向对象的行为。
- __init__ 构造函数:完成对象的初始化工作,方便统一管理、调用类创建对象时,自动执行。
- __del__ 析构函数:删除对象时执行一些操作,自动执行。
- __str__ 打印方法:输出执行信息,自动执行。
class Car(object):
def __init__(self, name, color):
self.name = name
self.color = color
def __str__(self):
return f"车品牌{self.name} 颜色{self.color}"
def __del__(self):
print(f"{self.name}报废了,去车管所吧")
c1 = Car("奥迪", "黑色")
c2 = Car("小米su7", "紫色")
print(c1.name, c2.name)
print(c1)
print(c2)
# print(str(c1))
_init__(self[, ...]): 构造器方法,当创建一个新对象时被调用,用于初始化对象。 |
__del__(self): 析构器方法,当对象被销毁之前被调用,用于清理资源。 |
__str__(self): 返回对象的字符串表示形式,常用于 print() 函数或 str() 函数。 |
__repr__(self): 返回一个准确无误的字符串表示形式,用于调试或开发,比 __str__ 更加详细 |
__len__(self): 定义当对对象使用 len() 函数时的行为,返回容器的长度。 |
__getitem__(self, key): 实现了对象的索引访问,如 my_obj[key]。 |
__setitem__(self, key, value): 允许设置对象的索引值,如 my_obj[key] = value。 |
__iter__(self): 使对象成为可迭代的,返回一个迭代器对象。 |
__next__(self): 在迭代器中定义 next() 行为,返回下一个值。 |
__call__(self[, args...]): 使得对象可以像函数一样被调用,例如 my_obj(). |
__add__(self, other): 定义加法操作符 + 的行为,如 my_obj + other_obj。 |
__eq__(self, other): 定义等于运算符 == 的行为,用于比较两个对象是否相等 |
1.4 类属性/方法 与 实例对象属性/方法 与 静态方法
属性:
class Student(object):
"""
定义了一个学生类
"""
grade = 'py24101' # 类属性
def __init__(self, name, age):
self.name = name # 实例对象属性
self.age = age # 实例对象属性
s1 = Student('张三', 18)
# 类属性的访问
print(Student.grade)
print(s1.grade)
# 实例属性的访问
# print(Student.name) 报错!!!
#类 不能访问 实例对象的属性
#相当于闭包,内可以访问外,外不能访问内
print(s1.name)
class Bank(object):
"""
定义了一个银行卡类,用于初始化、存钱、取钱
"""
total_money = 0
def __init__(self, name, money):
self.name = name
Bank.total_money += money #改为self.
#Bank.total_money 通过类 调用 类属性
def save(self, money): #self.total_money 通过对象 调用 类属性
Bank.total_money += money
def draw(self, money):
Bank.total_money -= money
b1 = Bank('张三', 1000)
print(b1.total_money)
b1.save(5000)
print(b1.total_money)
b1.draw(3000)
print(b1.total_money)
b2 = Bank('李四', 8888)
print(b2.total_money)
b2.save(10000)
print(b2.total_money)
类方法、实例方法、静态方法:
class Student(object):
"""
定义了一个学生类
"""
grade = 'py24101'
@classmethod
def cls_fun(cls):
"""类方法中只能调用类属性和类方法"""
print(f"班级名称是{cls.grade}")
def __init__(self, name, age):
self.name = name
self.age = age
def fun1(self):
"""实例方法中能调用类属性、实例属性"""
print(f"实例方法中输出类属性{self.grade}, 输出实例属性{self.name}")
@staticmethod
def sta_fun(x):
print(f"{x}静态方法一般实现与类和对象无关联的操作,例如:游戏说明书等")
s1 = Student('张三', 18)
# 如何调用类方法
Student.cls_fun()
s1.cls_fun()
# 如何调用实例方法
Student.fun1(s1)
s1.fun1()
# 如何调用静态方法
Student.sta_fun(3)
s1.sta_fun(3)
1.5 Python的内置类属性
- __dict__ : 类的属性(包含一个字典,由类的数据属性组成)
- __doc__ :类的文档字符串
- __name__: 类名
- __module__: 类定义所在的模块(类的全名是'__main__.className',如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod)
- __bases__ : 类的所有父类构成元素(包含了一个由所有父类组成的元组)
class Student(object):
"""
定义一个学生类
属性:名字 年龄
方法:method_1 method_2
"""
name = '张三'
age = 18
def method_1(self):
pass
def method_2(self):
pass
print(Student.__dict__)
print(Student.__doc__)
print(Student.__name__)
print(Student.__module__)
print(int.__module__)
print(Student.__bases__)
2.类的封装【私有属性与方法】
封装指的是隐藏对象中一些不希望让外部所访问的属性或方法。
python中封装是通过设置访问权限来体现的,私有属性和私有方法是控制访问权限的组成部分。
2.1 私有属性
在类的内部使用,不希望外部直接访问的变量。
在python中,使用双下划线作为前缀来定义私有属性。
私有属性在类外不能访问
class Bank(object):
"""
定义了一个银行卡类
属性:name pwd密码【我不希望外部访问】
"""
def __init__(self, name, pwd):
self.name = name
self.__pwd = pwd
# 为了在某些需要的时候,访问到私有属性,所以需要在类内部设置两个接口
def get_pwd(self):
return self.__pwd
def set_pwd(self, newpwd):
self.__pwd = newpwd
# print(Bank.__pwd)
b1 = Bank('张三', '123456')
print(b1.name)
# print(b1.__pwd)
print(b1.get_pwd())
b1.set_pwd('666888')
print(b1.get_pwd())
2.2 私有方法
和私有属性是一样的。
class Bank(object):
"""
定义了一个银行卡类
属性:name pwd密码【我不希望外部访问】
"""
def __init__(self, name, pwd):
self.name = name
self.__pwd = pwd
def __info(self):
print(f"名字{self.name}, 密码{self.__pwd}")
def get_info(self):
self.__info()
# Bank.__info() 报错
b1 = Bank('李四', '123456')
# b1.__info() 报错
b1.get_info()
2.3 属性装饰器
属性装饰器是实现把方法转为属性的装饰器。
作用:
1. 把方法转为属性,便于操作属性
2 . 实现对属性的更改(验证)、查看、删除
语法格式:
class 类名(object):
def __init__(self):
self.__名字 = xxx
@property def 函数名(self):
return self.__名字
@函数名.setter def 函数名(self, m):
self.__名字 += m
class Car(object):
def __init__(self, name, color):
self.name = name
self.color = color
self.__num = 20
@property
def num(self):
return self.__num
@num.setter
def num(self, x):
self.__num += x
c1 = Car('法拉利', '红色')
print(c1.name, c1.color, c1.num)
c1.num = 80
print(c1.num)
class Student(object):
def __init__(self, name):
self.__name = name
@property
def name(self):
return self.__name
@name.setter
def name(self, new_name):
if not isinstance(new_name, str):
print('名字必须是一个字符串')
else:
self.__name = new_name
@name.deleter
def name(self):
print("已删除名字")
del self.__name
s1 = Student('张三')
print(s1.name)
s1.name = 111
s1.name = '华清远见'
print(s1.name)
del s1.name
3.类的继承
面向对象的编程带来的主要好处之一就是代码的重用,
实现这种重用的方法之一就是通过继承机制。
通过继承创建的新类称之为【子类】或者【派生类】,
被继承的类称之为【父类】、【基类】、【超类】。
3.1 继承语法格式
class 子类名(父类名列表):
pass
class Parent(object):
"""
定义父类
"""
par_attr = 100
def __init__(self):
print("初始化父类")
def par_fun1(self):
print("父类方法1")
def par_fun2(self):
print("父类方法2")
class Child(Parent):
"""
定义子类
"""
child_attr = 666
def __init__(self):
print("初始化子类")
def child_fun1(self):
print("子类方法1")
c1 = Child()
print(c1.child_attr)
c1.child_fun1()
print(c1.par_attr)
c1.par_fun1()
c1.par_fun2()
3.2 多继承语法【不建议乱用】
如果在继承的元组()里面有一个以上的类,就称之为多继承。
# python中提供了一个函数mro()用于查看继承的顺序。
class A:
pass
class B:
pass
class C:
pass
class D(A, B, C):
pass
d1 = D()
print(D.mro())
3.3 继承重写父类方法
如果你的父类方法不能满足你得要求,你可以在之类中重写父类的方法。
class Parent(object):
def method(self):
print(f"{self}的方法")
class Child(Parent):
pass
c = Child()
c.method()
# 重写
class Parent(object):
def method(self):
print(f"{self}的方法")
class Child(Parent):
def method(self):
print("xxxxxxxxxx")
print(f"{self}的方法")
c = Child()
c.method()
这里列出了一些通用的功能,可以在自己的类重写:
- __init__ ( self [,args...] ) 构造函数 简单的调用方法: obj = className(args)
- __del__( self ) 析构方法, 删除一个对象 简单的调用方法 : del obj
- __repr__( self ) 转化为供解释器读取的形式 简单的调用方法 : repr(obj)
- __str__( self ) 用于将值转化为适于人阅读的形式 简单的调用方法 : str(obj)
- __cmp__ ( self, x ) 对象比较 简单的调用方法 : cmp(obj, x)
3.4 python继承特点
- 在子类中如果需要父类的构造方法,需要显式调用父类的构造方法,或者不重写父类的构造方法。__init__()
- 在子类中调用父类的方法,需要显式调用,且第一个参数self不能省略。
class Parent(object):
def __init__(self, x, y):
self.x = x
self.y = y
def method(self):
print(f"{self}的方法")
class Child(Parent):
def fun1(self):
print(self.x , self.y)
# 不重写父类构造方法
c = Child(1, 2)
c.fun1()
class Parent(object):
def __init__(self, x, y):
self.x = x
self.y = y
def method(self):
print(f"{self}的方法")
class Child(Parent):
def __init__(self, x, y, z):
Parent.__init__(self, x, y)
self.z = z
def fun1(self):
print(self.x , self.y, self.z)
# 重写父类构造方法、里面显式调用父类构造方法
c = Child(1, 2, 33)
c.fun1()
class Parent(object):
def __init__(self, x, y):
self.x = x
self.y = y
class Child(Parent):
def __init__(self, x, y, z):
super().__init__(x, y)
self.z = z
def add(self):
return self.x + self.y + self.z
c = Child(1, 1, 1)
print(c.add())
class Parent(object):
def __init__(self, x, y):
self.x = x
self.y = y
def add(self):
return self.x + self.y
class Child(Parent):
def __init__(self, x, y, z):
super().__init__(x, y)
self.z = z
def add(self):
return super().add() + self.z
c = Child(1, 1, 1)
print(c.add())
3.5 运算符重载
在Python中,并没有像其他语言(如C++)中那样的内置机制来重载运算符。但是,你可以通过定义特定的方法来模拟运算符重载的行为。
以下是一些常见运算符以及它们对应的特殊方法:
加法:+ 对应 __add__ |
减法:- 对应 __sub__ |
乘法:* 对应 __mul__ |
除法:/ 对应 __truediv__ |
取模:% 对应 __mod__ |
幂运算:** 对应 __pow__ |
位运算:<< 对应 __lshift__ |
位运算:>> 对应 __rshift__ |
位运算:| 对应 __or__ |
位运算:& 对应 __and__ |
位运算:^ 对应 __xor__ |
class Operator(object):
def __init__(self, x):
self.x = x
def __add__(self, other):
return self.x + other.x * 3
o1 = Operator(1)
o2 = Operator(3)
print(o1 + o2)
class Operator(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return self.x * other.x + self.y * other.y
o1 = Operator(1, 2)
o2 = Operator(3, 4)
print(o1 + o2)
4.类的多态
python中的多态也可以通过方法重写进行。
同一个方法,不同对象显式的结果不同。
class Animal(object):
name = '动物'
age = 0
def speak(self):
print("动物的声音")
class Dog(Animal):
def speak(self):
print("汪汪汪")
class Cat(Animal):
def speak(self):
print("喵喵喵")
a = Animal()
d = Dog()
c = Cat()
a.speak()
d.speak()
c.speak()
5. 关于下划线说明
- __foo__: 以双下划线开头双下划线结尾,定义的是特殊方法,一般是系统定义名字 ,
类似 __init__() 之类的,自动。
- _foo: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import ···
- __foo: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了。