魔法函数

1.什么是魔法函数

在python中,有的名称以双下划线开头同时以双下划线结尾这种形式,
我们只知道它是python自己定义的,同时我们也不应该去定义类似的函数。

我们将“__init__”这种形式的函数成为魔法函数。"__init__"是构造器,用来初始化对象。
魔法函数不需要去显式的调用,同时魔法函数不能自定义。
魔法函数会被python隐式的去被调用。

举个简单的例子:
现在我们需要遍历对象中的属性,传统做法是取属性然后去遍历。

class Person(object):
    def __init__(self,p_list):
        self.p_list = p_list

person = Person(["ming","ke","mao"])

for em in person.p_list:
    print(em)

我们可以使用__getitem__来更简单的实现。
class NewPerson(object):
    def __init__(self,p_list):
        self.p_list = p_list

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

newPerson = NewPerson(["ming","kebi","mao"])
#这里就不需要取属性了。
for em in newPerson:
    print(em)

我们可以通过不添加__getitem__,来知道__getitem__是将对象转换成可迭代对象。
#‘NewPerson‘ object is not iterable
在python中,只有可迭代对象才可以进行遍历,而可迭代对象必须拥有item()或者__item__方法。
当python在进行循环的时候,会去看对象是否由item()方法,如果没有会去看是否与__getitem__魔法函数,否则就不能迭代。

2.python魔法函数对python语法的影响

魔法函数会影响python语法本身。

示例一:

class NewPerson(object):
    def __init__(self,p_list):
        self.p_list = p_list

newPerson = NewPerson(["ming","kebi","mao"])
print(len(newPerson))   #TypeError: object of type ‘NewPerson‘ has no len()
print(len(newPerson[:]))  #TypeError: ‘NewPerson‘ object is not subscriptable

对象没有长度和不能切片可以理解。

示例二:

class NewPerson(object):
    def __init__(self,p_list):
        self.p_list = p_list

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

newPerson = NewPerson(["ming","kebi","mao"])
print(len(newPerson))  #TypeError: object of type ‘NewPerson‘ has no len()
print(len(newPerson[:]))  #3

newPerson之所以能够切片是因为__getitem__返回的是一个list,而list肯定可以切片
newPerson在取值的时候调用了__gititem__这个魔法方法,从而返回list,所以newPerson[]有len

示例三:

class NewPerson(object):
    def __init__(self,p_list):
        self.p_list = p_list

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

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

newPerson = NewPerson(["ming","kebi","mao"])
print(len(newPerson))  #3  调用__len__
print(len(newPerson[:]))  #3  调用__getitem__

现在我们帮这个对象实现了__len__这个方法,所以这个newPerson对象可以可以直接使用len()
此时newPerson[:]因为是取值,依旧使用的是__getitem__这个方法。

3.魔法函数一览

使用dir()或者__dir__可以或者一个对象已经定义的的魔法函数。
例如:dir(Person)
__class__ 等同于type,打印对象类似
__delattr__
__dict__ 等同于vars,以键值对的形式返回对象的属性信息
__dir__
__doc__ 帮助文档
__eq__
__format__
__ge__
__getattribute__
__gt__
__hash__
__init__ 构造器
__init_subclass__
__le__
__lt__
__module__
__ne__
__new__
__reduce__
__reduce_ex__
__repr__
__setattr__
__sizeof__
__str__
__subclasshook__
__weakref__

我们将魔法方法分为:非数学运算和数学运算两大类

1)非数学运算

(1)字符串
__repr__
__str__

(2)集合序列相关
__len__
__getitem__:将当前对象转换为可迭代对象,因而可以切片。
__setitem__
__delitem__
__contains__

(3)迭代相关
__iter__
__next__

(4)可调用
__call__

(5)with上下文管理器
__enter__
__exit__

(6)数值转换
__abs__
__bool__
__int__
__float__
__hash__
__index__

(7)元类相关
__new__
__init__

(8)属性相关
__getattr__:没有属性做什么
__setattr__
__getattribute__
__setattribute__
__dir__

(9)属性描述符
__get__
__set__
__delete__

(10)协程
__await__
__aiter__
__anext__
__aenter__
__aexit__

2)数学运算

(1)一元运算符
__neg__ (-)
__pos__ (+)
__abs__

(2)二元运算符
__lt__ (<)
__le__ (<=)
__eq__ (==)
__ne__ (!=)
__gt__ (>)
__ge__ (>=)

(3)算术运算符
__add__ (+)
__sub__ (-)
__mul__ (*)
__truediv__ (/)
__floordiv__ (//)
__mod__ (%)
__divmod__ 或divmod()
__pow__ 或pow() (**)
__round__ 或round()

(4)反向算术运算符
__radd__
__rsub__
__rmul__
__rtruediv__
__rfloordiv__
__rmod__
__rdivmod__
__rpow__

(5)增量赋值算术运算符
__iadd__
__isub__
__imul__
__ifloordiv__
__ipow__

(6)位运算符
__invert__ (~)
__lshift__ (<<)
__rshift__ (>>)
__and__ (&)
__or__ (|)
__xor__ (^)

(7)反向位运算符
__rlshift__
__rrshift__
__iand__
__ixor__
__ior__

(8)增量赋值运算符
__ilshift__
__irshift__
__iand__
__ixor__
__ior__

3)__str__、__repr__

class Person(object):
    def __init__(self,p_list):
        self.p_list = p_list
person = Person(["ming","UZI","karsa"])
print(person)  #<__main__.Person object at 0x00000218983ACBE0>
print会隐式调用str,也就是__str__

现在可以修改一下__str__返回值。
class Person(object):
    def __init__(self,p_list):
        self.p_list = p_list

    def __str__(self):
        return ".".join(self.p_list)  #默认return self
person = Person(["ming","UZI","karsa"])
#本来是返回这个对象的内存地址,现在我们修改了返回值。
print(person)  #ming.UZI.karsa

class Person(object):
    def __init__(self,p_list):
        self.p_list = p_list

person = Person(["ming","UZI","karsa"])
person  #<__main__.Person at 0x218983b47b8>
隐式调用repr(person)

class Person(object):
    def __init__(self,p_list):
        self.p_list = p_list

    def __repr__(self):
        return "+".join(self.p_list)

person = Person(["ming","UZI","karsa"])
person  #ming+UZI+karsa

反思:
我们在写代码的时候,比如定义a = 11,我们如果想获取它的绝对值,就会用abs(a)来进行获取。
此时我就会想为什么a就能用abs来获取绝对值了?因为它已经定义了

在init中定义了这个魔法方法,所以你才能够使用这些方法。
就像上面,如果我们没有定义__len__这个方法,那么按照常理是不能使用len(),
因为不支持,它是一个对象,对象里面原始定义也没有定义。
所以我们可以给它实现__len__这个魔法函数,person这个对象就可以使用了。
比如我们定义了一个类:

class Num(object):
def __init__(self,value):
    self.value = value

a = Num(1)
print(abs(a))  #TypeError: bad operand type for abs(): ‘Num‘

现在a是一个新的类Num的对象,并不是int的对象,所以它是无法使用abs()的。

我们给它添加魔法函数__abs__之后就可以了。

class Num(object):
    def __init__(self,value):
        self.value = value

    def __abs__(self):
        return abs(self.value)
a = Num(1)
print(abs(a))

比如我们再定义一个:

class MyVector(object):
    def __init__(self,x,y):
        self.x = x
        self.y = y
    def __add__(self,other_instance):
        return MyVector(self.x + other_instance.x, self.y + other_instance.y)
    def __str__(self):
        return "x:{x}, y:{y}".format(x=self.x, y=self.y)

first_v = MyVector(1,2)
second_v = MyVector(3,4)
print(first_v + second_v)  #x:4, y:6

如果我们不定义__add__,那就是两个对象在加

原文地址:https://www.cnblogs.com/yangmingxianshen/p/11281805.html

时间: 2024-08-30 06:54:12

魔法函数的相关文章

操作数据库的魔法函数

function bind(){ global $dbhost,$dbuser,$db,$dbpass; //首先我们不知道外面会传入多少个参数//可以用func_get_args()方法来获取全部传入参数,这个方法返回全部参数的数组//和func_get_args()方法相对应的其实还有一个func_num_args()来获取参数个数$args = func_get_args(); //通过使用array_shift方法,使传入的第一个参数,后后面的参数分开,其实就是把sql语句,和//后面传

php使用魔法函数和不使用魔法函数比较

/** * use magic 0.31868386268616s * not use magic 0.11876797676086s */ class Test { private $varstr = "123"; function __get($name) { return $this->varstr; } } function microtime_float() { list($usec, $sec) = explode(" ", microtime()

4-1 减少PHP魔法函数的使用 __get($name)返回私有变量 取执行时间

魔法函数执行时间0.635 <?php class Test{ private $var='123'; public function __get($name) { return $this->var; } } function current_time(){ list($usec,$sec)= explode(' ',microtime()); return ((float)$usec+(float)$sec); } $_start=current_time(); $i=0; while (

PHP魔法函数与变量

__invoke()    该魔术方法会在将一个对象作为函数调用时被调用:    __callStatic()    则会在调用一个不存在的静态方法时被调用. PHP魔法函数与变量 来源:http://ruby8.iteye.com/blog/626982 1:魔法函数 __construct() 实例化对象时被调用. 当__construct和以类名为函数名的函数同时存在时,__construct将被调用,另一个不被调用. __destruct() 当删除一个对象或对象操作终止时被调用. __

php魔法函数与魔法常量的说明

魔术函数 1.__construct() 实例化对象时被调用, 当__construct和以类名为函数名的函数同时存在时,__construct将被调用,另一个不被调用. 2.__destruct() 当删除一个对象或对象操作终止时被调用. 3.__call() 对象调用某个方法, 若方法存在,则直接调用: 若不存在,则会去调用__call函数. 4.__get() 读取一个对象的属性时, 若属性存在,则直接返回属性值: 若不存在,则会调用__get函数. 5.__set() 设置一个对象的属性

python魔法函数的一些疑问

看了魔法函数,有一点疑问.1中需要用self.word才能执行,而2直接用self就可以执行.而1中Word继承了int基本类型,但在__new__时并没有什么卵用.当用 Word(“123”)来实例化时,看到的运算结果是以字符串形式来进行运算的,比如“123”*3=123123123. 1. class Word(int): def __new__(cls, word): word = int(word) return int.__new__(cls,word) def __init__(se

python内置函数和魔法函数

内置方法:Python中声明每一个类系统都会加上一些默认内置方法,提供给系统调用该类的对象时使用.比如需要实例化一个对象时,需要调用该类的init方法:使用print去打印一个类时,其实调用的是str方法等等. init(self, …):初始化对象class,在创建新对象时调用.在方法里,可以初始化该对象的属性,否则调用其他时可能出“现has no attribute”错误: del(self):释放对象,在对象被虚拟机删除之前调用: new(cls,*args,**kwd):实例的生成操作,

python魔法函数之__getitem__

魔法函数会增强python类的类型,独立存在 class Company: def __init__(self, employees): self.employees = employees def __getitem__(self, item): return self.employees[item] company = Company(['a', 'b', 'c']) for val in company: print(val) company1 = company[:2] for val

Python的魔法函数系列 __getattrbute__和__getattr__

  #!/usr/bin/env python # -*- coding: utf-8 -*- import sys __metaclass__ = type """ __getattr__ 和 __getattribute__ 的区别 """ class ClassName: def __init__(self, name, info={}): self.name = name self.info = info # def __getattri

gj3 Python数据模型(魔法函数)

3.1 什么是魔法函数 类里面,实现某些特性的内置函数,类似 def __xx__(): 的形式. 不要自己定义XX,并不是和某个类挂钩的 class Company(object): def __init__(self, employee_list): self.employee = employee_list # 可迭代 def __getitem__(self, item): return self.employee[item] # 长度,实现了len函数 def __len__(self