python魔术方法(进阶)斐波那契数列 - Go语言中文社区

python魔术方法(进阶)斐波那契数列


特殊属性

属性 含义
_name_ 类、函数、方法等的名字,要调用实例显示的话要在前加上__class__
_class_ 对象 或 类所属的类名
_module_ 对象或类所属的类 (父)
_doc_ 类、函数的文档字符串,如果没有定义则为None (类和实例)
_dict_ 类或实例的属性,可写的字典(类和实例)

mro() 调用方法,类的名字加上.mro() # 可以得到查找循序
例子:

class Myname:
    def __init__(self, nam):
        self.nam = nam

    # __name__和__class__的运用
    def show(self):
        # print('11', self.__class__.__name__)  # __name__ 不能直接通过实例调用
        print('44', __class__.__name__)  # 少了self实例得到的是类的名字

    def show2(self):
        print('22', self.__module__)  # 类所定义的模块名
        # print('55', self.__mro__)


class Car(Myname):
    def carshow(self):
        print('33', self.__module__)  # 类所定义的模块名


b = Car('tom')
print(b.show())
print(b.show2())
print(b.carshow())
print(Car.mro() # 查找循序

查看属性

方法 意义
_dir_ 返回类或者对象的所有成员名称列表。dir()函数就是调用 _dir_ ()。 使用实例调用时,如果提供 _dir_ (),则返回其返回值,要求是可迭代对象。 如果没有提供 _dir_() ,则会从实例和类及祖先类中收集信息

用法:
dir() 括号里加上 你想查询的对象
如何用dir()函数查看模块属性和方法,例子:

class Animal:
    x = 123

    def __init__(self, name, age=20, color=10):
        self.name = name
        self.age = age
        self.color = color

    def show(self):
        pass


print('the dir is {}'.format(dir()))  # 在模块中返回模块的属性
print('the dir is {}'.format(dir(Animal)))  # 在返回模块的变量名
print(dir([]))

class Person:
    def show(self):
        a = 100
        t = int(a)
        print(dir())
def test(a=50, b=100):
    print(dir())
Person().show() # 实例的输出:a t self
test() # 只输出变量

实例化

方法 意义
_new_ 实例化一个对象 该方法需要返回一个值,如果该值不是cls的实例,则不会调用 _init_ 该方法永远都是静态方法。等于创建一个类的实例的方法

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

class Persron(object):
    def __new__(cls, *args, **kwargs):
        print('new')
        return super().__new__(cls)  # 

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

    def __repr__(self):
        return '<Preson {} {} >'.format(self.name, self.age)

if __name__ == '__main__':
    pi = Persron('tom', 18)
    print(pi)  # 缺少str 或者repe 看到的只是一个类对象的实例 <__main__.Persron object at 0x10214fcf8>

可视化

方法 意义
__str__ str()函数、format()函数、print()函数调用,需要返回对象的字符串表达。如果没有定义,就 去调用 __repr__ 方法返回字符串表达,如果 __repr__ 没有定义,就直接返回对象的内存地 址信息
__repr__ 内建函数repr()对一个对象获取字符串表达。调用 __repr__ 方法返回字符串表达,如果 __repr__ 也没有定义,就直接返回object的定义 就是显示内存地址信息
__bytes__ bytes()函数调用,返回一个对象的bytes表达,即返回bytes对象

例子:

class C:
    def __init__(self, name):
        self.name = name

    def __bytes__(self):  # 二进制转换
        # return "{} is {}".format(self.name, self.age).encode()
        import json
        return json.dumps(self.__dict__).encode()

    def __repr__(self): # 装换成字符串输出,没有定义的话,会返回对象的内存地址信息
        return '<re:{}>'.format(self.name)


print(C('tom'))
print(bytes(C('123'))) # 二进制装换,成json


hash

方法 意义
_hash_ 内建函数 hash() 调用的返回值,返回一个整数。如果定义这个方法该类的实例就可hash
_eq_ 对应==操作符,判断2个对象是否相等,返回bool值
class A:
    def __init__(self, name, age=18):
        self.name = name

    def __hash__(self):
#         return 1
        return hash(self.name) # 可以调用hash()
    def __eq__(self,other):
        return self.name == other.name

    def __repr__(self):
        return self.name

a = A('kenny')
b = A('kenny')
c = A('tom')
print(id(a),id(b),id(c)) # ip地址都不一样
# 内容对比 用到eq
print('1.',a == b) 
print('2.',a==c )
print(hash(a),hash(b),hash(c))
print('3.',a is b) # hash地址一样,但是ip地址不一样,所以是False

print({a,b})
# 总结: == 比较的是内容, is 比较的是ip地址, set集合要去重,必须内容和哈希地址一样

set() 集合的内容和****hash值地址一样就去重。有hash冲突并不去重,也不看id地址


练习: 设置一个二维坐标Point 它是可hash类型,并比较2个实例坐标是否相等


from collections import Hashable # 导入hashable判断是否hash类型
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __hash__(self):
        # return hash((self.x, self.y))
        return 1

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

a = Point(4, 5)
b = Point(5, 6)
c = Point(5, 6)
print(a.__hash__(), b.__hash__())
print(a == b)
print(b == c)
print(isinstance(a,Hashable)) #True

bool

方法 意义
__ bool__ 内建函数bool(),或者对象放在逻辑表达式的位置,调用这个函数返回布尔值。 没有定义 __bool__ (),就找__ len__ ()返回长度,非0为真。如果 __len__ ()也没有定义,那么所有实例都返回真

例子:(注意不能通过是否带引号来判断输出值的类型,判断类型还是要选择type或者isinstance)

class B:
    def __bool__(self):
        return False


print(bool(B))  # 判断有没有存在
print(bool(B()))  # 有定义的实例调用为return


class A: pass


class C:
    def __len__(self):
        return 0


print(bool(A()))
if A():
    print('Real A')
print(bool(A)) 
print(bool(A())) # 没有定义,全部实例返回为真  
print(bool(C()))  # __bool__没找到默认找__len() 返回长度,非0为真

运算符重载应用场景

在这里插入图片描述

往往是用面向对象实现的类,需要做大量的运算,而运算符是这种运算在数学上最常见的表达方式。例如,上例中 的对+进行了运算符重载,实现了Point类的二元操作,重新定义为Point + Point。 提供运算符重载,比直接提供加法方法要更加适合该领域内使用者的习惯。

例子:实现A类的2个实例相减

class A:
    def __init__(self, name, age):
        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)


a = A('kek', 18)
b = A('yuyu', 20)
print(a - b)

例子二:我们定义一个“人”的类People,当中有属性姓名name、年龄age。让你需要利用sorted函数对一个People的数组进行排序,排序规则是按照name和age同时排序,即name不同时比较name,相同时比较age。由于People类本身不具有比较功能,所以需要自定义,你可以这么定义People类

class People:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __gt__(self, other):
        return self.name > other.name if self.name != other.name else self.age > other.age

    def __repr__(self):
        return '<{}: {} {}>'.format(__class__.__name__, self.name, self.age)


tom = People('tom', 18)
jenny = People('jenny', 20)
s1 = [1, 4, 2, 5, 123, 3]
for item in sorted([tom, jenny, People('jenny', 28)]):
    print(item)

__eq__ 等于可以推断不等于
__gt__ 大于可以推断小于
__ge__ 大于等于可以推断小于等于
也就是用3个方法,就可以把所有比较解决了


容器相关方法

方法 意义
__len__ 内建函数len(),返回对象的长度(>=0的整数),如果把对象当做容器类型看,就如同list 或者dict。bool()函数调用的时候,如果没有 __bool__() 方法,则会看 __len__() 方法 是否存在,存在返回非0为真
__iter__ 迭代容器时,调用,返回一个新的迭代器对象
__getitem__ 实现self[key]访问。序列对象,key接受整数为索引,或者切片。对于set和dict,key为 hashable。key不存在引发KeyError异常
__setitem__ 和 __getitem__ 的访问类似,是设置值的方法

例子:构建一个购物车

class Cart:
    # 初始化列表
    def __init__(self):
        self.car = []

    # 调用函数,增加
    def additem(self, name):
        return self.car.append(name)

    # 不要返回对象内存地址
    def __repr__(self):
        return '<{} {}>'.format(__class__.__name__, self.car)

    # 判断列表长度
    def __len__(self):
        return len(self.car)

    # 可以迭代
    def __iter__(self):
        return iter(self.car)

    # 返回一个对象可以链式编程
    def __add__(self, other):
        self.car.append(other)
        return self

    # 通过索引取到列表的值
    def __getitem__(self, index):
        return self.car[index]

    # 通过索引修改列表的值
    def __setitem__(self, index, value):
        self.car[index] = value
        # return self
    # def __contains__(self, index):
    #     self.car = index


# def
# def __add__(self, other):


cart = Cart()
cart.additem(1)
cart.additem('abc')
cart.additem(3)
print(cart.car)
# 长度、bool
print(len(cart))
print(bool(cart))
# # 迭代
for x in cart:
    print(x, end=' ')
# # in
print()
print(3 in cart)
print(2 in cart)
# # 链式编程实现加法
print(cart + 4 + 5 + 6)
print(cart.__add__(17).__add__(18))
# 索引操作
print(cart[1])
cart[1] = 'xyz'

可调用对象

python 中一切皆对象
__call__,类中定义一个该方法,实例可以像函数一样使用
例子:

def foo():
    print(foo.__module__, foo.__name__)  # 类的名字,函数的名字
foo()
foo.__call__() # 函数即对象,对象foo加上() ,就是调用函数对象call__() 方法

练习:
定义一个类,并实例化得到其实例,像实例函数一样去调用。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

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

    def __repr__(self):
        return '<{},{},{}>'.format(self.__class__.__name__, self.name, self.age)


c1 = Person('tom', 12)
print(c1())


class add:
    ## 不初始化对象
    # def __call__(self, *args, **kwargs):
    #     ret = 0
    #     for x in args:
    #         print(x)
    #         ret += x
    #     self.ret = ret
    #     return ret

    # 初始化对象
    def __init__(self, *args):
        self.args = args

    def __call__(self, *args, **kwargs):
        ret = 0
        for i in args:
            ret += i
        return ret


adder = add()
print(adder(4, 6))
# print(adder.ret)
## 2. 定义一个斐波那契数列,计算第n项[0、1、1、2、3、5、8、13、21]
	
# [0、1、1、2、3、5、8、13、21]
# 普通方法
a = 1
b = 0
for i in range(6):
    a, b = b, a + b
print(b)
# 函数,生成器 做成生成器函数

def fib():
    a = 1
    b = 0
    while True:
        a, b = b, a + b
        yield a
foo = fib()
for i in range(10):
    print(next(foo))		

# 递归
def fib(n):return n if n <= 1 else fib(n - 2) + fib(n - 1)

#做成一个类:	
class Fib:
    def __init__(self):
        self.x = 1
        self.y = 1

    def __call__(self, index):
        if index <= 1:
            return index
        else:
            for i in range(index - 2):
                self.x, self.y = self.y, self.x + self.y
        return self.y
fib = Fib()
print(fib(5))

# 如何提高效率,一是使用cache缓存,二是将类做成一个列表,
# 一 缓存
import functools
@functools.lru_cache()
def fib(n):
    return n if n <= 1 else fib(n - 2) + fib(n - 1)
print(fib(135))

# 二 类的列表 实现,长度,可索引,可迭代,可实例调用
class Fib:
    def __init__(self):
        self.lb = [0, 1, 1]

    def __call__(self, index):
        if index < len(self.lb):
            return self.lb[index]
        for i in range(3, index+1):
            self.lb.append(self.lb[i - 2] + self.lb[i - 1])
        return self.lb
fib = Fib()
print(fib(3))

class Fib:
    def __init__(self):
        self.arrlis = [0, 1, 1]

    def __call__(self, index):
        if index < len(self.arrlis):
            return self.arrlis[index]
        for i in range(3
                        
                        
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/a13532865022/article/details/90453408
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢