__dir__
返回类或者对象的所有成员名称列表
dir()
函数操作实例就是调用__dir__()
如果dir([obj])
参数obj包含方法__dir__()
,该方法将被调用
如果参数obj
不包含__dir__()
,该方法将最大限度地收集属性信息
dir(obj)
对于不同类型的对象obj具有不同的行为:
1 如果对象是模块对象,返回的列表包含模块的属性名和变量名
2 如果对象是类型或者说是类对象,返回的列表包含类的属性名,及它的祖先类的属性名
3 如果是类的实例
有__dir__
方法,返回可迭代对象的返回值
没有 __dir__
方法,则尽可能收集实例的属性名、类的属性和祖先类的属性名
4 如果obj
不写,返回列表包含内容不同
在模块中,返回模块的属性和变量名
在函数中,返回本地作用域的变量名
在方法中,返回本地作用域的变量名
locals()
返回当前作用域中的变量字典
globals()
当前模块全局变量的字典
class Animal:
x = 123
def __init__(self, name):
self._name = name
self.__age = 10
self.weight = 20
dir(Animal)
['__class__',
'__delattr__',
'__dict__',
'__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__',
'x']
dir(Animal('Sybil'))
['_Animal__age',
'__class__',
'__delattr__',
'__dict__',
'__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__',
'_name',
'weight',
'x']
class Cat(Animal):
y = 'abc'
dir(Cat)
['__class__',
'__delattr__',
'__dict__',
'__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__',
'x',
'y']
__new__
__new__
方法;返回的是一个实例,然后继续调用__init__
方法,进行出厂配置cls
的实例,则不会调用__init__
cls
需要手动输入,不会自动注入任何参数__init__
方法很少使用,即使创建了该方法,也会使用return super().__new__(cls)
基类object
的 __new__
方法来创建实例并返回class A:
def __new__(cls, *args, **kwargs):
print('new')
print(cls)
print(args)
print(kwargs)
return super().__new__(cls)
# return None
def __init__(self, name):
print('init')
self.name = name
a = A('name')
new
<class '__main__.A'>
('name',)
{}
init
__str__:str() format() print()
函数调用,需要返回对象的字符串表达。如果没有定义,就去调用__repr__
方法返回字符串表达。如果__repr__
没有定义,就直接返回对象的内存地址__repr__
:内建函数repr()
对一个对象获取字符串表达。如果__repr__
没有定义,就直接返回对象的内存地址__bytes__:bytes()
函数调用,返回一个对象的bytes
表达,即返回bytes
对象type
或者isinstance
str
,但是间接作用也可以使用 str
repr
例如:[] ()
repr
,就会调基类的repr
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()
# import json
# return json.dumps(self.__dict__).encode()
print(A('tom')) # str: tom,18 # print函数使用__str__
print('{}'.format(A('tom'))) # str: tom,18 # format函数使用__str__
print(repr(A('tom'))) # repr: tom,18
print([A('tom')]) # [repr: tom,18] # []使用__str__,但其内部使用__repr__
print([str(A('tom'))]) # ['str: tom,18'] # []使用__str__,其中的元素使用str()函数也带哦用__str__
print('str:a,1') # str:a,1 # 字符串直接输出没有引号
s = '1'
print(s) # 1
s1 = 'a'
print(s1) # a
print([s1], (s,)) # ['a'] ('1',) # 字符串在基本数据类型内部输出有引号
print({s, 'a'}) # {'1', 'a'}
print(bytes(A('tom'))) # b'tom is 18'
hash
__hash__
:1 内建函数hash()调用的返回值,返回一个整数。2 如果定义这个方法该类的实例就可hash
__eq__
:1 对应==
操作符,判断2个对象是否相等,返回bool
值。2 定义了这个方法,如果不提供__hash__
方法,那么实例将不可hash
了__hash__
:方法只是返回一个hash
值作为set
的key
,但是去重,还需要__eq__
来判断2个对象是否相等。hash
值相等,只是hash
冲突,不能说明两个对象是相等的。因此,一般来说提供__hash__
方法是为了作为set
或者dict
的key
,如果去重,要同时提供__eq__
方法。hash
对象isinstance(p1, collections.Hashable)
一定为False
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'))) # 1
print([A('tom'), A('tom')]) # [tom, tom]
print({A('tom'), A('tom')}) # {tom}
print((A('tom'), A('tom'))) # (tom, tom)
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
def __str__(self):
return "Point:({},{})".format(self.x, self.y)
def __repr__(self): # set 里面显示的时候调用的时 repr
return "Point:({},{})".format(self.x, self.y)
p1 = Point(4, 5)
p2 = Point(4, 5)
print(p1, p2)
print(hash(p1))
print(hash(p2))
print(p1 is p2)
print(p1 == p2)
print(hex(id(p1)), hex(id(p2)))
print(set((p1, p2)))
print(isinstance(p1, Hashable))
Point:(4,5) Point:(4,5)
-1009709641759730766
-1009709641759730766
False
True
0x1eaf14f7f10 0x1eaf14c98b0
{Point:(4,5)}
True
__bool__
bool()
,或者对象放在逻辑表达式的位置,调用这个函数返回布尔值__bool__()
,就找__len__()
返回长度,非0为真__len__()
也没有定义,那么所有实例都返回真class A: pass
print(1, bool(A()))
if A():
print(2, 'Real A')
class B:
def __bool__(self):
return False
print(3, bool(B))
print(4, bool(B()))
if B():
print(5, 'Real B')
class C:
def __len__(self):
return 0
print(6, bool(C()))
if not C():
print(7, 'False C')
print(8, bool(C))
1 True
2 Real A
3 True
4 False
6 False
7 False C
8 True
# 就地修改
class A:
def __init__(self ,age):
self.age = age
def __sub__(self, other):
return self.age - other.age
def __isub__(self, other):
self.age -= other.age # int的-=和实例的-=不一样,不会递归
return self
a1 = A(20)
a2 = A(12)
print(id(a1), a1.age, a1)
a1 -= a2
print(id(a1), a1.age, a1)
# 2761171921408 20 <__main__.A object at 0x00000282E2ABEA00>
# 2761171921408 8 <__main__.A object at 0x00000282E2ABEA00>
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__
self.age = self.age - other.age # __isub__方法定义,一般会in-place就地来修改自身
return self
# return A(self.name, self - other)
def __str__(self):
return '[name = {}, age = {}]'.format(self.name, self.age)
tom = A('tom')
jerry = A('jerry', 16)
print(tom - jerry) # 2
print(jerry - tom, jerry.__sub__(tom)) # -2 -2
print(id(tom)) # 2457466099360
tom -= jerry
print(tom.age, id(tom)) # 2 2457466099360
print(tom) # [name = tom, age = 2]
# 运算符重载应用场景
# 比较大小需要实现6种方法, __lt__、__le__、__eq__、__gt__、__ge__
# 一般只需要用三种方法就行:__eq__、__gt__、__ge__
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', 18)
jerry = Person('jerry', 20)
print(tom > jerry) # False
print(tom >= jerry) # False
print(tom != jerry) # True
print(tom < jerry) # True
print(tom <= jerry) # True
print(tom == jerry) # False
__len__
1 内建函数len(),返回对象的长度(>=0的整数)
如果把对象当作容器类型看,就如同list或者dict
2 bool()函数调用的时候,如果没有__bool__()方法
则会看__len__()方法是否存在,存在返回非0为真
__iter__
1 迭代容器时,调用,返回一个新的迭代器
__contains__
1 in成员运算符,没有实现,就调用__iter__方法遍历
__getitem__
1 实现self[key]访问。序列对象,key接受整数为索引,或为切片
2 对于set和dict,key为hashable。key不存在引发KeyError异常
__setitem__
1 和__getitem__的访问类似,是设置值的方法
__missing__
1 字典或其子类使用__getitem__()调用时,key不存在执行该方法
# 偷梁换柱
class A(dict):
def __missing__(self, key): # 字典及其子类才会有此属性
print(key, 'missing ~~~~~~~~~~~~')
value = 1000
self.__dict__[key] = value
return value
a = A()
print(a['t'])
print(a.__dict__)
# t missing ~~~~~~~~~~~~
# 1000
# {'t': 1000}
# 注意递归问题
class A:
def __init__(self):
self.items = []
def add(self, item):
self.items.append(item)
return self
def __setitem__(self, index, value):
self.items[index] = value
# self[index] = value # 注意递归问题
def __getitem__(self, index): # 注意递归问题
return self.items[index]
# return self[index]
def __iter__(self):
yield from self.items
# return iter(self.items)
a = A()
a.add(1).add(2).add(3)
print(a)
print(a[1])
# 模拟购物车类
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):
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('a')
cart.additem('c')
print(cart) # [1, 'a', 'c']
print(len(cart)) # 3
for x in cart:
print(x, end = ' ') # 1 a c
print(3 in cart) # False
print(1 in cart) # True
print(cart[1]) # a
cart[1] = 'xyz'
print(cart) # [1, 'xyz', 'c']
print(cart + 4 + 'aaa' + 'ppp') # [1, 'xyz', 'c', 4, 'aaa', 'ppp']
print(cart.__add__('iii')) # [1, 'xyz', 'c', 4, 'aaa', 'ppp', 'iii']
print(cart.items) # [1, 'xyz', 'c', 4, 'aaa', 'ppp', 'iii']
Python中一切皆对象,函数也不例外。
__call__
:类中定义一个该方法,实例就可以像函数一样调用
def foo():
print(foo.__module__, foo.__name__)
foo() # __main__ foo
# 等价于
foo.__call__() # __main__ foo
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)) # 13
# 逐步优化
class Fib:
def __init__(self):
self.a = 1
self.b = 1
def __call__(self, index):
if index < 0:
raise IndexError()
elif index == 0:
return 0
elif index < 3:
return 1
for i in range(index - 2):
self.a, self.b = self.b, self.a + self.b
return self.b
fib = Fib()
fib(35) # 9227465
# 保存计算过的各个结果
class Fib2:
def __init__(self):
self.items = [0, 1, 1]
def __call__(self, index):
if index < 0:
raise IndexError()
if index < len(self.items):
return self.items[index]
import time
time.sleep(1)
for i in range(len(self.items), index+1):
self.items.append(self.items[i - 1] + self.items[i - 2])
return self.items[index]
# 继续进行容器化
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-2] + self.items[i-1])
return self.items[index]
def __str__(self):
return str(self.items)
__repr__ = __str__
fib = Fib()
print(fib(5), len(fib)) # 5 6
print(fib.items) # [0, 1, 1, 2, 3, 5]
print(fib(101)) # 573147844013817084101
print(fib[100] + fib[99]) # 573147844013817084101
print(fib[101]) # 573147844013817084101