Python——魔术方法

发布时间:2020-07-07 02:07:09 作者:AiSmile
来源:网络 阅读:523

特殊属性

Python——魔术方法

__name__    类、函数、方法等的名字

__module__  类定义所在的模块

__class__   对象或类所属的类

__bases__   类的基类的元组,顺序为他们在基类列表中出现的顺序

__doc__     类、函数的文档字符串,如果没有定义则为None

__mro__     类的面容,class.mro()返回的结果 保存在__mro__中

__dict__    类或实例的属性,可写的字典

查看属性

Python——魔术方法

__dir__     返回类或者对象的所有成员名称列表。dir() 函数就是调用__dir__()。

使用实例调用时,如果提供__dir__(),则返回其返回值,要求是可迭代对象

           如果没有提供__dir__(),则会从实例和类及祖先类中手机信息

如果dir([obj])  参数obj包含方法 __dir__(),该方法将被调用。如果Obj 不包含 __dir__(),该方法将最大限度收集属性信息

dir(obj) 对于不同类型的对象obj具有不同的行为:

1.如果对象是模块对象,返回的列表包含模块的属性名和变量名

2.如果对象是类型或者类对象,返回的列表包含类的属性名,及它的基类的属性名

3.如果obj不写  即dir(),返回列表包含内容不同

- 在模块中,返回模块的属性和变量名

- 在函数中,返回本地作用域的变量名

- 在方法中,返回本地作用域的变量名

dir()测试如下:

class Person:

   def show(self):

       a = 100

       t = int(a)

       print(dir())

def test(a=50, b=100):

   print(dir())

Person().show()

test()

-----------------------------------------------

['a', 'self', 't']

['a', 'b']


魔术方法***

分类:

1.创建、初始化与销毁

__new__ 、__init__ 与__del__

2.hash

3.bool

4.可视化

5.运算符重载

6.容器和大小

7.可调用对象

8.上下文管理

9.反射

10.描述器

11.其它杂项

实例化

Python——魔术方法

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

class A:

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

       print(cls)

       print(*args)

       print(**kwargs)

       return super().__new__(cls) # 返回cls的实例

       # return 1

       # return None

   def __init__(self, name):

       self.name = name

a = A("tom")

print(a)

--------------------------------------------

<class '__main__.A'>

tom

<__main__.A object at 0x00000281924C46A0>


hash

Python——魔术方法

hash(x) x都一样,求得hash应该不变的,幂等性:一般来说,x不一样,hash应该不一样.

不同的hash算法都有hash冲突的问题,即不同的x求得同样的hash值

hash值相同就会去重吗??

不是的

list 类为为什么不可hash ??

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

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

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)

print({tuple('t'), tuple('t')})

print({('tom',), ('tom',)})

print({"tom", "tom"})

---------------------------------------------------------------

1

(tom, tom)

[tom, tom]

-------------------------

{tom, tom} # set 没有去重

{('t',)}

{('tom',)}

{'tom'}

Python——魔术方法

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

hash值相等,只是hash冲突,不能说明两个对象是相等的。

因此,一般来说提供__hash__方法是为了作set或者dict的key,所以 去重,要同时提供__eq__方法

不可hash对象 isinstance(p1, collection.Hashable) 一定为False(import collections)

去重需要提供 __eq__方法

class A:

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

       self.name = name

   def __hash__(self):

       return 1

   def __eq__(self, other): # 提供了__eq__方法

       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')}

print(s)

print({tuple('t'), tuple('t')})

print({('tom',), ('tom',)})

print({"tom", "tom"})

------------------------------------------------

1

(tom, tom)

[tom, tom]

-------------------------

{tom} #去重了

{('t',)}

{('tom',)}

{'tom'}


bool

Python——魔术方法

可视化

Python——魔术方法

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

class A:

   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()

print(A('tom'))

print([A('tom')])

print([str(A('tom'))])

print(bytes(A('tom')))

print('str:a,1')

s = '1'

print(s)

s1 = 'a'

print(s1)

print([s1], (s,))

print({s, "a"})

-----------------------------------------------------------------

str:tom,18

[repr:tom,18]

['str:tom,18']

b'tom is 18'

str:a,1

1

a

['a'] ('1',)

{'1', 'a'}


运算符重载

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

Python——魔术方法

实现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):

       # self.age -= other.age

       # return self

       # return self.__clas__(self.name, self - other)

       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))

-------------------------------------------------------

2

-2 -2

1864834369800

2 1864834369800

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

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


运算符重载应用场景

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

@functools.total_ordering装饰器

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

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

__eq__ 等于 可以推断 不等于

__gt__ 大于 可以推断 小于

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

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

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 is other or (self.x == other.x and self.y == other.y)

   def __add__(self, other):

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

   def __iadd__(self, other):

       self.x, self.y = self.x + other.x, self.y + other.y

       return self

   def __eq__(self, other): #判断 == , !=

       return self.x == other.x

   def __gt__(self, other): # 判断> , <

       return self.x > other.x

   def __ge__(self, other): # 判断>= , <=

       return self.x >= other.x

a = Point(3,2)

b = Point(1,3)

c = Point(3,1)

print(a + b)

print(a > b)

print(a > c)

print(a < b)

print(a < c)

print(a >= c)

print(a <= c)

-----------------------------------------------------------

<__main__.Point object at 0x000001F51ACA49E8>

True

False

False

False

True

True

容器相关方法

Python——魔术方法

为什么空字典,空字符串,空元祖,空列表,空集合可以等效为False

因为 __bool__未定义时,回调用 __len__ 结果为0 等下 False

class A(dict):

   def __missing__(self, key):

       print('Missingn key:', key)

       return 0

a = A()

print(a['k'])

------------------------------

Missingn key: k

0

可调用对象

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

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

def foo():

   print(foo.__module__, foo.__name__)

foo()

# 等价于

foo.__call__()

Python——魔术方法

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

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(p)

print(p())

--------------------------------------------------------

<__main__.Point object at 0x000001F7E8E30A20>

<Point 4:5>

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) # 当adder(4,5,6)不存在时,__call__方法不会调用,Adder无adder.ert属性,会抛异常

-------------------------------------------------------

<Point 4:5>

15

15


推荐阅读:
  1. python单例模式和魔术方法的实现
  2. php魔术方法

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

python 面向对象 魔术方法

上一篇:Android学习—Activity之间数据传递之Intent数据传递

下一篇:Redis构建分布式锁

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》