文章目录
1. 类的创建与实例化
下面实例为类的创建与实例化,class后面为类名,类名第一个字母大写
class Person:
def __init__(self, name):
self.name = name
def show(self):
print(self.name)
if __name__ == '__main__':
person = Person('Tony')
person.show()
动态绑定属性
:实例化对象后,为该对象添加一个属性,给哪个对象绑定了属性,只能对哪个对象有该属性,其他对象没有该属性,如果在方法中引用了该属性,那么没有该属性的对象调用这个方法时会报错,对上面代码做些修改,将name改为动态绑定属性后代码如下:
class Person:
def __init__(self):
pass
if __name__ == '__main__':
person = Person()
person.name = "Tony"
print(person.name)
复合类
:类的属性也可以是类对象,创建对象时通过参数传入,即将类对象作为另一个类属性使用
class Car(object):
def __init__(self, person):
self.person = person
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
tom = Person('Tom', 20)
Car(tom)
2. 类的魔法方法
方法 | 含义 | 说明 |
---|---|---|
__init__ | 创建对象的时候自动执行,用于初始化对象 | |
__str__ | 格式化对象输出,返回一个字符串 | 没有时打印对于输出内容+类使用<__main__.Person object at 0x000002C506609590> |
__repr__ | 格式化对象输出,返回的是官方字符串表示格式 | 作用和str差不多,该方法返回的字符串能被eval()解析,即eval(repr(obj))得到的结果与obj相同的对象,有str时,优先执行str方法,没有则执行repr方法 |
__del__ | 销毁对象,回收释放资源 | |
__len__ | 运行对类对象使用len()函数 | 没有该方法时使用len则报错 |
__getitem__ | 对象索引获取内容 | 没有该方法时使用对象[0]则报错 |
_getattr_ | 属性查找失败,进入该方法 | |
_setitem_ | 可以对类使用shuffle(类对象)方法打乱列表 |
class Person:
# 初始化时执行
def __init__(self, name):
self.name = name
def __str__(self):
# 一定要返回字符串
return self.name
def __len__(self):
return len(self.name)
# 类切片通常获取的是列表,如果要类对象切片之后返回的还是类对象,返回Person(self.name[position])
def __getitem__(self, position):
return self.name[position]
if __name__ == '__main__':
person = Person('Tony')
# 没有__str__方法则输出 <__main__.Person object at 0x00000210D7E13FB0>
print(person) # Tony
# 没有__len__方法则报错
print(len(person)) # 4
# 没有__getitem__方法则报错
print(person[0]) # T
如下为类运算相关的魔法方法(运算符重载)
方法 | 含义 |
---|---|
_neg_ | 取负运算符 |
_pos_ | 取正运算符 |
_invert_ | 对整数按位取反运算符 |
__abs__ | 绝对值,模长 |
__add__ | 加法运算 |
__sub__ | 减法运算 |
__mul__ | 乘法运算 |
__truediv__ | / |
__floordiv__ | // |
__mod__ | % |
__divmod__ | divmod() |
__pow__ | **或pow() (3**2) |
__round__ | round() |
__lt__ | < |
__le__ | <= |
__eq__ | == |
__ne__ | != |
__gt__ | > |
__ge__ | >= |
实现一元运算符和中辍运算符重载一定不能修改操作数,使用这些运算符表达式期待结果是新对象(返回结果为新创建的对象),只有增量赋值可能会修改第一个操作(修改原值)
运算符 | 正向方法 | 反向方法 | 就地方法 | 说明 |
---|---|---|---|---|
+ | _add_ | _radd_ | _iadd_ | 加法或拼接 |
- | _sub_ | _rsub_ | _isub_ | 减法 |
* | _mul_ | _rmul_ | _imul_ | 乘法或重复复制 |
/ | _truediv_ | _rtruediv_ | _itruediv_ | 除法 |
// | _floordiv_ | _rfloordiv_ | _ifloordiv_ | 整除 |
% | _mod_ | _rmod_ | _imod_ | 取模 |
divmod() | _divmod_ | _rdivmod_ | _idivmod_ | 返回有整除的商和模数组成的元组 |
**,pow() | _pow_ | _rpow_ | _ipow_ | 取幂 |
@ | _matmul_ | _rmatmul_ | _imatmul_ | 矩阵乘法 |
& | _matmul_ | _rmatmul_ | _imatmul_ | 位与 |
| | _or_ | _ror_ | _ior_ | 位或 |
^ | _xor_ | _rxor_ | ixor | 位异或 |
<< | _lshift_ | _rlshift_ | _ilshift_ | 按位左移 |
>> | _rshift_ | _rrshift_ | _irshift_ | 按位右移 |
比较运算符
分组 | 中辍运算符 | 正向方法调用 | 反向方法调用 | 后备机制 |
---|---|---|---|---|
相等性 | a == b | a.__eq__(b) | b.__eq__(a) | 返回id(a) == id(b) |
a != b | a.__ne__(b) | b.__ne__(b) | 返回not (a == b) | |
排序 | a > b | a.__gt__(b) | b.__gt__(a) | 抛出TypeError |
a < b | a.__lt__(b) | b.__lt__(a) | 抛出TypeError | |
a >= b | a.__ge__(b) | b.__ge__(a) | 抛出TypeError | |
a <= b | a.__le__(b) | b.__le__(a) | 抛出TypeError | |
如下代码以向量为例,对向量进行操作 |
class Vendor:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
# 定义输出的格式内容
def __repr__(self):
return 'Vector(%r, %r)' % (self.x, self.y)
# 实现加法运算
def __add__(self, other):
return Vendor(self.x + other.x, self.y + other.y)
# 实现乘法
def __mul__(self, other):
return Vendor(self.x * other.x, self.y * other.y)
a = Vendor(3, 4)
b = Vendor(1, 2)
print(a) # __repr__ # Vector(3, 4)
print(a + b) # __add__ # Vector(4, 6)
print(a * b) # __mul__ # Vector(3, 8)
类的实例变成可调用类型:类中声明__call__的时候,类对象可以充当函数使用,调用call的功能
class Abc():
def __init__(self):
self.a = 'abc'
def __call__(self):
print(self.a)
a = Abc()
a()
# abc
除了上面那些,还有很多魔法函数,如下为运算符无关的魔法方法
类别 | 方法名 |
---|---|
字符串/字符串序列表达形式 | __repr__,__str__,__format__,__bytes__ |
数值转换 | __abs__,__bool__,__complex__,__init__,__float__,__hash__,__index__ |
集合模拟 | __len__,__getitem__,__setitem__,__delitem__,__contains__ |
迭代枚举 | __iter__,__reversed__,__next__ |
可调用模拟 | __call__ |
上下文管理 | __enter__,__exit__ |
实例创建和销毁 | __new__,__init__,__del__ |
属性管理 | __getattr__,__getattribute__,__setattr__,__delattr__,__dir__ |
属性描述符 | __get__,__set__,__delete__ |
跟类相关的服务 | __prepare__,__instancecheck__,__subclasscheck__ |
与运算符相关的魔法方法
类别 | 方法名 |
---|---|
一元运算符 | __neg__ -,__pos__ +,__abs__ abs() |
反向算术运算符 | __radd__,__rsub__,__rmul__,__rtruedi__,__rfloordi__,__rmod__,__rdivmod__,____rpow__ |
增量赋值算术运算符 | __iadd__,__isub__,__imul__,__itruediv__,__ifloordiv__,__imod__,__ipow__ |
位运算符 | __invvert__ ~,__lshift__ <<,__rshift__ >>,__and__ &,__or__ |,__xor__ ^ |
反向位运算符 | __rlshift__,__rrshift__,__rand__,__rxor__,__ror__ |
增量赋值位运算符 | __ilshift__,__irshift__,__iand__,__ixor__,__ior__ |
3. 类属性与函数
公有属性
(public):属性前面没有加下划线,则为共有属性,该属性既可以在类内获取与修改,也可以在类外获取与修改
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
if __name__ == '__main__':
Tony = Person('Tony', 25)
print(Tony.age) # 25
Tony.age = 18
print(Tony.age) # 18
# __dict__用来保存当前对象的所有成员
print(Tony.__dict__)
私有属性
(private):属性前面加了双下划线,则为私有属性,该属性只能可以在类内获取与修改,在类外不能读取与修改,要在类外使用,只能通过类的公有方法调用
class Person(object):
def __init__(self, name, age):
self.name = name
self.__age = age
def get_age(self):
return self.__age
def set_age(self, age):
self.__age = age
if __name__ == '__main__':
Tony = Person('Tony', 25)
print(Tony.get_age()) # 25
Tony.set_age(18)
print(Tony.get_age()) # 18
私有方法
:类的方法前面加了双下划线,则为私有方法,只能在类的内部使用,或在外部通过共有方法间接使用
公有方法
:类的方法没有双下划线,则为公有方法,即可以在类内使用,也可以在类外使用
class Person(object):
def __init__(self, name, age):
self.name = name
self.__age = age
def get_age(self):
self.__show_age()
def __show_age(self):
print(self.__age)
if __name__ == '__main__':
Tony = Person('Tony', 25)
Tony.get_age() # 25
4. 类的继承与改写
4.1 继承属性与函数
是否继承 | |
---|---|
公有函数 | 继承 |
私有函数 | 不继承 |
公有属性 | 视情况 |
私有属性 | 不继承 |
子类可以继承父类的公有方法,但不能继承私有方法,能否继承属性,得具体看情况
继承不获取父类属性
:子类提供init方法后,子类实例化对象时,就会调用子类自己的init初始化方法,就不会调用父类的init方法,这时没有父类的属性(这里继承了name属性,没有继承num/__age属性)
class A(object):
name = "Tony" # 继承
def __init__(self):
self.num = 10
self.__age = 18
class B(A): # B继承A
def __init__(self): # 提供init方法,则不继承父类的init方法,则没有父类的num属性
self.age = 18
if __name__ == '__main__':
a = B() # 使用a.num报错
继承获取父类属性
:如果想要得到父类init中定义的属性,需要执行父类的init方法(父类名.init(
)或super().init()
)(继承了num属性,没有继承__age属性)
class A(object):
name = "Tony" # 继承
def __init__(self, num):
self.num = num # 公有属性 继承
self.__age = 18
class B(A): # B继承A
def __init__(self, num, age):
A.__init__(self, num) # 获取父类属性 继承num属性
self.age = age
if __name__ == '__main__':
a = B(10, 18)
print(a.num)# 可以使用a.num
4.2 多重多继承
如下代码为多层次继承模式
# 父类
class A(object):
def __init__(self):
print('a class')
# 子类
class B(A):
def __init__(self):
A.__init__(self)
print('b class')
class C(A):
def __init__(self):
A.__init__(self)
print('c class')
class D(B, C):
def __init__(self):
B.__init__(self)
C.__init__(self)
print('d class')
# d拥有A类B类和C类的属性和方法
# 这里A类输出会打印多次,这个问题可以在super方法解决
d = D()
'''
a class
b class
a class
c class
d class
'''
上面代码可以看出,类A初始化中的输出被调用了多次,要避免该方法,继承时可以使用super方法
4.3 super()函数(减少反复继承初始化)
在多继承时,使用super方法可以减少父类被多次初始化的次数
class A(object):
def __init__(self):
print('a class')
class B(A):
def __init__(self):
super(B, self).__init__() # 简化格式:super().__init__()
print('b class')
class C(A):
def __init__(self):
super(C, self).__init__() # super().__init__()
print('c class')
class D(B, C):
def __init__(self):
super(D, self).__init__() # super().__init__()
print('d class')
# super方法解决A类输出会打印多次问题
d = D()
'''
a class
c class
b class
d class
'''
super方法还可以用来调用父类的方法,代码如下:
class A(object):
def print_num(self):
print("hello")
class B(A): # B继承A
def print_num(self):
super().print_num() # 执行父类方法
print("world")
if __name__ == '__main__':
a = B()
a.print_num()
4.4 继承中mro与函数调用顺序
类的继承书写顺序会影响mro顺序
class A(object):
pass
class B(A):
pass
class C(A):
pass
# class D(B, C): # (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
# pass
class D(C, B):
pass
print(D.__mro__)
# (<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
多重多继承时,方法的查找顺序也参考MRO
class A(object):
def show(self):
print('A show')
def info(self):
print('A info')
class B(A):
def show(self):
print('B show')
def info(self):
print('B info')
class C(A):
def show(self):
print('C show')
class D(C, B):
def show(self):
print('D show')
d = D()
# 优先找D里面的,如果没有,则找C里面,如果没有,再找B里面,都没有,则找A里面
d.show() # D show
# 优先找D里面的,如果没有,则找C里面,如果没有,再找B里面,都没有,则找A里面
d.info() # B info
'''
# 如果要在找完C之后直接找A,可以在C类里面添加内容
class C(A):
def show(self):
super().info() # 或A.info()
print('C show')
'''
4.5 父类的重写与调用
如下代码为在子类中对父类进行改写,函数名相同,调用时则执行子类的函数
class A(object):
def print_num(self):
print("hello")
class B(A): # B继承A
def print_num(self):
print("world")
if __name__ == '__main__':
a = B()
a.print_num() # world
如果要在改写父类的同时执行父类的方法,可以在改写的方法里面执行父类的方法
class A(object):
def print_num(self):
print("hello")
class B(A): # B继承A
def print_num(self):
A.print_num(self) # 执行父类方法 或 super().print_num()
print("world")
if __name__ == '__main__':
a = B()
a.print_num()
5. 多态、类方法
多态
:调用一个方法时,得到的结果不同,多态是由继承类实现的(闯入参数不同,输出不同)
class A(object):
def show(self):
print('A show')
class B(object):
def show(self):
print('B show')
class C(object):
def info(self, a):
a.show()
c = C()
c.info(A()) # A show
c.info(B()) # B show
类方法
:类方法中不能使用self,但可以使用cls(用来表示当前类对象,这个参数是自动传递的,可用于类属性)。一般设计类的时候,如果有类方法,这个类一般不会实例化对象,直接使用类对象来操作(如:数学函数类),一般用来定义工具类的使用
class Mymath(object):
@classmethod # 修饰器,用来表示是一个类方法
def sum(cls, *args):
total = 0
for arg in args:
total += arg
return total
print(Mymath.sum(1,2,3,4))
'''
上面show前面没有@classmethod,使用Mymath.show()会报错
只能使用Mymath.show(MyMath)
'''
静态方法
:静态方法其实就是对普通方法使用类进行整合(普通函数一样,只是在类内)
class MyMath(object):
# 定义类属性
n = 10
# 标准格式
@staticmethod
def sum(data):
print(MyMath.n, data)
a = MyMath()
a.sum('abc') # 10 abc
MyMath.sum('abc') # 10 abc
6. 模块导入
6.1 导入文件
一个py文件就是一个模块,当在一个py文件中要使用另一个py文件时,需要在这个py文件里面导入另一个py文件(即导入模块)
自定义模块函数test.py
n = 1
def show():
print('show')
class Cat(object):
def show(self):
print('Cat show')
main.py使用import导入自定义模块
# 导入模块式会执行模块内的所有代码
import test
test.show() # show
a = test.Cat()
a.show() # Cat show
或者在main.py中使用from import导入自定义模块
from test import n
from test import Cat
from test import show
# from test import show, as, sh
# from test import *
print(n) # 1
show()
a = Cat() # show
a.show() # Cat show
导入模块常见问题
test.py
a = 1 # 全局变量,模块间的公有变量
_b = 2 # 私有变量,文件内的私有变量
__c = 3 # 私有变量,一般出现在类中
main.py中按如下方式导入可以输出
import test
print(test.a)
print(test._b)
print(test.__c)
如果使用下面方法,则会报错无法输出私有成员
from test import *
print(a)
# print(_b) # 报错
# print(__c) # 报错
可以使用__all__
修改from import导入规则,但是公有的会报错
# 一般不会在这里使用__all__属性
__all__ = ['_b', '__c']
a = 1
_b = 2
__c = 3
from test import *
# print(a) # 报错
print(_b)
print(__c)
命名冲突问题:当命名冲突的时候,后者会覆盖前者
test.py
a = 1
main.py
from test import *
def a():
print('hello')
return 0
# 这里调用的是这里的a函数,而不是test类中的变量a
print(a)
'''
# 可以使用import解决冲突
import test
def a():
print('hello')
return 0
print(test.a)
'''
6.2 导包路径问题
如果要导入其他位置的文件,需要将包所在的路径使用sys.path.append加入,在这下面导入该路径的包
import sys
sys.path.append(dir_path)
# import xxx
比如,导入某路径,该路径下的direc目录里面有文件a.py,内容如下
m = 1
则在main.py文件内容如下
import sys
sys.path.append("dir_path") # dir_path表示文件所在路径
# 导入direc中的a模块
import direc.a
print(direc.a.m)
'''
或者使用下面的方法导入
from direc import a
print(a.m)
或者
from direc.a import m
print(m)
或者
from direc.a import *
'''
7. property属性
property属性:把一个方法当做属性进行使用,这样做可以简化代码使用,定义property属性有两种方式:装饰器方式、类属性方式
类属性方式简化属性操作:可以使用属性的方式间接访问类的私有属性,简化操作(property
)
class Person(object):
def __init__(self):
self.__age = 0
self.__name = 'Jack'
# 当获取age属性的时候会执行该方法
def get_age(self):
return self.__age
# 当设置age属性的时候会执行该方法
def set_age(self, new_age):
self.__age = new_age
def set_name(self):
pass
def get_name(self):
pass
# 类属性方式的property属性
age = property(get_age, set_age)
name = property(get_name, set_name)
p = Person()
print(p.age) # 0
p.age = 20
print(p.age) # 20
装饰器方式:如果使用装饰器形式来简化属性操作时,@property
只能用来装饰 get 方法,被装饰的属性方法前面不需要在使用 set 或 get 做为前缀了
property一定写在对应的setter前面,否则报错
class Person(object):
def __init__(self):
self.__age = 0
self.__name = 'Jack'
# 当获取age属性的时候会执行该方法
@property
def age(self):
return self.__age
# 当设置age属性的时候会执行该方法
@age.setter
def age(self, new_age):
self.__age = new_age
@property
def name(self):
return self.__name
@name.setter
def name(self, username):
self.__name = username
p = Person()
print(p.age) # 0
p.age = 20
print(p.age) # 20
p.name = 'Jack'
print(p.name)
标签:__,python,self,魔法,class,print,方法,age,def
From: https://blog.csdn.net/weixin_46287157/article/details/141902965