Python魔术方法

什么是魔术方法?

所有以双下划线__包起来的方法,统称为Magic Method(魔术方法) ,它是一种的特殊方法,普通方法需要调用,而魔术方法不需要显示调用就可以执行。

魔术方法在类或对象的某些事件出发后会自动执行,让类具有神奇的"魔力"。如果希望根据自己的程序定制自己特殊功能的类,那么就需要对这些方法进行重写。

常见的魔术方法

init(self)

初始化方法

触发机制:实例化对象之后立即触发

参数:至少有一个self,接收当前对象,其他参数根据需要进行定义

返回值:无

作用:初始化对象的成员

python 复制代码
# __init__示例
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

p = Point(1, 2)
print(p.x, p.y)  # 输出: 1 2

new(cls)

构造方法

触发时机: 实例化对象时自动触发(在__init__之前触发)

参数:至少一个cls 接收当前类,其他参数根据初始化方法参数决定

返回值:必须返回一个对象实例,没有返回值,则实例化对象的结果为None

作用:实例化对象

注意:实例化对象是Object类底层实现,其他类继承了Object的__new__才能够实现实例化对象。

python 复制代码
class Person(object):
    def __init__(self):
        print('__init__(): 我也被调用啦~')

    def __new__(cls, *args, **kwargs):  # 重写后,不再创建对象
        print('__new__(): 哈哈我被调用啦~')


>>> per = Person()
__new__(): 哈哈我被调用啦~
>>> print(per)
None

class Person(object):
    def __init__(self):
        print('__init__(): 我也被调用啦~')

    def __new__(cls, *args, **kwargs): 
        print('__new__(): 哈哈我被调用啦~')
        ret = super().__new__(cls)  # 调用父类object的__new__方法创建对象
        return ret


>>> per = Person()
__new__(): 哈哈我被调用啦~
__init__(): 我也被调用啦~
>>> print(per)
<__main__.Person object at 0x0000020FA3892848>
python 复制代码
class Test:
    def __new__(cls, *args, **kwargs):
        print("我是__new__方法")
        obj = object.__new__(cls)
        print(obj)
        return obj

    def __init__(self):
        print(self)
        print("我是__init__方法")


if __name__ == '__main__':
    a = Test()
    
-------输出结果---------
我是__new__方法
<__main__.Test object at 0x123902f70>
<__main__.Test object at 0x123902f70>
我是__init__方法

上面示例会发现:

1)__new__魔术方法返回的就是self的内存地址;

2)如果不在__new__方法里面调object的__new__方法就不会创建对象,__init__不会被执行;

3)如果不在__new__方法里面return创建好的对象,__init__不会被执行;

事实上,当我们理解了new方法后,我们还可以利用它来做一些其他有趣的事情,比如实现 设计模式中的 单例模式(singleton)

依照Python官方文档的说法,new方法主要是当你继承一些不可变的class时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径。还有就是实现自定义的metaclass

这个方法我们一般很少定义,不过我们在一些开源框架中偶尔会遇到定义这个方法的类。实际上,这才是"真正的构造方法",它会在对象实例化时第一个被调用,然后再调用init,它们的区别主要如下:

  • new 的第一个参数是cls,而init的第一个参数是self
  • new 返回值是一个实例,而init没有任何返回值,只做初始化操作
  • new由于是返回一个实例对象,所以它可以给所有实例进行统一的初始化操作

由于new 优先于init调用,且返回一个实例,所以我们可以利用这种特性,每次返回同一个实例来实现一个单例类:

del(self)

析构方法

触发时机:当该类对象被销毁时,自动触发

参数:一个self,接受当前对象

返回值:无

作用:关闭或释放对象创建时资源

注意:del不一定会触发当前方法,只有当前对象没有任何变量引用时才会触发

python 复制代码
class Cat:
    def eat(self):
        print("我嘎嘎能吃")

    def __del__(self):
        print("ohohoh,我被销毁了")

print("<=======start======>")
cat1 = Cat()
print("<=======ends======>")

'''
<=======start======>
<=======ends======>
ohohoh,我被销毁了
'''

出现上面现象的原因是在没有手动执行del的情况下,程序执行结束后自动触发析构方法。

继续,现在加一个实例化,并且我们delcat1:

python 复制代码
cat1 = Cat()
cat2 = cat1
print("<=======start======>")
del cat1
print("<=======ends======>")

'''
<=======start======>
<=======ends======>
ohohoh,我被销毁了
'''

既然我们在start与end中间删除了cat1,为啥程序还是在执行完后触发析构方法?这主要是因为cat2还在继续占用cat1的内存地址,所以会在cat2执行完毕后触发析构方法。

只要同时删除cat1和cat2,内存地址没有指向的值,这块内存被释放就会触发析构方法:

python 复制代码
cat1 = Cat()
cat2 = cat1
print("<=======start======>")
del cat1
del cat2
print("<=======ends======>")

'''
<=======start======>
ohohoh,我被销毁了
<=======ends======>
'''

call(self)

可调用对象魔术方法

触发时机:将对象当作函数调用时触发,方式: 对象()

参数:至少一个self接收对象,其余根据调用时参数决定

返回值:根据情况而定

作用:可以将复杂的步骤进行合并操作,减少调用的步骤,方便使用

注意:无

python 复制代码
class A(object):
    def __call__(self, *args, **kwargs):
        print('call....')


a = A()
a()  # 自动调用__call__()

class Fibonacci(object):
    def __call__(self, num):
        a, b = 1, 1
        lst = []
        if num <= 2:
            lst.append(a)
            lst.append(b)
        else:
            for i in range(num):
                lst.append(a)
                a, b = b, a + b
        return lst


>>> f = Fibonacci()
>>> print(f(5))
[1, 1, 2, 3, 5]

str(self)

需要对象转换为string时,python都会默认调用该魔法方法,如print的时候,与字符串进行+运算的时候,凡是需要进行隐示类型转换为字符串的地方,都会自动调用该方法。该方法返回一个字符串:

python 复制代码
class Dog(object):
    def __init__(self,name):#self 是对象
        #对象.属性名 = 属性值
        self.name = name

    def __str__(self):
        #必须返回一个字符串
        return f"小狗的名字是{self.name}"
dog1 = Dog('aha')

print(dog1)
#str = 'Hello!' + dog1; #会提示TypeError
str = 'Hello!' + str(dog1);
print(f'{str=}')

'''
小狗的名字是aha
str='Hello!小狗的名字是aha'
'''

repr(self)

函数str() 用于将值转化为适于人阅读的形式,而repr() 转化为供解释器读取的形式,某对象没有适于人阅读的解释形式的话,str() 会返回与repr(),所以print展示的都是str的格式。

我们经常会直接输出类的实例化对象.

python 复制代码
class Coo:
    def __init__(self):
        self.name = ""
        self.add = "python.org"
    def __repr__(self):
        return "[name="+ self.name +",add=" + self.add +"]"
co = Coo()
print(co)

'''
[name=,add=python.org]
'''

由此可见,repr() 方法是类的实例化对象用来做"自我介绍"的方法,默认情况下,它会返回当前对象的"类名+object at+内存地址",而如果对该方法进行重写,可以为其制作自定义的自我描述信息。

__repr____str__这两个方法都是用于显示的,__str__是面向用户的,而__repr__面向程序员。

  • 打印操作会首先尝试__str__和str内置函数(print运行的内部等价形式),它通常应该返回一个友好的显示。
  • __repr__用于所有其他的环境中:用于交互模式下提示回应以及repr函数,如果没有使用__str__,会使用print和str。它通常应该返回一个编码字符串,可以用来重新创建对象,或者给开发者详细的显示。

当我们想所有环境下都统一显示的话,可以重构__repr__方法;当我们想在不同环境下支持不同的显示,例如终端用户显示使用__str__,而程序员在开发期间则使用底层的__repr__来显示,实际上__str__只是覆盖了__repr__以得到更友好的用户显示。

python 复制代码
# __str__和__repr__示例
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return f"{self.name} is {self.age} years old"

    def __repr__(self):
        return f"Person('{self.name}', {self.age})"

p = Person("Alice", 25)
print(str(p))  # 输出: Alice is 25 years old
print(repr(p))  # 输出: Person('Alice', 25)

del(self)

析构函数,对象在内存中被销毁删除的时候会自动调用__del__ 方法。

会在以下两个场景被调用:

1、程序代码运行结束,在程序运行过程中,创建的所有对象和变量都会被删除销毁

2、使用del变量,将这个对象的引用计数变为0,会自动调用del方法

python 复制代码
class Star(object):
    def __init__(self, name, movie):
        self.name = name  # 成员属性 明星姓名
        self.movie = movie  # 成员属性 明星的电影

    # 成员方法
    def playing(self):
        print(f"{self.name} 出演了电影 {self.movie} !")

    def __str__(self):
        # 打印对象时显示,
        return f"{self.name} 是我的偶像,我非常喜欢他的电影 {self.movie}"

    def __del__(self):
        # 删除对象时显示
        print(f"我现在不喜欢 {self.name} 了")


s1 = Star('周星驰', '大话西游')
print(s1)
del s1
s2 =Star('周慧敏', '赌圣风云')
print(s2)
print('---game over---')

'''
周星驰 是我的偶像,我非常喜欢他的电影 大话西游
我现在不喜欢 周星驰 了
周慧敏 是我的偶像,我非常喜欢他的电影 赌圣风云
---game over--
我现在不喜欢 周慧敏 了
'''

len(self)

len(obj)函数调用时,对象会自动调用__len()__方法

python 复制代码
import collections
card = collections.namedtuple('card', ["rank", 'suit'])
class FrenchDeck:
    ranks = [ str(n) for n in range(2, 11)] + list("JQKA")
    suits = 'spades diamonds clubs hearts'.split()

    def __init__(self):
        self._cards = [card(rank, suit) for suit in self.suits for rank in self.ranks]

    def __len__(self):
        return len(self._cards)


fd = FrenchDeck()
print('len(fd)=', len(fd))   # 可以直接使用len函数查看fd对象的长度 52

getitem(self,item)

拥有此方法的对象可以通过的使用列表的形式进行对象操作,如:切片,下标取值.

python 复制代码
import collections
card = collections.namedtuple('card', ["rank", 'suit'])
class FrenchDeck:
    ranks = [ str(n) for n in range(2, 11)] + list("JQKA")
    suits = 'spades diamonds clubs hearts'.split()

    def __init__(self):
        self._cards = [card(rank, suit) for suit in self.suits for rank in self.ranks]

    def __len__(self):
        return len(self._cards)

    def __getitem__(self, item):
        return self._cards[item]


fd = FrenchDeck()
print('fd[0]=', fd[0])  # 可以直接使用下表取值
for i in range(0, len(fd)):
    print(fd[i])

特别注意,虽然可以通过循环的形式取出对象中值,但并不代表它是一个可迭代对象,即使你在方法中返回的是字符串也可以循环,不过字符串循环会一直无限循环下去,直到你手动停止。主要原因是,因为在使用Obj[key]时,python解释器自动帮你调用了__getitem__(self,item)方法,所以只要不使用item这个参数,无论你传什么参数都不会报错,返回什么值是有你决定的.

python 复制代码
>>> isinstance(fd, collections.Iterable)
False

cmp(self,other)

用实例自身self和传入的实例other进行比较,如果self应该排在前面,就返回 -1,如果other应该排在前面,就返回1,如果两者相当,返回 0。

最后可以用list.sort函数或者sorted函数来实现排序。

python 复制代码
class Student(object):
    def __init__(self):
        self.grade = 0
    def __cmp__(self,other):
        if self.grade<other.grade:
            return -1
        elif self.grade>other.grade:
            return 1
        else:
            return 0

bool(self)

触发时机: 使用bool(对象)的时候触发

参数:一个self接收对象

返回值:必须是布尔值

作用:根据实际情况决定,可以作为快捷方式使用

注意:仅适合于返回布尔值的操作

python 复制代码
class A:
    print("__bool__和__len__都未定义,bool调用恒为True")

print(bool(A()))
#__bool__和__len__都未定义,bool调用恒为True
#True

class B:
    def __bool__(self):
        print("__bool__返回False,bool调用恒为False")
        return False

print(bool(B()))
#__bool__返回False,bool调用恒为False
#False


class C:
    def __len__(self):
        print("__bool__未定义,找到__len__,__len__返回值非0,bool调用恒为True")
        return 1


print(bool(C()))
#__bool__未定义,找到__len__,__len__返回值非0,bool调用恒为True
#True

# 定义空字典
a = {}
# 定义空列表
b = []
# 定义空元组
c = ()

# 以后判断这个3种数据类型是否有返回值直接通过bool方法来判断
if not bool(a):
    print("a为空字典")

if not bool(b):
    print("b为空列表")

if not bool(c):
    print("c为空元组")

'''
a为空字典
b为空列表
c为空元组
'''

format(self)

触发时机:使用字符串.format(对象)时候触发

参数:一个self接收对象,一个参数接收format的{}中的格式,例如:>5

返回值:必须是字符串

作用:设置对象可以作为format的参数,并且自定义对象格式化的规则

注意:无

hash(self)

调用hash函数时

python 复制代码
class A:
    def __init__(self):
        self.a = 'a'
        self.b = 'b'

    def __hash__(self):
        return 1


print(hash(A())) #1
print(hash(A())) #1


class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __hash__(self):
        return hash((self.name, self.age))

    def __eq__(self, other):
        if isinstance(other, Person):
            return self.name == other.name and self.age == other.age
        return False


# 创建对象
person1 = Person("John", 30)
person2 = Person("Alice", 25)

# 输出哈希值
print(f"对象person1的hash值 {hash(person1)}") #对象person1的hash值 2511066681118794660
print(f"对象person2的hash值 {hash(person2)}") #对象person2的hash值 -7352762741811000521

# 比较对象相等性
print(f"person1和person2相等是否成立  {person1 == person2}") #对象person2的hash值 -7352762741811000521

add(self,other)

实例只见的加法运算

python 复制代码
class Vector:
   def __init__(self, a, b):
      self.a = a
      self.b = b
 
   def __str__(self):
      return 'Vector (%d, %d)' % (self.a, self.b)
   
   def __add__(self,other):
      return Vector(self.a + other.a, self.b + other.b)
 
v1 = Vector(2,10)
v2 = Vector(5,-2)
print (v1 + v2)

'''
Vector(7,8)
'''

运算符魔术方法

|---------------------------------|---------------------------------------------------|
| 重载运算魔法函数定义 | 魔法函数说明 |
| add(self,other) | 实例之间的加法运算+ |
| sub(self,other) | 实例之间的减法运算- |
| mul(self,other) | 实例之间的乘法运算* |
| truediv(self,other) | 类与类之间的真除。只有from future import division之后它才有效/ |
| floordiv(self,other) | 类与类之间的浮点除法运算// |
| mod(self,other) | 类与类之间的取余运算% |
| pow(self,other[,module])) | 类与类之间的指数运算** |
| and(self,other) | 类与类之间的按位与运算& |
| xor(self,other) | 类与类之间的按位异或运算^ |
| or(self,other) | 类与类之间的按位或运算| |
| lt(self,other) | 定义了比较操作符< |
| gt(self,other) | 定义了比较操作符> |
| le(self,other) | 定义了比较操作符<= |
| ge(self,other) | 定义了比较操作符>= |
| eq(self,other) | 定义了比较操作符== |
| ne(self,other) | 定义了比较操作符!= |
| setitem(self, key, value) | 使用self[nkey] = value赋值容器中的一项 |
| delitem(self, key) | 删除self[nkey]。 |

例子:

python 复制代码
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)
    
    def __sub__(self, other):
        return Point(self.x - other.x, self.y - other.y)
    
    def __mul__(self, scalar):
        return Point(self.x * scalar, self.y * scalar)
    
    def __truediv__(self, scalar):
        return Point(self.x / scalar, self.y / scalar)
    
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

p1 = Point(1, 2)
p2 = Point(3, 4)

# 加法操作
p3 = p1 + p2
print(p3.x, p3.y) # 输出: 4, 6

# 减法操作
p4 = p1 - p2
print(p4.x, p4.y) # 输出: -2, -2

# 乘法操作
p5 = p1 * 2
print(p5.x, p5.y) # 输出: 2, 4

# 除法操作
p6 = p1 / 2
print(p6.x, p6.y) # 输出: 0.5, 1.0

# 等值比较操作
print(p1 == p2) # 输出: False
print(p1 == Point(1, 2)) # 输出: True



# __lt__和__eq__示例
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __lt__(self, other):
        return self.age < other.age

    def __eq__(self, other):
        return self.age == other.age

p1 = Person("Alice", 25)
p2 = Person("Bob", 30)
p3 = Person("Charlie", 25)
print(p1 < p2)  # 输出: True
print(p1 == p3)  # 输出: True

反运算魔术方法

反运算魔法方法,与算术运算符保持一一对应,不同之处就是反运算的魔法方法多了一个"r"。当文件左操作不支持相应的操作时被调用。

  • radd(self, other)定义加法的行为:+
  • rsub(self, other)定义减法的行为:-
  • rmul(self, other)定义乘法的行为:*
  • rtruediv(self, other)定义真除法的行为:/
  • rfloordiv(self, other)定义整数除法的行为://
  • rmod(self, other) 定义取模算法的行为:%
  • rdivmod(self, other)定义当被 divmod() 调用时的行为
  • divmod(a, b)把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a // b, a % b)。
  • rpow(self, other[, module])定义当被 power() 调用或 ** 运算时的行为
  • rlshift(self, other)定义按位左移位的行为:<<
  • rrshift(self, other)定义按位右移位的行为:>>
  • rand(self, other)定义按位与操作的行为:&
  • rxor(self, other)定义按位异或操作的行为:^
  • ror (self, other)定义按位或操作的行为:|
    a + b
    这里加数是a,被加数是b,因此是a主动,反运算就是如果a对象的__add__()方法没有实现或者不支持相应的操作,那么 Python 就会调用b的__radd__()方法。
python 复制代码
class Nint(int):
    def __add__(self, other):
        print('__add()__')
        return int.__add__(self, other)
    def __radd__(self, other):
        print('__radd()__')
        return int.__sub__(other, self) # 注意 self 在后面

a = Nint(5)
b = Nint(3)
print(a + b)  # 8
print('####')
print(1 + b)  # -2

'''
__add()__
8
####
__radd()__
-2
'''

赋值运算符魔术方法

  • iadd(self, other)定义赋值加法的行为:+=
  • isub(self, other)定义赋值减法的行为:-=
  • imul(self, other)定义赋值乘法的行为:*=
  • itruediv(self, other)定义赋值真除法的行为:/=
  • ifloordiv(self, other)定义赋值整数除法的行为://=
  • imod(self, other)定义赋值取模算法的行为:%=
  • ipow(self, other[, modulo])定义赋值幂运算的行为:**=
  • ilshift(self, other)定义赋值按位左移位的行为:<<=
  • irshift(self, other)定义赋值按位右移位的行为:>>=
  • iand(self, other)定义赋值按位与操作的行为:&=
  • ior(self, other)定义赋值按位或操作的行为:|=
  • ixor(self, other)定义赋值按位异或操作的行为:^=

一元运算符魔术方法

  • neg(self)定义正号的行为:+x
  • pos(self)定义负号的行为:-x
  • abs(self)定义当被abs()调用时的行为
  • invert(self)定义按位求反的行为:~x

属性访问魔术方法

__getattr __(self, name)

定义当用户试图获取一个不存在的属性时的行为。

触发时机:获取不存在的对象成员时触发

参数:一个是接收当前对象的self,一个是获取成员名称的字符串

返回值:必须有值

作用:为访问不存在的属性设置值

注意:getattribute无论何时都会在getattr之前触发,触发了getattribute就不会在触发getattr了

python 复制代码
class Base:
    n = 0
    
class Point(Base):
    z = 6
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def show(self):
        print(self.x, self.y)
        
    def __getattr__(self, item):
        return item
    
>>> p1.x
4
>>> p1.z
6
>>> p1.n
0
>>> p1.t
't'

实例属性会按照继承关系 寻找,如果找不到,就会执行__getattr__()方法,如果没有这个方法,就会抛出AttributeError异常标识找不到属性。

__getattribute __(self, name)

定义当该类的属性被访问时的行为(先调用该方法,查看是否存在该属性,若不存在,接着去调用__getattr__)

触发时机:使用对象成员时触发,无论成员是否存在

参数:1个接收当前对象self,一个是获取的成员的名称字符串

返回值:必须有

作用:在具有封装操作(私有化时),为程序开部分访问权限使用

python 复制代码
class Base:
    n = 0
    
class Point(Base):
    z = 6
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __getattr__(self, item):
        return item
    
    def __getattribute__(self, item):
        return item
     
>>> p1 = Point(4, 5)
>>> print(p1.__dict__)
__dict__
>>> print(p1.x)
x
>>> print(p1.z)
z
>>> print(p1.n)
n
>>> print(p1.t)
t
>>> print(Point.__dict__)
{'__module__': '__main__', 'z': 6, '__init__': <function Point.__init__ at 0x000001F5EB7063A8>, '__getattr__': <function Point.__getattr__ at 0x000001F5EB706558>, '__getattribute__': <function Point.__getattribute__ at 0x000001F5EB706168>, '__doc__': None}
>>> print(Point.z)
6

实例的所有的属性访问,第一个都会调用__getattribute__方法,它阻止了属性的查找,该方法应该返回值或者抛出一个AttributeError异常。

该方法的返回值将作为属性查找的结果。

如果抛出AttributeError异常,则会直接调用__getattr__方法,因为属性没有找到,__getattribute__方法中为了避免在该方法中无限递归,它的实现应该永远调用基类的同名方法以访问需要的任何属性。

需要注意的是,除非明确知道__getattrtbute__方法用来做什么,否则不要使用。

__setattr __(self, name, value)

定义当一个属性被设置时的行为

触发时机:设置对象成员值的时候触发

参数:1个当前对象的self,一个是要设置的成员名称字符串,一个是要设置的值

返回值:无 过程操作

作用:接管设置操作,可以在设置前之前进行判断验证等行为

注意:在当前方法中无法使用成员=值的方式直接设置成员,否则会无限递归,必须借助object的设置方法来完成

python 复制代码
class Base:
    n = 0
    
class Point(Base):
    z = 6
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def show(self):
        print(self.x, self.y)
        
    def __getattr__(self, item):
        return item
    
    def __setattr__(self, key, value):
        print(key, value)
        
# --------------------------------------------------
>>> p1 = Point(4, 5)
x 4
y 5
>>> print(p1.x)
x
>>> print(p1.z)
6
>>> print(p1.n)
0
>>> print(p1.t)
t
# --------------------------------------------------
>>> p1.x = 50
>>> print(p1.x)
x
>>> print(p1.__dict__)
{}
>>> p1.__dict__['x'] = 60
>>> print(p1.__dict__)
{'x': 60}
>>> p1.x
60

__delattr __(self, name)

定义当一个属性被删除时的行为

触发时机:删除对象成员时触发

参数:一个当前对象的self

返回值:无

作用:可以在删除成员时进行验证。

dir(self)

触发时机:dir(对象)的时候触发

参数:1个接收当前对象self

返回值:必须为序列类型(列表,元组,集合等,)

作用:可以自定义成员列表的返回值

例子

python 复制代码
class C:
    def __getattribute__(self, item):
        print('__getattribute__')
        return super().__getattribute__(item)

    def __getattr__(self, item):
        print('__getattr__')

    def __setattr__(self, key, value):
        print('__setattr__')
        super().__setattr__(key, value)

    def __delattr__(self, item):
        print('__delattr__')
        super().__delattr__(item)

c = C()
print('1-----')
c.x
# __getattribute__
# __getattr__
print('2-----')
c.x = 1
# __setattr__
print('3-----')
del c.x
# __delattr__

类型转换魔术方法

  • complex (self)定义当被 complex() 调用时的行为(需要返回恰当的值)
  • int(self) 定义当被 int() 调用时的行为(需要返回恰当的值)
  • float(self) 定义当被 float() 调用时的行为(需要返回恰当的值)
  • round(self[, n]) 定义当被 round() 调用时的行为(需要返回恰当的值)
  • index(self) 1. 当对象是被应用在切片表达式中时,实现整形强制转换
    1. 如果你定义了一个可能在切片时用到的定制的数值型,你应该定义 index
    1. 如果 index 被定义,则 int 也需要被定义,且返回相同的值

上下文相关的魔术方法

enter(self)

  1. 定义当使用 with 语句时的初始化行为

  2. enter 的返回值被 with 语句的目标或者 as 后的名字绑定

exit(self, exctype, excvalue, traceback)

  1. 定义当一个代码块被执行或者终止后上下文管理器应该做什么

  2. 一般被用来处理异常,清除工作或者做一些代码块执行完毕之后的日常工作

python 复制代码
# __enter__和__exit__示例
class DatabaseConnection:
    def __init__(self, db_url):
        self.db_url = db_url

    def __enter__(self):
        self.connection = open(self.db_url)
        return self.connection

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.connection.close()

# 使用 with 语句打开数据库连接,并在结束时自动关闭连接
with DatabaseConnection('example.db') as conn:
    # 执行一些操作
    cursor = conn.cursor()
    cursor.execute('SELECT * FROM users')
    rows = cursor.fetchall()
    print(rows)

容器相关的魔术方法

  • len(self) 定义当被 len() 调用时的行为(返回容器中元素的个数)
  • getitem(self, key) 定义获取容器中指定元素的行为,相当于 self[key]
  • setitem(self, key, value) 定义设置容器中指定元素的行为,相当于 self[key] = value
  • delitem(self, key) 定义删除容器中指定元素的行为,相当于 del self[key]
  • iter(self) 定义当迭代容器中的元素的行为
  • next(self)从iterable对象中获取下一个元素
  • reversed(self) 定义当被 reversed() 调用时的行为
  • contains(self, item) 定义当使用成员测试运算符(in 或 not in)时的行为
  • missing__字典使用__getitem()调用时,key不存在执行该方法
python 复制代码
# __getitem__和__setitem__示例
class MyList:
    def __init__(self, items):
        self.items = items

    def __getitem__(self, index):
        return self.items[index]

    def __setitem__(self, index, value):
        self.items[index] = value

l = MyList([1, 2, 3, 4])
print(l[2])  # 输出: 3
l[2] = 5
print(l[2])  # 输出: 5

# __contains__示例
class MyList:
    def __init__(self, items):
        self.items = items

    def __contains__(self, item):
        return item in self.items

l = MyList([1, 2, 3, 4])
print(2 in l)  # 输出: True
print(5 in l)  # 输出: False


# __iter__和__next__示例
class MyRange:
    def __init__(self, start, end):
        self.start = start
        self.end = end

    def __iter__(self):
        return self

    def __next__(self):
        if self.start >= self.end:
            raise StopIteration
        value = self.start
        self.start += 1
        return value

r = MyRange(0, 5)
for i in r:
    print(i)  # 输出: 0 1 2 3 4

魔法属性

doc

这是一个属性,获取类或对象内部文档。

python 复制代码
class MyClass():
    """
        我是一个类,这里说明一些有用的信息
    """

    def __init__(self):
        pass


print(MyClass.__doc__)
#        我是一个类,这里说明一些有用的信息

name

这也是一个属性,获取类名或函数名

python 复制代码
class Class1:
    pass


class MyClass:
    def task1(self, func1):
        print(func1.__name__)


def func():
    print("我是func1函数")


>>> obj = MyClass()
>>> obj.task1(func)
func
>>> obj.task1(Class1)
Class1

class

获取当前对象获取的类

python 复制代码
class Class1:
    pass


>>> obj = Class1()
>>> print(obj.__class__)
<class '__main__.Class1'>
>>> print(obj.__class__.__name__)
Class1

base

获取一个类直接继承的所有父类,返回元组。

python 复制代码
class Class1:
    pass


class Class2:
    pass


class MyClass(Class1, Class2):
    pass


>>> print(MyClass.__bases__)
(<class '__main__.Class1'>, <class '__main__.Class2'>)

dict

获取类或对象的的内部成员结构 。主要用来获取用户自定义的属性,以及这个属性对应的值。返回的是一个字典

python 复制代码
class MyClass():
    name1 = "Lsir"
    name2 = "Wsir"
    name3 = "Zsir"

    def task1(self):
        print("task1")

    def task2(self):
        print("tesk2")

    def task3(self):
        print("task3")


>>> print(MyClass.__dict__)
{'__module__': '__main__', 'name1': 'Lsir', 'name2': 'Wsir', 'name3': 'Zsir', 'task1': <function MyClass.task1 at 0x0000020C16385558>, 'task2': <function MyClass.task2 at 0x0000020C16385D38>, 'task3': <function MyClass.task3 at 0x0000020C16385708>, '__dict__': <attribute '__dict__' of 'MyClass' objects>, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__doc__': None}

dir函数做一个区分。dir函数返回的是这个对象上拥有的所有属性,包括Python内置的属性和用户自己添加的,并且只是获取属性名字,不会获取这个属性对应的值。

相关推荐
一点媛艺42 分钟前
Kotlin函数由易到难
开发语言·python·kotlin
姑苏风1 小时前
《Kotlin实战》-附录
android·开发语言·kotlin
奋斗的小花生2 小时前
c++ 多态性
开发语言·c++
魔道不误砍柴功2 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
闲晨2 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
_.Switch2 小时前
高级Python自动化运维:容器安全与网络策略的深度解析
运维·网络·python·安全·自动化·devops
老猿讲编程2 小时前
一个例子来说明Ada语言的实时性支持
开发语言·ada
Chrikk3 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*3 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue3 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang