特殊属性
__name__ 类、函数、方法等的名字
__module__ 类定义所在的模块
__class__ 对象或类所属的类
__bases__ 类的基类的元组,顺序为他们在基类列表中出现的顺序
__doc__ 类、函数的文档字符串,如果没有定义则为None
__mro__ 类的面容,class.mro()返回的结果 保存在__mro__中
__dict__ 类或实例的属性,可写的字典
查看属性
__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.其它杂项
实例化
__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
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'}
__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
可视化
注意:类型判断要使用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模块提供以下的特殊方法,可以将类的实例使用下面的操作符来操作
实现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
容器相关方法
为什么空字典,空字符串,空元祖,空列表,空集合可以等效为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__()
可调用对象: 定义一个类,并实例化的到其实例,将实例像函数一样调用
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
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。