类
定义:类是对一群具有相同特征或者行为的事物的一个统称,是抽象的,不能直接使用。在 Python 中,类的定义与函数的定义类似,所不同的是,类的定义是使用关键字 “class”。与函数定义相同的是,在定义类时也要使用缩进的形式,以表示缩进的语句属于该类。
对象:对象是由类创建出来的一个具体存在,可以直接使用,并且由哪一个类创建出来的对象,就拥有在哪一个类中定义的: 属性和方法。
类的定义语法
最简单的应用: #类中的语句可以是变量(表示类的属性),与可以是函数(表示类的功能)
class ClassName #这里类的命名采用驼峰命名法规则。
<statement-1>
.
.
.
<statement-N>
类对象与实例变量
类变量:定义在类中的,且方法外的变量叫做类变量。除此之外,类变量用于类的所有实例共享的属性和方法,即所有实例共享类变量。
实例变量(对象变量):仅对每一个实例对象独享,且对象之间相互独立。
类变量和实例对象的定义:
class StudentName:
sex = "男" 这里的sex和score属于对类变量的定义
score = 100
def __init__(self,name, age):
#这里通过def __init__(self, arg1, arg2) 将所有定义的实例对象定义在—__init__中.
# self.attr1 = arg1
# self.attr2 = arg2
#self.attr1和self.attr2就是对象变量,且使用了self。
self.name = name
self.age = age
def print_info(self): 定义类方法
print("该学生基本信息")
zhangsan = StudentName("zhangsan", 18) #那么这里zhangsan和lisi属于对象的实例化
lisi = StudentName("lisi", 20)
类中的访问:
print(zhangsan.name) #对实例对象的访问
print(zhangsan.sex) #对类对象的访问
print(StudentName.sex) #标准语法是用类名访问类变量
print(zhangsan.score) #此语法为不规范的访问
zhangsan.print_info() #通过实例对象访问类方法
StudentName.print_info(self=zhangsan) #通过类变量访问类方法需要加参数
类的继承
首先明白一点如果不支持继承,语言特性就不值得称为“类”。
类继承的语法:
class ClassName(ParentClass1, ParentClass2, ....):
<statement-1>
.
.
.
<statement-N>
#了解”class ClassName(object):“ 这个语句。其实在python中所有的类都默认继承子object, object在继承的语法的时候,可以省略,并且,如果一个类继承自除object之外的类,object是不能写在继承列表中的。
#以下为object以及python内置的函数方法:
def __add__(self, other):
def __sub__(self, other):
def __divmod__(self, other):
def __mul__(self, other):
def __floordiv__(self, other):
def __truediv__(self, other):
def __eq__(self, other):
def __le__(self, other):
def __len__(self):
def __str__(self):
def __repr__(self):
def __dir__(self):
def print_info(self):
__new__: 创建一个对象
__init__: 初始化一个对象
__add__: 加法:预定的魔法方法
__sub__: 减法:预定义的
__mul__: 乘法:预定义的
__truediv__: 除法:预定义的
__len__:长度
__str__:人可读的的
__repr__:程序员可读的
继承的顺序
python中如何判定继承顺序:__mor__方法
改变类的顺序:
super(type, object-or-type)
这里type:根据__mro__继承的顺序,从type开始搜寻。
object-or-type:指定我我们对继承顺序,object对应类的__mro__,type对应类的__mro__
super(A, c) => isinstance(c, A) => c是A的一个实例 #判断是否属于类中的实例
super(A, C) => issubclass(C, A) => C是A的一个子类 #判断是否属于类中的子类
例子:
class A:
def print_info(self):
print("A")
class B:
def print_info(self):
print("B")
def say_something(self):
print("B says something")
class C:
def say_thing(self):
print("C says something")
class D:
def print_info(self):
print("D")
def say_something(self):
print("D says something")
class E(A, B, C, D):
pass
输入:
e = E() #E类对象的 实例化
print(E.__mro__) #查看E类的继承顺序
e.print_info() #我们通过对象调用E类中的方法
e.say_something()
结果: #当我们执行上面语句时,可以看出默认执行的是按照E类的执行顺序第一个方法print_info在A类中调用,第二个say_something在B类中调用。
(<class '__main__.E'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)
A
B says something
#那么我们怎么改变E的继承顺序呢?
通过以上我们的 super()方法进行。
将我们要改的语句在E类中进行说明。
如: #这里我们将print_info方法调用B类的,将say_something方法调用C类的。
class E(A, B, C, D):
def print_info(self):
super(A, self).print_info() #等价super()print_info()
def say_something(self):
super(B, self).say_thing()
结果:#再次运行输入的代码结果如下
B
C says something
装饰器
定义:函数去装饰别的函数,一个函数叫我们的装饰器,一个函数叫做被装饰的函数或者原函数
python中的装饰器:在不改变原函数代码的情况下,增强原函数的功能。
装饰器语法:
1.利用闭包定义一个装饰器
2.利用装饰器的语法糖: @装饰器名, 写在被装饰函数的上边
闭包
定义:一个函数定义中引用了函数外定义的变量,并且该函数可以在其定义环境外被执行,能够读取其他函数内部变量的函数。
闭包特征:
1.嵌套函数
2.内层函数引用了外层函数的变量
3.内层函数作为回值返回给外层函数
自由变量: 既不是局部变量,也不是模块全局变量
在闭包的时候:内层引用外层函数的变量
def outer(fucn): #fucn是一个自由变量,它指的是我们调用此函数的函数即是test_fucn。
data = fucn
def inner():
print("我们赢了")
fucn()
print("EDG NB")
return inner
@outer
def test_fucn():
print("S11 champion: EDG")
test_fucn()
结果:
我们赢了
S11 champion: EDG
EDG NB
从上面可以看出装饰器并没有传递参数,那么装饰器怎么传递参数呢?
输入:
def outer(func):
def inner(arg1, arg2):
print("我们赢啦")
func(arg1, arg2)
print("EDG NB")
return inner
@outer
def test_arg(arg1, arg2):
print(arg1, arg2)
test_arg(1, 2)
结果:
我们赢啦
1 2
EDG NB
装饰器的委托属性
委托属性:当类中有一个对象变量_x: 但是_x不想让用户直接去访问,但是可以通过其他的方式去操作它。_x ——> 不能 _x = xxx, 不能直接去访问_x,所以可以创建一个委托属性:操作委托属性就相当于操作_x。
静态方法:staticmethod
@staticmethod
类方法: classmethod
@classmethod
调用方法:
# 1.直接使用类名.方法名
# 2.使用对象.方法名
既然类名.方法名可以调用,意味着我在可以不实例化对象的时候调用它。
class Person:
@staticmethod
def static_method():
print("This is static method")
@classmethod
def class_method(cls):
print("This is class method:", cls)
# cls => class和定义类的时候的关键字冲突,cls
# cls指向的就是调用它的类
Person.class_method()
Person.static_method()
human = Person()
human.class_method()
human.static_method()
结果:
This is class method: <class '__main__.Person'>
This is static method
This is class method: <class '__main__.Person'>
This is static method
例子2.
class Woman:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self._gender = gender
def print_info(self):
print(self.name, self.age, self._gender)
@property
def gender(self):
return self._gender
@gender.setter
def gender(self, value):
self._gender = value
@gender.deleter
def gender(self):
del self._x
用户可以去直接操作name, age,但是不能直接_gender,所以可以给_gender 产生一个委托属性 gender,并且通过操作gender就相当于操作_gender。
操作的方式:访问gender, 修改gender, 删除。
委托属性怎么产生?
我们可以提供一些方法:访问get, 修改方法set, 删除方法del。
使用python中提供装饰器讲这些方法转换成属性
给这些方法起相同名字xxx:具有一个委托属性xxx
_gender的委托属性gender
python中的私有变量
python解释器中的名称改写:
由于存在对于类私有成员的有效使用场景(例如避免名称与子类所定义的名称相冲突),
因此存在对此种机制的有限支持,称为名称改写。
名称改写:在类中定义的__xxx的变量和方法, python解释器都会进行名称改写
改成_ClassName__xxx: 在变量名之前加_ClassName
例子:
class Parent:
def __method1(self): # __method1 => _Parent__method1
print("123")
class Son(Parent):
def __method1(self): # __method1 => _Son__method1
print("456")
# 子类son从父类继承: _Parent__method1,
# 子类中有两个方法: _Parent__method1, _Son__method1
son = Son()
son._Son__method1()
son._Parent__method1()
结果:
456
123