首页 > 编程语言 >python类与魔法方法

python类与魔法方法

时间:2024-10-15 19:18:43浏览次数:3  
标签:__ python self 魔法 class print 方法 age def

文章目录

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 == ba.__eq__(b)b.__eq__(a)返回id(a) == id(b)
a != ba.__ne__(b)b.__ne__(b)返回not (a == b)
排序a > ba.__gt__(b)b.__gt__(a)抛出TypeError
a < ba.__lt__(b)b.__lt__(a)抛出TypeError
a >= ba.__ge__(b)b.__ge__(a)抛出TypeError
a <= ba.__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

相关文章

  • 去除 iPhone 设置右上角强制升级红色数字方法
    iPhone强制用户升级在设置右上角有红色数字提示,即使关闭了自动升级也清不掉。可以用快捷指令伪造一个设置的快捷方式来替代原生设置图标打开快捷指令,点击+新建快捷指令选择“打开App”点击App标签,选取“设置”然后点击当前正在创建的快捷指令顶端的“打开App”,自定......
  • 基于yolov8、yolov5的烟雾检测系统(含UI界面、训练好的模型、Python代码、数据集)
    项目介绍项目中所用到的算法模型和数据集等信息如下:算法模型:  yolov8、yolov8+SE注意力机制或yolov5、yolov5+SE注意力机制,直接提供最少两个训练好的模型。模型十分重要,因为有些同学的电脑没有GPU,无法自行训练。数据集:  网上下载的数据集,格式都已......
  • 【idea技巧篇】idea的类注释和方法注释模版自定义设置
    这块idea技巧虽然常用,谁没事会经常修改模版设置呢,一般是搭建开发环境的时候或者开发规范要求等设置一次就行了。用的虽然少,但几乎每次搭建环境都会用到,这里记录下并分享设置的过程已经发现的更高级的一些使用技巧。注释模版idea默认创建java文件时,是不会生成类注释的,但是......
  • js数组、字符串的那些方法
    一、数组方法arr.copyWithin(a,b,c)用数组部分覆盖数组中的某些内容,改变原数组内容但长度不变a:被覆盖的起始下标;b:复制开始下标(包含);c:复制结束下标(不包含)[1,2,3,4].copyWithin(1,2,3)//[1,3,3,4]arr.flatMap(function(t,i){})拍平数组,只能拍平一层t表示第二层的每......
  • python实现了通过摄像头检测手部动作,根据手指数量的不同映射为特定的视频控制操作
    importcv2#导入OpenCV库,用于图像处理importmediapipeasmp#导入MediaPipe库,用于手部检测等fromseleniumimportwebdriver#导入selenium库fromselenium.webdriver.common.keysimportKeysfromselenium.webdriver.common.byimportByfromselenium.webdrive......
  • Python学习流水账Day5——有关Python中的函数
    文章目录前言一、Python中的函数1.内置函数2.定义一个函数调用函数为函数设置参数实参形参给函数设置多个形参默认形参函数的返回值函数的变量局部变量全局变量3.匿名函数4.递归函数总结前言简单的python复习第五天:不是用来教学的,上班没劲,主打一个本科毕业没竞......
  • Win11如何设置双声道音效-Win11双声道音效的设置方法
    有一些用户在使用Windows11操作系统时,可能会希望调整音频设置以获得更好的听觉体验。其实双声道音效是一种常见的音频配置,它可以提供更加立体和丰富的音响效果。如果您想要在Windows11中设置双声道音效,以下是一些简单的步骤指导,一起看看吧。Win11双声道音效的设置方法......
  • 《统治者:罗马》游戏崩溃报错?解决《统治者:罗马》“An error has occured“崩溃问题的有
    《统治者:罗马》游戏崩溃报错,特别是出现"Anerrorhasoccured"这样的错误提示时,确实会让玩家感到困扰。以下是一些解决这一崩溃问题的有效方法:一、检查电脑配置确认配置要求:首先,确保你的电脑配置满足《统治者:罗马》的最低配置要求。如果配置不足,游戏可能会出现崩溃或运行不......
  • 集合Collection接口中的成员方法
    一、Collection集合的介绍:1.Collection是一个接口,List,Set是继承Collection接口的子接口2.当我们使用Collection的方法的时候,由于是一个接口不能直接new对象,可以通过其具体实现的子类来进行调用二、Collection的基本方法(6)1.booleanadd(Ee),可以传任意一个类型的元素进去2......
  • python实现主动学习【一】modAL example active_regression
    文章目录一、简要介绍二、代码运行2.1前期准备2.1.1关于sklearn.gaussian_process.kernels的小展开1.RBFKernel(RadialBasisFunction)2.WhiteKernel3.组合内核的原理4.在主动学习中的优势5.其他核函数的特点6.如何组合使用不同的核2.1.2关于ActiveLearner......