Python入门记录七

仅为入门记录!

目录

#魔法方法

#算术运算和反运算和增量赋值操作符:

#比较操作符和一元操作符

#属性访问魔法方法

#描述符:一个类

#定制容器和迭代器

#生成器:就是迭代器

#模块:模块就是程序

#__name__



#--------------------------------------------------------------------

#魔法方法

#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)
#--------------------------------------------------------------------

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值