文章目录

    • 特殊属性
    • 查看属性
    • 实例化
    • 可视化
    • hash
    • bool
    • 运算符重载应用场景
    • 容器相关方法
    • 可调用对象
    • 上下文管理
    • 上下文管理的安全性
    • 方法的参数
    • contextlib.contextmanager
    • 反射
    • 反射相关的魔术方法
    • 描叙器
  • 描述器定义

特殊属性

属性 含义
_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 = 123def __init__(self, name, age=20, color=10):self.name = nameself.age = ageself.color = colordef show(self):passprint('the dir is {}'.format(dir()))  # 在模块中返回模块的属性
print('the dir is {}'.format(dir(Animal)))  # 在返回模块的变量名
print(dir([]))class Person:def show(self):a = 100t = 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 = nameself.age = agedef __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 = namedef __bytes__(self):  # 二进制转换# return "{} is {}".format(self.name, self.age).encode()import jsonreturn 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 = namedef __hash__(self):
#         return 1return hash(self.name) # 可以调用hash()def __eq__(self,other):return self.name == other.namedef __repr__(self):return self.namea = 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地址不一样,所以是Falseprint({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 = xself.y = ydef __hash__(self):# return hash((self.x, self.y))return 1def __eq__(self, other):return self.x == other.x and self.y == other.ya = 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 Falseprint(bool(B))  # 判断有没有存在
print(bool(B()))  # 有定义的实例调用为returnclass A: passclass C:def __len__(self):return 0print(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 = nameself.age = agedef __sub__(self, other):  # 定义的是-return self.age - other.agedef __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 = nameself.age = agedef __gt__(self, other):return self.name > other.name if self.name != other.name else self.age > other.agedef __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 = nameself.age = agedef __call__(self, *args, **kwargs):return selfdef __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 = argsdef __call__(self, *args, **kwargs):ret = 0for i in args:ret += ireturn retadder = 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 = 1b = 0while True:a, b = b, a + byield 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 = 1self.y = 1def __call__(self, index):if index <= 1:return indexelse:for i in range(index - 2):self.x, self.y = self.y, self.x + self.yreturn 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, index + 1):self.arrlis.append(self.arrlis[i - 2] + self.arrlis[i - 1])return self.arrlis[index]# 可迭代def __iter__(self):return iter(self.arrlis)#返回长度def __len__(self):return len(self.arrlis)#通过索引取值def __getitem__(self, item):return self.arrlis[item]fib = Fib()
print(fib(5))
for i in fib:print(i)
print(len(fib))
print(fib[4])

上下文管理

使用with…as语法,可以用文件IO操作对文件对象使用上下文管理当一个对象同时实现__enter__ 和__exit__的方法,它就属于上下文管理。enter 和__exit__必须成对出现

方法 意义
__enter__ 进入对象相关的上下文,with语法会把其返回值绑定到 as 字句的指定变量上
__exit__ 退出上下文管理,返回值可以压制主程序的异常

例子:

class Point:def __init__(self):print('1')def __enter__(self):print('2')return '==='def __exit__(self, exc_type, exc_val, exc_tb):print('3')if __name__ == '__main__':with Point() as f:  # 实例化对象时,会执行init属性 但是不会进入enter里,with语法会调用到enter方法。print('---')print(f)  # ==enter里的返回值

注意:with可以开启一个上下文运行环境,在执行前做一些准备工作,执行后做一些收尾工作。with并不开启一个新的作用域。


上下文管理的安全性

异常并不会影响上下文的进入和退出。with会调用enter方法。

即以上例得到,如果调用上下文管理,先会初始化实例,然后通过with 执行enter方法,里面执行完之后再执行主语句体的内容。如果主语句体报错,也不会影响exit的执行

所以:上下文管理是安全的


方法的参数

__enter__ 方法 没有其他参数。
__exit__ 方法有3个参数:
__exit__(self, exc_type, exc_value, traceback) return True 可以压制异常
这三个参数都与异常有关。 如果该上下文退出时没有异常,这3个参数都为None
exc_type ,异常类型
exc_value ,异常的值
traceback ,异常的追踪信息

练习:为加法函数计时
1.用装饰器显示函数的执行时长
2 . 用上下文管理方法来显示函数的执行时长

##1
import time
import datetime
from functools import wraps
def logger(fn):@wraps(fn)def inner(*args, **kwargs):print('begin')start = datetime.datetime.now()ret = fn(*args, **kwargs)end = ((datetime.datetime.now()) - start).total_seconds()print('{},run is {}'.format(fn.__name__, end))return retreturn inner
@logger  # add = logger(add)
def add(x, y):time.sleep(2)return x + y
if __name__ == '__main__':print(add(4, 5))## 2
import time
import datetime
from functools import wrapsclass Timeni:def __init__(self, fn):self.fn = fndef __enter__(self):print('begin')self.start = datetime.datetime.now()return selfdef __exit__(self, exc_type, exc_val, exc_tb):end = (datetime.datetime.now() - self.start).total_seconds()print('{},run time is {}'.format(self.fn.__name__, end))print('byebye')def add(x, y):time.sleep(2)return x + yif __name__ == '__main__':with Timeni(add) as f:print(add(4, 5))print(add(7, 8))
# 或者可以将Timeni当成可调用对象实现,就不用写adddef __call__(self, x, y):return self.fn(x, y)if __name__ == '__main__':with Timeni(add) as f:print(f(4, 5))

修改成类属性装饰器:

import time
import datetime
from functools import wrapsclass Timeni:"""this is timeni class"""def __init__(self, fn):self.fn = fndef __call__(self, *args, **kwargs):self.start = datetime.datetime.now()ret = self.fn(*args, **kwargs)duration = (datetime.datetime.now() - self.start).total_seconds()print('{} run is {}'.format(self.fn.__name__, duration))return ret@Timeni  # add = Timeni(add)
def add(x, y):"""this is add function"""time.sleep(2)return x + yif __name__ == '__main__':print(add(4, 5))print(add.__doc__) # doc的名字变了print(add.__class__.__name__) # add 的名字是类的名字# 修改:
## 在类的init方法下直接修改字符串self.__doc__ = self.fn.__doc__
##方法二:
from functools import wraps, update_wrapper
在__init__下,调用update_wrapper(self,fn)
## 方法三:wrap(fn)(self)

总结上下文应用场景

  1. 可以增强功能
  2. 打开的资源可以自动关闭,例如文件对象,网络连接,数据库连接。
  3. 权限验证(在执行代码前,做权限验证。在__enter__中处理。)

contextlib.contextmanager

它是一个装饰器实现上下文管理,装饰一个函数,而不用像类一样实现 __enter__ 和 __exit__ 方法。 对下面的函数有要求,必须有yield,也就是这个函数必须返回一个生成器,且只有yield一个值。 也就是这个装饰器接收一个生成器对象作为参数

contextlib.contextmanager装饰器,yield前代表__extend__ 。yield后代表__exit__ yield代表__extend的返回值

import contextlib
@contextlib.contextmanager
def add():"""this is add function"""print('begin')try:yield 2finally:print('end')if __name__ == '__main__':with add() as f:print(f)# 如果不加 try..finally, 程序出现异常时,无法执行后继的end,

练习:依然是给add函数通过上下文管理的方式计算时间

import contextlib
import time
import datetime@contextlib.contextmanager
def add(x, y):"""this is add function"""print('begin')start = datetime.datetime.now()try:yield x + yfinally:duration = (datetime.datetime.now() - start).total_seconds()print('the time is {}'.format(duration))if __name__ == '__main__':with add(4, 5) as f:time.sleep(2)print(f)

总结 如果业务逻辑简单可以使用函数加contextlib.contextmanager装饰器方式,如果业务复杂,用类的方式加__enter__ 和 __exit__ 方法方便。

反射

反射,reflection,指的是运行时获取类型定义信息
简单说,在Python中,在运行的时候,能够通过一个对象,找出其type、class、attribute或method的能力,称为反射或者自省。
具有反射能力的函数有type(),isinstance(),callable(),dir(), getattr()

内建函数 意义
getattr(object, name[, default]) 通过name返回object的属性值。当属性不存在,将使用default返回,如果没有 default,则抛出AttributeError。name必须为字符串
setattr(object, name, value) object的属性存在,则覆盖,不存在,新增
hasattr(object, name) 判断对象是否有这个名字的属性,name必须为字符串

如果为实例增加方法,是没有绑定的
例子:有一个Point类,查看它实例的属性,并修改它,动态为实例增加属性

class Point:def __init__(self, x, y):self.x = xself.y = ydef __str__(self):return 'Point{} {}'.format(self.x, self.y)# def show(self):#     print(self.x, self.y)p = Point(4, 5)
print(p)
# p.show()
setattr(p, 'z', 21)
print(getattr(p, 'z', 'NONe'))
print(getattr(p, 'k', 'NONe'))
print(getattr(p, '__dict__'))
print(dir(p))
print(p.__dir__())
# 动态调用方法
if hasattr(p, 'show'):getattr(p, 'show')()
# 为类创建相等
setattr(Point, 'xyz', 100)
print(Point.__dict__)
# 为类增加方法
if not hasattr(Point, 'show'):setattr(Point, 'show', lambda self: print(self.x, self.y))
p2 = Point(4, 5)
p2.show()
# 实现两个实例相加
if not hasattr(Point, 'add'):setattr(Point, 'add', lambda self, other: Point(self.x + other.x, self.y + other.y))print(p2.add(p))
# 实现两个实例相减
if not hasattr(Point, 'sub'):setattr(Point, 'sub', lambda self, other: Point(self.x - other.x, self.y - other.y))
print(p2.sub(p))

练习:建立一个命令分发器,通过名称找对应的函数执行

class Fenfa:def __init__(self):passdef reg(self, name, fn):setattr(self, name, fn)def run(self):while True:cmd = input('>>>')if cmd == 'quit':print('bye')breakgetattr(self, cmd, lambda : print('Not emted{}'.format(cmd)))()fenfa = Fenfa()
fenfa.reg('ls', lambda :print('so'))
fenfa.run()

反射相关的魔术方法

方法 意义
__getattr__() 实例属性会按照继承关系找,如果找不到,就会执行 __getattr__() 方法,如果没有这个方法,就会抛出 AttributeError异常表示找不到属性。查找属性顺序为:instance.__dict__ --> instance.__class__.__dict__ --> 继承的祖先类(直到object)的__dict__ —找不到–> 调 用__getattr__()
__setattr__() 通过 . 访问实例属性,进行增加、修改都要调用它管
__delattr__() 防止实例删除属性

__getattr__的使用例子:

class Base:n = 0class Point(Base):z = 6def __init__(self, x, y):self.x = xself.y = ydef show(self):print(self.x, self.y)def __getattr__(self, item):  # 只管实例,没有return的话只能返回None# return "missing{}".format(item)value = 1000self.__dict__[item] = value  # 所有缺失属性的一个缺省值,可以加到实例字典看到,相当于后悔药,如果直接return 1000 加不进实例字典里return valueP1 = Point(4, 5)
print(P1.x)
print(P1.z)
print(P1.n)
print(P1.t)  # 跟getattr 相关,没有getattr的话会报错,表示找不到属性
print(P1.l)
print(P1.__dict__)

__setter__使用方法:实例通过.点号设置属性,例如 self.x = x 属性赋值,就会调用 __setattr__() ,属性要加到实例的 __dict__ 中,就需要自己完成。

class Base:n = 0class Point(Base):z = 6def __init__(self, x, y):self.x = xself.y = ydef show(self):print(self.x, self.y)def __getattr__(self, item):  # 只管实例,没有return的话只能返回None# return "missing{}".format(item)value = 1000self.__dict__[item] = valuereturn valuedef __setattr__(self, key, value):self.__dict__[key] = value# print('{} = {}'.format(key, value))P1 = Point(4, 5)
print(P1.x)
print(P1.y)
print(P1.__dict__)
P1.z = 250 # 实例通过.点号设置属性,例如 self.x = x 属性赋值,就会调用 __setattr__() ,属性要加到实例的 __dict__ 中,就需要自己完成。
print(P1.z)
print(P1.__dict__)

__delattr__() 使用方法:防止实例删除属性

class Base:n = 0
class Point(Base):z = 6# d = {'tttt': '20000'}def __init__(self, x, y):self.x = xself.y = y#  def __delattr__(self, item):#    print('is not del {}'.format(item))# return super().__delattr__(self, *args)P1 = Point(4, 5)
del P1.x # 可以删除
print(P1.__dict__)
print(Point.__dict__)
# P1.z = 15

__getattribute__和__getattr配合使用。__getattribute__实例所有的属性调用都从这个方法开始

class Point(Base):z = 6d = {'tttt': '20000'}def __init__(self, x, y):self.x = xself.y = ydef show(self):print(self.x, self.y)def __getattr__(self, item):return __class__.d[item]# def __setattr__(self, key, value):#     self.__dict__[key] = value#     # print('{} = {}'.format(key, value))def __getattribute__(self, item):# return super.__getattribute__(item)raise AttributeError('aaa')P1 = Point(4, 5)
print(P1.tttt)

描叙器

用到3个魔术方法: __get__() 、 __set__() 、 __delete__()
方法签名如下

  1. object.__get__(self, instance, owner)
  2. object.__set__(self, instance, value)
  3. object.__delete__(self, instance)
    self 指代当前实例,调用者 instance 是owner的实例 owner 是属性的所属的类
class A:def __init__(self):self.a1 = 'a1'print('A init')#  A的实例 #属组的实例 # 属组的类def __get__(self, instance, owner):  # 需要返回值,instance属组的属性即B实例, ownerprint(self, instance, owner)print(self.__dict__)return selfclass B:  # 属组x = A()  # 访问A实例里面的getdef __init__(self):print('b init')# print(B.x)  # 对A实例的魔术方法的get
# print(B.x.a1) # A的实例访问a1
b = B()
print(b.x)
#因为定义了 __get__ 方法,类A就是一个描述器,对类B或者类B的实例的x属性读取,成为对类A的实例的访问, 就会调用 __get__ 方法
class A:def __init__(self):self.a1 = 'a1'print('A init')#  A的实例 #属组的实例 # 属组的类
# 描述器def __get__(self, instance, owner):  # 需要返回值,instance属组的属性即B实例, ownerprint(self, instance, owner)print(self.__dict__)return selfclass B:  # 属组x = A()  # 类属性可以,描述器和属主类的类属性有关def __init__(self):self.y = A()  # 实例属性没用print('b init')b = B()
print(b.y) # b.x才会触发描述器的方法

描述器定义

Python中,一个类实现了 __get__ 、 __set__ 、 __delete__ 三个方法中的任何一个方法,就是描述器。
如果仅实现了 __get__ ,就是非数据描述符 non-data descriptor;
同时实现了 __get__ 、 __set__ 就是==数据描述符 data descriptor ==赋值将会跑到set方法当中。优先级更高
如果一个类的类属性设置为描述器实例,那么它被称为owner属主。
当该类的属性被查找、设置、删除的时候,就会调用描述器相应的方法。

练习:实现staticmethod装饰器、实现classMethod装饰器

class StaticMethod:def __init__(self, fn):self.fn = fndef __get__(self, instance, owner):return self.fnclass A:@StaticMethod  # stmtd = StaticMethod(stmtd)def stmtd():print('static')A.stmtd()
A().stmtd()from functools import partial  # 偏函数class ClassMethod:def __init__(self, fn):self.fn = fndef __get__(self, instance, cls):ret = partial(self.fn, cls)  # 将例注入return retclass B:@ClassMethod  # stmtd = StaticMethod(stmtd)def stmt(cls, x, y):print(cls.__name__, x, y)print(B.__dict__)
print(B.stmt)
B.stmt(4, 5)
B().stmt(4, 5)
  1. 实现property装饰器:
#!/usr/bin/env python
# -*- coding: utf-8 -*-class Property:def __init__(self, fget, fset=None):  # 等于一个函数,实例调用self.fget = fgetself.fset = fsetdef __get__(self, instance, owner):return self.fget(instance)def __set__(self, instance, value):  # 先实现只读属性if self.fset is None:raise AttributeError(123)self.fset(instance, value)  #  返回def setter(self, fn):self.fset = fnreturn selfclass A:def __init__(self, x):self._x = x@Property  # self.fn = Property(self.fn)def x(self):return self._x@x.setterdef x(self, value):self._x = valuea = A(10)
print(a.x)
a.x = 1000
print(a.x)
  1. 对实例的数据进行校验,判断,函数先写
class Person:def __init__(self, name: str, age: int):parmr = ((name, str), (age, int))if not self.chank(parmr):raise TypeError('int or str')self.name = nameself.age = agedef chank(self, parmr):for i,v in parmr:if not isinstance(i,v):return Falsereturn True
Person('tom','12')

对实例的数据进行校验,装饰器

import inspectdef check(cls):def wrapper(*args, **kwargs):sig = inspect.signature(cls)  # 拿到签名params = sig.parameters  # 拿到有序字典# print(params.items())for x, (k, v) in zip(args, params.items()):if v.annotation != inspect._empty and not isinstance(x, v.annotation):raise TypeError('1!!!!!!!!!!!!!')re = cls(args, kwargs)print('end')return rereturn wrapper@check  # Person = check(Pecson)
class Person:def __init__(self, name: str, age: int):self.name = nameself.age = agea = Person('tom', '12') # 报错,成功

对实例的数据进行校验,描述器

class TypeCheck:  # 描述器def __init__(self, name, typ):self.name = nameself.type = typdef __get__(self, instance, owner):# print('get~~~~~~~~~~~~~~')if instance:return instance.__dict__[self.name]else:raise Exception  # 或者return self,总之不正常def __set__(self, instance, value):# print('set~~~~~~~~~~~~~')if instance:if not isinstance(value, self.type):raise TypeError(self.name, '+++++++++++')else:instance.__dict__[self.name] = value  # 存回到属主类的实例字典中,默默的检查,不出错的话,像什么都没有发生一样# def __set_name__(self, owner, name):  # python3.6新增的方法#     print(name)#     self.name = nameclass TypeInject:def __init__(self, cls):self.cls = clsdef __call__(self, *args, **kwarg):sig = inspect.signature(self.cls)params = sig.parameters# print(params)  # OrderedDict([('name', <Parameter "name:str">), ('age', <Parameter "age:int">)])for name, param in params.items():# print(name, param.annotation)if param.annotation != param.empty:  # inspect._emptysetattr(self.cls, name, TypeCheck(name, param.annotation))return self.cls(*args, **kwarg)@TypeInject  # Person = TypeInject(Person)
class Person:def __init__(self, name: str, age: int):self.name = nameself.age = agep5 = Person('Green', 28)

python魔术方法(进阶)斐波那契数列相关推荐

  1. python使用递归实现斐波那契数列

    递归简而言之就是函数自己调用自己,在python中,会自动限制调用次数防止造成内存溢出 下面时使用递归的方法实现斐波那契数列取值的代码 def fibonacci(n):if n == 1 or n ...

  2. python利用列表计算斐波那契数列前30项并输出_python分享斐波那契数列示例分享 Python 分享斐波那契数列前20项和...

    分享助python大神.斐波那契数列,编写程序,利用列具体内容 拜托拜托有时候,最痛苦的其实不是失去,而是你得到以后其实不快乐. ##缩进格式看图 l=[1,1] for i in range(28) ...

  3. Python手动编程实现斐波那契数列

    Python手动编程实现斐波那契数列 目录 Python手动编程实现斐波那契数列 #斐波那契数列起源 #斐波那契数列特点<

  4. python 递归方式实现斐波那契数列

    python 递归方式实现斐波那契数列 import time t1=time.time() def factorial(n):if n==1 or n==2:return 1else:return ...

  5. 【君义精讲】多种方法求斐波那契数列

    概念 斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为"兔子数列&q ...

  6. python输入第十个斐波那契数列,0,1,1,2,3,5,8,13,21,34

    题目:python输入第十个斐波那契数列,0,1,1,2,3,5,8,13,21,34 思路:斐波那契数列定义 : '''递归''' def s(x):n = []if x ==1 or x == 2 ...

  7. 笔试题:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。该题有三种解法:递归的方法求解斐波那契数列、用概率与统计的数学方法解决,3.动态规划

    笔试题 一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶.求该青蛙跳上一个 n 级的台阶总共有多少种跳法.该题有三种解法:1.递归的方法求解斐波那契数列.2.用概率与统计的数学方法解决,3.动态规划 ...

  8. Python生成器、实现斐波那契数列

    Python生成器.实现斐波那契数列 """生成器按照一定规则不断产生新元素的对象无法直接输出生成器里面的内容生成器保存的是数据的算法/规则,每一次调用产生一个生成器创建 ...

  9. 斐波那契数列python递归 0、1、1、2、3_python: 递归和递推方法求斐波那契数列

    1.  斐波那契数列 序号 0 1 2 3 4 5 6... 数列 0 1 1 2 3 5 8... 2.  三种程序 import time time1 = time.clock() #斐波那契数列 ...

  10. python斐波那契数列函数,python—函数进阶-斐波那契数列

    上次说到生成器的调用next(),这样很不方便,需要手动调,我们一般是循环着调,while ,for都可以 a = (i for i in range(5)) for i in a: print(i) ...

最新文章

  1. android qt 对比_QT for android 比较完美解决 全屏问题
  2. 关于C语言运算符优先级的记忆技巧是什么?
  3. cocos2d-x 2.x版本使用uiwidget需要注意的几点
  4. ie php脚本引擎,使用php重新实现PHP脚本引擎内置函数
  5. 英雄传说服务器维护中,英雄传说:星之轨迹 正统《轨迹》手游无法连接服务器是什么原因...
  6. CCNA-第八篇-OSPF-上
  7. 使用freemarker模板生成word文档
  8. 泛型 java 总结_JAVA泛型总结
  9. [Data Structure Algorithm] 哈希表
  10. IIS搭配Server-u构建企业空间服务(二)
  11. 写给软件工程师的 30 条建议
  12. “拼多多优惠券”测试的套路,今天让你秒懂~
  13. 怎样解决An internal error has occurred. Index out of bounds
  14. 全国 259GB 离线天地图地名路网数据覆盖范围
  15. 常微分方程——解的延拓性定理
  16. 《富爸爸穷爸爸》精髓:穷人思维和富人思维的区别
  17. 2021第一学期学习笔记01
  18. Canal Admin Web-UI 学习
  19. 你是人见人捏的“软柿子”吗
  20. 网页字体单位px、em、%、rem、pt、vm、vh介绍

热门文章

  1. 大数据时代,人的行为真的可以被预测吗?
  2. Windows echo 命令
  3. erp java 源码下载_erp java
  4. 华为测试软件csfb分析,华为完成创新语音解决方案Ultra-Flash CSFB 的端到端测试
  5. 给麦田PT做的新主题:Harvest
  6. 儿子上学户口房产不能少 外来创业者被逼回老家
  7. selenium 模块 webdriver使用:Mac下 Firefox和Chrome浏览器驱动下载安装
  8. 为什么科来找不到网络适配器呢
  9. HCIE-RS基础知识
  10. 【贵旅优品】贵旅空港黄果树