仅为入门记录!
目录
#--------------------------------------------------------------------
#魔法方法
#1:魔法方法总是被双下划线包围,例如__init__
#2:魔法方法是面向对象的python的一切,他们总能在适当的时候自己被调用
#--__init__(self[,...]):默认构造和有参构造,无返回值
#--__new__(cls[,...]):对象实例化调用的第一个方法,返回一个实例对象
#--new方法主要是当你继承一些不可变的class时(int,str,tuple)。
'''
class CapStr(str):
def __new__(cls, string):
string = string.upper()
return str.__new__(cls, string)
a = CapStr('aaa')
print(a) -> AAA
__new__属于比较难理解的!!
#例:
#传入字符串,返回字符串的ASCII值。
class Nint(str):
def __new__(cls, arg = ''): #arg是实例对象时传入的参数
if isinstance(str, arg):
total = 0
for each in arg:
total += ord(each)
arg = total
return int.__new__(cls, arg): #实例对象接受的参数
'''
#--__del__(self):相当于析构函数。
'''
class A():
def __del__(self):
print('del!!')
a = A()
b = a
print(del a) -> 没有任何输出
print(del b) -> 输出del
#说明当所有对类对象的引用销毁后,才会调用__del__(self)
'''
#__str__(self):返回字符串来描述实例对象,可以被print调用
#__repr__(self):将一个对象转化为字符串显示,注意只是显示用
'''
class A:
def __str__(self):
return '__str__'
def __repr__(self):
return '__repr__'
a = A()
print(a) -> __str__
在idle上直接输入a:
__repr__
两者同时重写print()显示__str__返回内容
'''
#--------------------------------------------------------------------
#算术运算和反运算和增量赋值操作符:
#在python2.2以后,对类和类型进行了统一,做法就是将int(), str(), list(), tuple()这些BIF转化为了工厂函数
#工厂函数就是一个类对象,当你调用他们的时候,事实上就是创建一个相应的实例对象。
#类对象之间的运算操作便是调用了魔法方法
#__add__(self, other): +
#__sub__(self, other): -
#__mul__(self, other): *
#__truediv(self, other): /
#__floordiv(self, other): //
#__mod__(self, other): %
#__divmod__(self, other): divmod()
#__pow__(self, other[, modulo]): powe()或者**运算符
#__lshift__(self, other): <<
#__rshift__(self, other): >>
#__and__(self, other): &
#__xor__(self, other): ^异或
#__or__(self, other): |
'''
例:实现字符串的左移
class Nstr(str):
def __lshift__(self, other):
return self[other:] + other[:other]
'''
#反运算的魔法方法:与运算方法相同,当左操作数不支持相应的操作时被调用。
#方法名称为在对应算术运算前加r,其他完全相同
'''
例如:
class Int(int):
def __radd__(self, other):
return int.__sub__(self, other)
a = Int(10)
print(11 + a) -> -1:注意:self为a,other为11 所以10-11 = -1
'''
#增量赋值操作符:
#与运算符相同,在前加i
'''
例:字符串默认不能-=,我们来重写,定义从后为删除几个字符
class Str(str):
def __isub__(self, other):
if other <= len(self):
return self[:len(self)-other]
else:
print('长度过长!')
a = Str('abcdef')
a -= 3
print(a) -> abc
'''
#--------------------------------------------------------------------
#比较操作符和一元操作符
#比较操作符
#__lt__(self, other): x < y -> x.__lt__(y)
#__le__(self, other): x <= y -> x.__le__(y)
#__gt__(self, other): x > y
#__ge__(self, other): x >= y
#__eq__(self, other): x == y
#__ne__(self, other): x != y
'''
例:字符串比较大小默认为按字典序,我们定义Str修改为按长度比较
class Str(str):
def __lt__(self, other):
return int.__lt__(self, other)
def __gt__(self, other):
return int.__gt__(self, other)
s1 = Str('abc')
s2 = Str('bc')
print(s1 > s2) True
#一元操作符
#__pos__(self): +x(正号)
#__neg__(self): -x
#__abs__(self): abs()
#__invert__(self): 取反操作: ~x
'''
#--------------------------------------------------------------------
#属性访问魔法方法
#__getattr__(self, name)#!!super无此方法!!
#定义当用户试图获取一个不存在的属性时的行为
#__getattribute__(self,name)
#定义当该类的属性被访问时的行为
#__setattr__(self, name, value)
#定义当一个属性被设置时的行为
#__delattr__(self, name)
#定义当一个属性被删除时的行为
'''
class Test:
def __getattritube__(self, name):
print('getattribute')
return super().__getattribute__(name)
def __getattr__(self, name):
print('getattr')
def __setattr__(self, name, value)
print('setattr')
super().__setattr__(name, value)
def __delattr__(self, name):
print('delattr')
super().__delattr__(name)
print(c.x)
#会先打印getattributel来直接访问,不存在才会调用__getattr__()
getattribute
c.x = 1 -> setattr
getattr
print(c.x) -> getattribute,存在不会调用__getattr__()
del c.x -> delattr
#重写属性访问魔法方法时一定要注意防止死循环
#例:
class Test:
def __setattr__(self, name, value):
1:self.name = value
2:super().__setattr__(name, value)
3:self.__dict__[name] = value
#1:造成死循环,因为无限调用了__setattr__()
#易出错
class Counter:
def __init__(self):
self.counter = 0
def __setattr__(self, name, value):
self.counter += 1
super().__setattr__(name, value)
def __delattr__(self, name):
self.counter -= 1
super().__delattr__(name)
#当实例化对象时:会有异常-> AttributeError: 'Counter' object has no attribute 'counter'
#原因:在初始化方法中:self.counter = 0 会调用__setattr__, 而我们重写了__setattr__,其中的self.counter还没有定义!!
'''
#--------------------------------------------------------------------
#描述符:一个类
#描述符就是将某种特殊类型的类的实例指派给另一个类的属性
#特殊类型的类:至少要实现以下三个方法(描述符属性的方法)的一个
#__get__(self, instance, owner):用于访问属性,返回属性的值
#__set__(self, instance, value):将在属性分配操作中调用,不返回任何内容
#__delete__(self, instance):控制删除操作,不返回任何内容
'''
#例:
class Desc:#描述符
def __get__(self, instance, owner):
print('__get__')
print('self:\t', self)
print('instance:\t', instance)
print('own:\t', owner)
class TestDesc:
x = Desc()
t = TestDesc()
print(t.x)
#输出:
__get__
self: <__main__.Desc object at 0x00000216E3DF4160>
instance: <__main__.TestDesc object at 0x00000216E3E0E860>
own: <class '__main__.TestDesc'>
'''
#self:Desc的实例对象:x
#instanc:TestDesc的实例对象:t
#owner:拥有者,TestDesc
#--------------------------------------------------------------------
#定制容器和迭代器
#定制容器:
#如果说你希望定制的容器是不可变的话,你只需要定义__len__()和__getitem__()方法
#如果你希望定制的容器是可变的话,除了__len__()和__getitem__()方法,你还需要定义__setitem__()和__delitem__()两个方法
#__len__(self): 定义当被 len() 调用时的行为(返回容器中元素的个数)
#__getitem__(self, key):定义获取容器中指定元素的行为,相当于 self[key]
#__setitem__(self, key, value): 定义设置容器中指定元素的行为,相当于 self[key] = value
#__delitem__(self, key): 定义删除容器中指定元素的行为,相当于 del self[key]
#迭代器:
#iter() -> __iter__()
#next() -> __next__()
'''
#iter(), next()小例子
string = 'next'
it = iter(string)
while True:
try:
each = next(string)#next()的参数为迭代器
print(each, end='')
except StopIteration:
break
'''
#在python中关于迭代的两个概念:第一个是Iterable, 第二个是Iterator,协定规定Iterable的__iter__方法会返回一个Iterator,Iterator的__next__方法会返回下一个迭代对象。
'''
#序列,字典,集合,文件为可迭代对象(Iterable), 通过iter()可转换为迭代器
import collections as co
isinstance([], co.Iterator) -> False
isinstance(iter([]), co.Iterator) -> True
'''
#普通类中重写了__iter__, __next__的实例对象为迭代器
'''
例1:斐波那契数列
class Fibs:
def __init__(self):
self.a = 0
self.b = 1
def __iter__(self):#自己为迭代器,返回自己
return self
def __next__(self):
self.a, self.b = self.b, self.a+self.b
if self.a > 20:
raise StopIteration
return self.a
fibs = Fibs()
for i in fibs:
print(i)
isinstance(fibs, co.Iterator) -> True
例2;迭代器功能为逆序
class myRev:
def __init__(self, string):
self.string = string
self.index = len(self.string)-1
def __iter__(self):
return self
def __next__(self):
if self.index < 0:
raise StopIteration
temp = self.string[self.index]
self.index -= 1
return temp
s = myRev('abcde')
for each in s:
print(each, end='')
#结果
edcba
'''
#--------------------------------------------------------------------
#生成器:就是迭代器
#详细讲解
#生成器函数:一个生成器函数的定义很像一个普通的函数,除了当它要生成一个值的时候,使用 yield 关键字而不是 return。如果一个 def 的主体包含 yield,这个函数会自动变成一个生成器(即使它包含一个 return)。
#生成器函数返回生成器的迭代器。这可能是你最后一次见到“生成器的迭代器”这个术语了, 因为它们通常就被称作“生成器”。
#当一个生成器函数调用 yield,生成器函数的“状态”会被冻结,所有的变量的值会被保留下来,下一行要执行的代码的位置也会被记录,直到再次调用 next()。
#一旦 next() 再次被调用,生成器函数会从它上次离开的地方开始。如果永远不调用 next(),yield 保存的状态就被无视了。
#生成器只需要一个yield函数即可,其内部会自动创建__iter__()和__next__()方法。
'''
#例
def is_prime(num) #判断是否是素数的函数
#处理无穷序列的常见方法
def get_prime(start): #不断生成从start开始的素数
while True:
if is_prime(start):
yield start #next()的下次会回到该位置
start += 1
prime = get_prime(3)
for i in prime:
if i < 200:
print(i)
else:
break
'''
#复习一下推导式
#列表推导式:list1 = [i for i in range(10) if not(i%2) and i%3]
#字典推导式:dict1 = {i:i%2==0 for i in range(10)}
#集合推导式:set1 = {i for in [1,2,3,4,3,2,1]}
#用小括号生成的推导式就是生成器推导式
'''
gen = (i for i in range(10)) 为迭代器
print(next(gen)) -> 0
print(next(gen)) -> 1
'''
#关键思想:
#1: generator 是用来产生一系列值的
#2: yield 则像是 generator 函数的返回结果
#3: yield 唯一所做的另一件事就是保存一个 generator 函数的状态
#4: generator 就是一个特殊类型的迭代器(iterator)
#5: 和迭代器相似,我们可以通过使用 next() 来从 generator 中获取下一个值
#6: 通过隐式地调用next()来忽略一些值
#--------------------------------------------------------------------
#模块:模块就是程序
#容器 -> 数据的封装
#函数 -> 语句的封装
#类 -> 方法和属性的封装
#模块 -> 模块就是程序
#导入模块
#1:import 模块名 as 替换名
#2:from 模块名 import 函数名 #不管是否使用了函数,一定会先加载函数
#阻止 from…import * 导入你的“私隐”属性
#可以给你不想导入的属性名称的前边加上一个下划线(_)。不过需要注意的是,如果使用 import … 导入整个模块,或者显式地使用 import xx._oo 导入某个属性,那么这个隐藏的方法就不起作用了。
#将模板和类A的对象挂钩
#sys.modules 是一个字典,它包含了从 Python 开始运行起,被导入的所有模块。键就是模块名,值就是模块对象。
'''
import sys
sys.modules[__name__] = A()
'''
#--------------------------------------------------------------------
#__name__
#所有模板都有一个__name__属性,__name__的值取决于如何应用模板,在作为独立程序运行的时候,__name__属性的值是'__main__', 而作为模板引入时,这个值就是该模板的名字了。
#__name__ == '__main__'
#当.py文件被直接运行是,if __name__ == '__main__'的内容才会被运行;当.py文件以模板导入时,if __name__=='__main__'之下的代码不会被执行
#搜索路径
#python可以导入同一个文件夹下的其他.py文件,如果要导入其他文件夹下的,需要在sys.path做处理
#sys模块中有 sys.path为一个列表,里面存放着模块存放的路径,当我们导入模块时,系统便在列表中的路径搜索。
#当我们自己写的模块要在非同一个文件夹下导入时,需要sys.append('模块路径')加入列表。
#包(package)
#创建包
#1:创建一个文件夹,用于存放相关的模板,文件夹的名字即包的名字
#2:在文件夹中创建一个__init__.py的模板文件,内容可以为空
#3:将相关的模板放入文件夹中
#导入包中的模板: import 包名.模板名(也不要忘记把包的路径加入sys.path)
#--------------------------------------------------------------------