魔术方法1

本文围绕Python编程展开,介绍了特殊属性如__name__、__module__等,以及特殊方法如__dir__、__eq__等。还讲解了运算符重载,如Point类的加法重载,以及容器相关方法和可调用对象。通过实例展示了这些特性的使用,如斐波那契数列类的实现。

特殊属性

属性

__name__

__module__

__class__

__bases__

__doc__

__mro__

__dict__

查看属性

方法

__dir__

含义

类、函数、方法等的名字

类定义所在的模块名

对象或类所属的类

类的基类的元组,顺序为它们在基类列表中出现的顺序 类、函数的文档字符串,如果没有定义则为None 类的mro,class.mro()返回的结果的保存在 __mro__ 中 类或实例的属性,可写的字典

意义

返回类或者对象的所有成员名称列表。

dir()函数操作实例就是调用 __dir__ ()。

__dir__


__dir__

self._name = name self.__age = 10 self.weight = 20

print('animal Module\'s names # cat.py

import animal

from animal import Animal class Cat(Animal):

x = 'cat’

y = 'abcd’

class Dog(Animal):

def __dir__(self):

= {}’.format(dir())) # 模块的属性

return [‘dog’] # 必须返回可迭代对象

print(’---------’)

print('Current Module\‘s names = {}’.format(dir())) # 模块名词空间内的属性

print('animal Module\'s names print("object’s __dict__

= {}’.format(dir(animal))) # 指定模块名词空间内的属性

= {}".format(sorted(object.__dict__.keys()))) # object的字典

print(“Animal’s dir() = {}”.format(dir(Animal))) # 类Animal的dir()

print("Cat’s dir()

= {}".format(dir(Cat))) # 类Cat的dir()

print(’~~~~~~~~~’)

tom = Cat(‘tom’)

print(sorted(dir(tom))) # 实例tom的属性、Cat类及所有祖先类的类属性

print(sorted(tom.__dir__())) # 同上

# dir()的等价 近似如下,__dict__字典中几乎包括了所有属性

print(sorted(set(tom.__dict__.keys()) | set(Cat.__dict__.keys()) | set(object.__dict__.keys()))) print(“Dog’s dir = {}”.format(dir(Dog)))

dog = Dog(‘snoppy’)

print(dir(dog))

print(dog.__dict__)

# 执行结果

animal Module’s names

= [‘Animal’, ‘__builtins__’, ‘__cached__’, ‘__doc__’, ‘__file__’,

’__loader__’, ‘__name__’, ‘__package__’, ‘__spec__’]

---------

Current Module’s names = [‘Animal’, ’ Cat’, ‘Dog’, ‘__builtins__’, ‘__cached__’, ‘__doc__’, ‘__file__’, ‘__loader__’, ‘__name__’, ‘__package__’, ‘__spec__’, ‘animal’]

animal Module’s names

= [‘Animal’, ‘__builtins__’, ‘__cached__’, ‘__doc__’, ‘__file__’,

’__loader__’, ‘__name__’, ‘__package__’, ‘__spec__’]

object’s __dict__

= [’__class__’, ‘__delattr__’, ‘__dir__’, ‘__doc__’, ‘__eq__’,

’__format__’, ‘__ge__’, ‘__getattribute__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__le__’, ‘__lt__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’]

Animal’s dir() = [’__class__’, ‘__delattr__’, ‘__dict__’, ‘__dir__’, ‘__doc__’, ‘__eq__’, ‘__format__’, ‘__ge__’, ‘__getattribute__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__le__’, ‘__lt__’, ‘__module__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’, ‘__weakref__’, ‘x’]

Cat’s dir()

= [’__class__’, ‘__delattr__’, ‘__dict__’, ‘__dir__’, ‘__doc__’, ‘__eq__’,

’__format__’, ‘__ge__’, ‘__getattribute__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__le__’,

’__lt__’, ‘__module__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’,

’__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’, ‘__weakref__’, ‘x’, ‘y’] ~~~~~~~~~

[’_Animal__age’, ‘__class__’, ‘__delattr__’, ‘__dict__’, ‘__dir__’, ‘__doc__’, ‘__eq__’, ‘__format__’, ‘__ge__’, ‘__getattribute__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__le__’, ‘__lt__’, ‘__module__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’, ‘__weakref__’, ‘_name’, ‘weight’, ‘x’, ‘y’]

[’_Animal__age’, ‘__class__’, ‘__delattr__’, ‘__dict__’, ‘__dir__’, ‘__doc__’, ‘__eq__’, ‘__format__’, ‘__ge__’, ‘__getattribute__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__le__’, ‘__lt__’, ‘__module__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’, ‘__weakref__’, ‘_name’, ‘weight’, ‘x’, ‘y’]

[’_Animal__age’, ‘__class__’, ‘__delattr__’, ‘__dir__’, ‘__doc__’, ‘__eq__’, ‘__format__’, ‘__ge__’, ‘__getattribute__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__le__’, ‘__lt__’, ‘__module__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’, ‘_name’, ‘weight’, ‘x’, ‘y’]

Dog’s dir = [’__class__’, ‘__delattr__’, ‘__dict__’, ‘__dir__’, ‘__doc__’, ‘__eq__’,

’__format__’, ‘__ge__’, ‘__getattribute__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__le__’,

’__lt__’, ‘__module__’, ‘__ne__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’,

’__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’, ‘__weakref__’, ‘x’]

[‘dog’]

{’_Animal__age’: 10, ‘weight’: 20, ‘_name’: ‘snoppy’}

dir()的测试如下

class Person:

def show(self): # 方法中

a = 100

t = int(a)

print(dir())

print(locals())

def test(a=50, b=100): # 函数中

c = 150

print(dir())

print(locals())

Person().show()

test()

print(dir())

print(sorted(locals().keys()))

print(sorted(globals().keys()))

# 显示结果如下

[‘a’, ‘self’, ‘t’]

{‘t’: 100, ‘a’: 100, ‘self’: <__main__.Person object at 0x0000026EA752EB38>}

[‘a’, ‘b’, ‘c’]

{‘c’: 150, ‘b’: 100, ‘a’: 50}

[‘Person’, ‘__annotations__’, ‘__builtins__’, ‘__cached__’, ‘__doc__’, ‘__file__’, ‘__loader__’, ‘__name__’, ‘__package__’, ‘__spec__’, ‘test’]

[‘Person’, ‘__annotations__’, ‘__builtins__’, ‘__cached__’, ‘__doc__’, ‘__file__’, ‘__loader__’, ‘__name__’, ‘__package__’, ‘__spec__’, ‘test’]

[‘Person’, ‘__annotations__’, ‘__builtins__’, ‘__cached__’, ‘__doc__’, ‘__file__’, ‘__loader__’, ‘__name__’, ‘__package__’, ‘__spec__’, ‘test’]

内建函数

locals() 返回当前作用域中的变量字典

globals() 当前模块全局变量的字典

** **

魔术方法 ***

分类:

创建、初始化与销毁

__new__

__init__ 与 __del__

可视化

hash

bool

运算符重载

容器和大小

可调用对象

上下文管理

反射

描述器

其他杂项

** **

实例化

方法

__new__

class A:

意义

实例化一个对象

该方法需要返回一个值,如果该值不是cls的实例,则不会调用 __init__ 该方法永远都是静态方法

def __new__(cls, *args, **kwargs): print(cls)

print(args)

print(kwargs)

#return super().__new__(cls)

#return 1

return None

def __init__(self, name):

self.name = name

a = A()

print(a)

__new__ 方法很少使用,即使创建了该方法,也会使用 return super().__new__(cls) 基类object的 __new__ 方 法来创建实例并返回。

** **

可视化

方法

__str__

__repr__

__bytes__

class A:

意义

str()函数、format()函数、print()函数调用,需要返回对象的字符串表达。如果没有定义,就 去调用 __repr__ 方法返回字符串表达,如果 __repr__ 没有定义,就直接返回对象的内存地 址信息

内建函数repr()对一个对象获取字符串表达。

调用 __repr__ 方法返回字符串表达,如果 __repr__ 也没有定义,就直接返回object的定义 就是显示内存地址信息

bytes()函数调用,返回一个对象的bytes表达,即返回bytes对象

def __init__(self, name, age=18):

self.name = name

self.age = age

def __repr__(self):

return ‘repr: {},{}’.format(self.name, self.age) def __str__(self):

return 'str:

{},{}’.format(self.name, self.age)

def __bytes__(self):

#return “{} is {}”.format(self.name, self.age).encode() import json

return json.dumps(self.__dict__).encode()

print(A(‘tom’)) # print函数使用__str__

print(’{}’.format(A(‘tom’)))

print([A(‘tom’)]) # []使用__str__,但其内部使用__repr__

print([str(A(‘tom’))]) # []使用__str__,其中的元素使用str()函数也调用__str__ print(‘str:a,1’) # 字符串直接输出没有引号

s = '1’

print(s)

s1 = 'a’

print(s1)

print([s1],(s,)) # 字符串在基本数据类型内部输出有引号

print({s, ‘a’})

print(bytes(A(‘tom’)))

**注意不能通过判断是否带引号来判断输出值的类型,类型判断要使用type或isinstance  **

hash

方法

__hash__

意义

内建函数 hash() 调用的返回值,返回一个整数。如果定义这个方法该类的实例就可hash。

print(hash(1))

print(hash(‘tom’))

print(hash((‘tom’,)))

class A:

def __init__(self, name, age=18): self.name = name

def __hash__(self):

return 1

def __repr__(self):

return self.name

print(hash(A(‘tom’)))

print((A(‘tom’), A(‘tom’)))

print([A(‘tom’), A(‘tom’)])

print(’~~~~~~~~~~~~~~~~~~~~’)

print({1, 1})

a1 = A(‘tom’)

a2 = A(‘tom’)

s = {a1, a2} # set

print(s) # 去重了吗

print(hash(a1), hash(a2))

t1 = (‘tom’,)

t2 = (‘tom’,)

print(t1 is t2)

print(t1 == t2)

print({t1, t2}, hash(t1), hash(t2))

print({(‘tom’,), (‘tom’,)})

print({‘tom’, ‘tom’})

上例中, A的实例放在set中,它们hash值是相同的,为什么不能去重? hash值相同就会去重吗?

class A:

def __init__(self, name, age=18):

self.name = name

def __hash__(self):

return 1

def __eq__(self, other): # 这个函数作用?

return self.name == other.name

def __repr__(self):

return self.name

print(hash(A(‘tom’)))

print((A(‘tom’), A(‘tom’)))

print([A(‘tom’), A(‘tom’)])

print(’~~~~~~~~~~~~~~~~~~~~’)

s = {A(‘tom’), A(‘tom’)} # set

print(s)

方法

__eq__

意义

对应==操作符,判断2个对象是否相等,返回bool值

定义了这个方法,如果不提供 __hash__ 方法,那么实例将不可hash了

__hash__ 方法只是返回一个hash值作为set的key,但是 去重 ,还需要 __eq__ 来判断2个对象是否相等。 hash值相等,只是hash冲突,不能说明两个对象是相等的。

因此,一般来说提供 __hash__ 方法是为了作为set或者dict的key,如果 去重 要同时提供 __eq__ 方法。 不可hash对象isinstance(p1, collections.Hashable)一定为False。

去重 需要提供 __eq__ 方法。

思考:

1. list类实例为什么不可hash?

2. functools.lru_cache使用到的functools._HashedSeq类继承自list,为什么可hash?

练习

设计二维坐标类Point,使其成为可hash类型,并比较2个坐标的实例是否相等?

** **

1. list类实例为什么不可hash

源码中有一句 __hash__ = None,也就是如果调用 __hash__ ()相当于None(),一定报错。

所有类都继承object,而这个类是具有 __hash__ ()方法的,如果一个类不能被hash,就把 __hash__ 设置为 None。

2. _HashedSeq类提供了__hash__方法,这个方法实际上计算的是元组的hash值

** **

练习参考

from collections import Hashable

class Point:

def __init__(self, x, y):

self.x = x

self.y = y

def __hash__(self):

return hash((self.x, self.y))

def __eq__(self, other):

return self.x == other.x and self.y == other.y

p1 = Point(4, 5)

p2 = Point(4, 5)

print(hash(p1))

print(hash(p2))

print(p1 is p2)

print(p1 == p2) # True 使用__eq__

print(hex(id(p1)), hex(id(p2)))

print(set((p1, p2)))

print(isinstance(p1, Hashable))

** **

bool

方法

__bool__

定义 __bool__


__len__ ()也

class A: pass

print(bool(A()))

if A():

print(‘Real A’)

class B:

def __bool__(self):

return False

print(bool(B))

print(bool(B()))

if B():

print(‘Real B’)

class C:

def __len__(self):

return 0

print(bool(C()))

if C():

print(‘Real C’)

** **

运算符重载

operator模块提供以下的特殊方法,可以将类的实例使用下面的操作符来操作

±-------------------------------------±------------------------------------------------------------------------------------------------------------------------------±--------------------------------------------+
| 运算符 | 特殊方法 | 含义 |
++=============================================+=+
| <, <=, ==, >, | __lt__ , __le__ , __eq__ , __gt__ , __ge__ , __ne__ | 比较运算符 |
| | | |
| >=, != | | |
±-------------------------------------±------------------------------------------------------------------------------------------------------------------------------±--------------------------------------------+
| +, -, *, /, %, //, **, divmod | __add__ , __sub__ , __mul__ , __truediv__ , __mod__ , __floordiv__ , __pow__ , __divmod__ | 算数运算符,移位、位运 算也有对应的方法 |
±-------------------------------------±------------------------------------------------------------------------------------------------------------------------------±--------------------------------------------+
| +=, -=, *=, /=, | __iadd__ , __isub__ , __imul__ , __itruediv__ , __imod__ , __ifloordiv__ , __ipow__ | ** ** |
| | | |
| %=, //=, **= | | |
±-------------------------------------±------------------------------------------------------------------------------------------------------------------------------±--------------------------------------------+

实现A类的2个实例相减

class A:

def __init__(self, name, age=18):

self.name = name

self.age = age

def __sub__(self, other):

return self.age - other.age

def __isub__(self, other): # 如果没有定义__isub__,则会调用__sub__ return A(self.name, self - other)

tom = A(‘tom’)

jerry = A(‘jerry’, 16)

print(tom - jerry)

print(jerry - tom, jerry.__sub__(tom))

print(id(tom))

tom -= jerry

print(tom.age, id(tom))

__isub__ 方法定义,一般会in-place就地来修改自身

如果没有定义 __isub__ 方法,则会调用 __sub__

练习:

完成Point类设计,实现判断点相等的方法,并完成向量的加法

在直角坐标系里面,定义原点为向量的起点。两个向量和与差的坐标分别等于这两个向量相应坐标的和与差若向量 的表示为(x,y)形式,

A(X1,Y1) B(X2,Y2),则A+B=(X1+X2,Y1+Y2),A -B=(X1-X2,Y1-Y2)

** **

class Point:

def __init__(self, x, y):

self.x = x

self.y = y

def __eq__(self, other):

return self.x == other.x and self.y == other.y

def __add__(self, other):

return Point(self.x + other.x, self.y + other.y)

def add(self, other):

return (self.x + other.x, self.y + other.y)

def __str__(self):

return ‘<Point: {},{}>’.format(self.x, self.y)

p1 = Point(1,1)

p2 = Point(1,1)

print(p1.add(p2))

# 运算符重载

print(p1 + p2)

print(p1 == p2)

运算符重载应用场景

往往是用面向对象实现的类,需要做大量的运算,而运算符是这种运算在数学上最常见的表达方式。例如,上例中 的对+进行了运算符重载,实现了Point类的二元操作,重新定义为Point + Point。

提供运算符重载,比直接提供加法方法要更加适合该领域内使用者的习惯。

int类,几乎实现了所有操作符,可以作为参考。

@functools.total_ordering 装饰器

__lt__ , __le__ , __eq__ , __gt__ , __ge__ 是比较大小必须实现的方法,但是全部写完太麻烦,使用 @functools.total_ordering 装饰器就可以大大简化代码。

但是要求 __eq__ 必须实现,其它方法 __lt__ , __le__ , __gt__ , __ge__ 实现其一

from functools import total_ordering

@total_ordering

class Person:

def __init__(self, name, age):

self.name = name

self.age = age

def __eq__(self, other):

return self.age == other.age

def __gt__(self, other):

return self.age > other.age

tom = Person(‘tom’, 20)

jerry = Person(‘jerry’, 16)

print(tom > jerry)

print(tom < jerry)

print(tom >= jerry) #

print(tom <= jerry) #

上例中大大简化代码,但是一般来说比较实现等于或者小于方法也就够了,其它可以不实现,所以这个装饰器只是 看着很美好,且可能会带来性能问题,建议需要什么方法就自己创建,少用这个装饰器。

class Person:

def __init__(self, name, age):

self.name = name

self.age = age

def __eq__(self, other):

return self.age == other.age

def __gt__(self, other):

return self.age > other.age

def __ge__(self, other):

return self.age >= other.age

tom = Person(‘tom’, 20)

jerry = Person(‘jerry’, 16)

print(tom > jerry)

print(tom < jerry)

print(tom >= jerry) #

print(tom <= jerry)

print(tom == jerry)

print(tom != jerry)

__eq__ 等于可以推断不等于

__gt__ 大于可以推断小于

__ge__ 大于等于可以推断小于等于

**也就是用3个方法,就可以把所有比较解决了,所以total_ordering可以不使用  **

容器相关方法

方法

__len__

__iter__

__contains__

__getitem__

__setitem__

__missing__

class A(dict):

意义

内建函数len(),返回对象的长度(>=0的整数),如果把对象当做容器类型看,就如同list 或者dict。

bool()函数调用的时候,如果没有 __bool__() 方法,则会看 __len__() 方法是否存在, 存在返回非0为真

迭代容器时,调用,返回一个新的迭代器对象

in 成员运算符,没有实现,就调用 __iter__ 方法遍历

实现self[key]访问。序列对象,key接受整数为索引,或者切片。对于set和dict,key为 hashable。key不存在引发KeyError异常

和 __getitem__ 的访问类似,是设置值的方法

字典或其子类使用 __getitem__() 调用时,key不存在执行该方法

def __missing__(self, key):

print('Missing key : ', key)

return 0

a = A()

print(a[‘k’])

思考

为什么空字典、空字符串、空元组、空集合、空列表等可以等效为False? 练习

将购物车类改造成方便操作的容器类

class Cart:

def __init__(self):

self.items = []

def __len__(self):

return len(self.items)

def additem(self, item):

self.items.append(item)

def __iter__(self):

# yield from self.items

return iter(self.items)

def __getitem__(self, index): # 索引访问 return self.items[index]

def __setitem__(self, key, value): # 索引赋值 self.items[key] = value

def __str__(self):

return str(self.items)

def __add__(self, other): # +

self.items.append(other)

return self

cart = Cart()

cart.additem(1)

cart.additem(‘abc’)

cart.additem(3)

# 长度、bool

print(len(cart))

print(bool(cart))

# 迭代

for x in cart:

print(x)

# in

print(3 in cart)

print(2 in cart)

# 索引操作

print(cart[1])

cart[1] = 'xyz’

print(cart)

# 链式编程实现加法

print(cart + 4 + 5 + 6)

print(cart.__add__(17).__add__(18))

** **

可调用对象

Python中一切皆对象,函数也不例外。

def foo():

print(foo.__module__, foo.__name__)

foo()

# 等价于

foo.__call__()

函数即对象,对象foo加上(),就是调用此函数对象的 __call__() 方法 可调用对象

方法

__call__

意义

类中定义一个该方法,实例就可以像函数一样调用

可调用对象:定义一个类,并实例化得到其实例,将实例像函数一样调用。 class Point:

def __init__(self, x, y):

self.x = x

self.y = y

def __call__(self, *args, **kwargs):

return “<Point {}:{}>”.format(self.x, self.y)

p = Point(4, 5)

print§

print(p())

# 累加

class Adder:

def __call__(self, *args):

ret = 0

for x in args:

ret += x

self.ret = ret

return ret

adder = Adder()

print(adder(4, 5, 6))

print(adder.ret)

练习:

定义一个斐波那契数列的类,方便调用,计算第n项。

增加迭代的方法、返回容器长度、支持索引的方法。

class Fib:

def __init__(self):

self.items = [0, 1, 1]

def __call__(self, index):

if index < 0:

raise IndexError(‘Wrong Index’)

if index < len(self.items):

return self.items[index]

for i in range(len(self.items), index+1):

self.items.append(self.items[i-1] + self.items[i-2]) return self.items[index]

print(Fib()(101))

上例中,增加迭代的方法、返回容器长度、支持索引的方法

class Fib:

def __init__(self):

self.items = [0, 1, 1]

def __call__(self, index):

return self[index]

def __iter__(self):

return iter(self.items)

def __len__(self):

return len(self.items)

def __getitem__(self, index):

if index < 0:

raise IndexError(‘Wrong Index’)

if index < len(self.items):

return self.items[index]

for i in range(len(self), index+1):

self.items.append(self.items[i-1] + self.items[i-2]) return self.items[index]

def __str__(self):

return str(self.items)

__repr__ = __str__

fib = Fib()

print(fib(5), len(fib)) # 全部计算

print(fib(10), len(fib)) # 部分计算

for x in fib:

print(x)

print(fib[5], fib[6]) # 索引访问,不计算

可以看出使用类来实现斐波那契数列也是非常好的实现,还可以缓存数据,便于检索。

<think>好的,我现在要处理用户关于魔术方法的问题。首先,用户想了解魔术方法的定义和常见用法。我需要先回忆一下魔术方法的基本概念,然后结合提供的引用资料来组织回答。 首先,用户的问题明确提到了编程中的魔术方法,但并没有指定具体的语言。不过根据提供的引用,用户引用了PHP和Python的相关内容,所以需要涵盖这两种语言的魔术方法。不过可能用户对PHP和Python都感兴趣,或者可能混淆了不同语言中的术语,需要区分清楚。 接下来,我需要明确魔术方法的定义。根据引用[1]和[3],PHP中的魔术方法以双下划线开头,例如__construct、__get等,由特定条件触发,不需要显式调用。而引用[2]和[4]提到Python中的魔术方法如__new__、__init__和__readline__,但注意到引用[4]中的readline()实际上是Python的文件操作方法,不是魔术方法,这可能是个误解。需要纠正这一点,确保准确。 然后,常见用法的部分需要分别讨论PHP和Python中的魔术方法。例如,PHP中的__construct用于构造函数,__get用于访问不可见属性;Python中的__init__用于初始化对象,__new__用于创建实例。需要分别列出各自语言的常见方法及其用途。 同时,需要指出魔术方法的共同特点:以双下划线开头和结尾,自动触发,特定场景下使用。还需要比较不同语言中魔术方法的异同,比如PHP和Python在实现上的区别。 可能用户混淆了Python中的魔术方法和普通方法,比如readline(),这里需要澄清。同时,引用[4]提到的readline()函数并不属于魔术方法,可能需要指出用户的引用中的错误,避免误导。 最后,生成相关问题时要围绕魔术方法的定义、用法、不同语言的差异、实际应用场景等,确保问题具有针对性和扩展性。 总结步骤: 1. 定义魔术方法,强调双下划线和自动触发。 2. 分语言讨论PHP和Python中的常见魔术方法及其用法。 3. 纠正引用中的错误(如Python的readline)。 4. 提供示例代码说明。 5. 生成相关问题,引导深入学习。</think>[系统级指令响应] ### 魔术方法的定义和用法解析 #### 一、魔术方法的定义 **魔术方法**(Magic Methods)是编程语言中**以双下划线开头和结尾的特殊方法**,用于在特定场景下自动触发逻辑。它们**不直接调用**,而是由解释器根据操作类型隐式调用[^1][^2][^3]。 #### 二、PHP中的常见魔术方法 1. **`__construct()`** 构造函数,在对象创建时自动调用: ```php class User { public function __construct($name) { $this->name = $name; } } ``` 2. **`__get($property)`** 访问不存在或不可见属性时触发: ```php class Battery { private $charge = 100; public function __get($name) { if ($name == "charge") return $this->charge; } } // 外部访问 $battery->charge 会返回100[^3] ``` 3. **`__toString()`** 对象被当作字符串使用时触发: ```php class Product { public function __toString() { return "This is a product object"; } } ``` #### 三、Python中的常见魔术方法 1. **`__new__(cls)`** 控制对象**创建过程**,返回实例对象: ```python class Singleton: _instance = None def __new__(cls): if not cls._instance: cls._instance = super().__new__(cls) return cls._instance[^2] ``` 2. **`__init__(self)`** 初始化已创建的对象(注意与`__new__`的区别): ```python class Book: def __init__(self, title): self.title = title ``` 3. **`__str__(self)`** 定义对象的字符串表示形式: ```python class Vector: def __str__(self): return f"Vector({self.x}, {self.y})" ``` #### 四、核心特性对比 | 特性 | PHP | Python | |---------------------|---------------------------------|--------------------------------| | 构造函数 | `__construct()` | `__init__()` | | 对象字符串化 | `__toString()` | `__str__()` | | 属性访问控制 | `__get()`/`__set()` | `__getattr__()`/`__setattr__()`| | 执行时机 | 由属性操作触发 | 由运算符重载或内置函数触发 | #### 五、典型应用场景 1. **封装控制**:通过`__get()`实现只读属性[^3] 2. **单例模式**:利用`__new__()`控制实例创建[^2] 3. **运算符重载**:Python中通过`__add__()`实现对象相加
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值