零基础Python(五)

魔法方法

1.魔法方法总是被双下划线包围,例如__init__
2.魔法方法是面向对象的Python的一切,如果不知道魔法方法,说明还没能意识到面向对象的Python的强大
3.魔法方法的魔力体现在它们总能在适当的时候被自动调用
一、构造和析构
1.__init__(self[,...])
相当于其他语言的构造方法,类在实例化的时候首先会被调用的方法
2.__new__(cls[,...])
这个是类实例化第一个调用的魔法方法,在init之前
3.__del__(self)
python析构方法,当类没有任何引用时,就会自动删除掉,ex:

>>> class C:
	def __init__(self):
		print('我是__init__,我被调用了')
	def __del__(self):
		print('我是__del__,我被调用了')

		
>>> c1=C()
我是__init__,我被调用了
>>> c2=c1
>>> c3=c1
>>> del c3
>>> del c2
>>> del c1
我是__del__,我被调用了
>>> 

二、算术运算
python的魔法方法还支持自定义类的数值处理,通过对魔法方法的重写,可以自定义任何对象之间的算数运算。算数运算魔法方法如下:

1.__add__(self,other)--->定义加法的行为:+
2.__sub__(self,other)--->定义减法的行为:-
3.__mul__(self,other)--->定义乘法的行为:*
4.__truediv__(self,other)--->定义真除法的行为:/
5.__floordiv__(self,other)--->定义整数除法的行为://
6.__mod__(self,other)--->定义取模算法的行为:%
7.__divmod__(self,other)--->定义当被divmod()调用时的行为
8.__pow__(self,other[,modulo])--->定义当被power()调用或**运算的时的行为
9.__lshift__(self,other)--->定义按位左移位的行为:<<
10.__rshift__(self,other)--->定义按位右移位的行为:>>
11.__and__(self,other)--->定义按位与操作的行为:
&
12.__xor__(self,other)--->定义按位异或操作的行为:^
13.__or__(self,other)--->定义按位或操作的方法:|
14.

ex:

>>> class NewAdd(int):
	def __add__(self,other):
		return int.__sub__(self,other)
	def __sub__(self,other):
		return int.__add__(self,other)

	
>>> a=NewAdd(3)
>>> b=NewAdd(7)
>>> a+b
-4
>>> a-b
10
>>> 

这里一定要搞清对象之间的关系!如果直接加是什么情况,你可以试试看,不是老师说,我还真没想到!,ex:

>>> class NewAdd(int):
	def __add__(self,other):
		return self+other
	def __sub__(self,other):
		return self-other

	
>>> a=NewAdd(3)
>>> b=NewAdd(7)
>>> a+b
Exception ignored in: <function NewAdd.__del__ at 0x00000201DA228950>
TypeError: __del__() missing 1 required positional argument: 'other'
Exception ignored in: <function NewAdd.__del__ at 0x00000201DA228950>
TypeError: __del__() missing 1 required positional argument: 'other'
Traceback (most recent call last):
  File "<pyshell#103>", line 1, in <module>
    a+b
  File "<pyshell#100>", line 3, in __add__
    return self+other
  File "<pyshell#100>", line 3, in __add__
    return self+other
  File "<pyshell#100>", line 3, in __add__
    return self+other
  [Previous line repeated 990 more times]
RecursionError: maximum recursion depth exceeded

return a+b中的+,会再调用类的__add__,然后又调用+,无限循环~~
还有一种情况:

>>> class int(int):
	def __add__(self,other):
		return int.__sub__(self,other)

	
>>> a=int('5')
>>> a
5
>>> b=int(3)
>>> a+b
2

这里默默把int替换成我们自定义的int类
反运算

__radd__(self,other):与上方相同,当左操作不支持相应的操作时被调用
....

左边没有定义可操作的方法时,就会调用右侧的方法,ex:

>>> class Nint(int):
	def __radd__(self,other):
		return int.__sub__(self,other)


>>> a=Nint(5)
>>> b=Nint(3)
>>> a+b
8
>>> 1+a
4
>>> 
>>>> a+1
6
>>> 1-a
-4
>>> a-1
4

这里a和b都定义了方法,执行正常的加法运算,而1+a中,1没有定义方法,a定义了,就会调用a的加法,也就是减法,即1+a其实就等价于与a-1,其他的都是这个道理了

简单定制

基本要求:
–定制一个计时器的类
–start和stop方法代表启动计时和停止计时
–假设计时器对象t1,print(t1)和直接调用t1
均显示结果
–当计时器未启动或已经停止计时,调用stop方法会给予温馨的提示
–两个计时器对象可以进行相加:t1+t2
–只能使用提供的有限资源完成
提供的资源:
使用time模块的localtime方法获取时间
–扩展阅读:time模块详解(时间获取和转换)
time.localtime犯规struct_time的时间格式
表现你的类:__str__和__repr__

time.localtime([ sec ])

sec – 转换为time.struct_time类型的对象的秒数。
ex:

import time
 
print( "time.localtime() : %s" % time.localtime())

输出结果:

time.localtime() : time.struct_time(tm_year=2016, tm_mon=11, tm_mday=27, tm_hour=10, tm_min=26, tm_sec=5, tm_wday=6, tm_yday=332, tm_isdst=0)
int tm_sec; /* 秒 – 取值区间为[0,59] */
int tm_min; /* 分 - 取值区间为[0,59] */
int tm_hour; /* 时 - 取值区间为[0,23] */
int tm_mday; /* 一个月中的日期 - 取值区间为[1,31] */
int tm_mon; /* 月份(从一月开始,0代表一月) - 取值区间为[0,11] */
int tm_year; /* 年份,其值等于实际年份减去1900 */
int tm_wday; /* 星期 – 取值区间为[0,6],其中0代表星期天,1代表星期一,以此类推 */
int tm_yday; /* 从每年的1月1日开始的天数 – 取值区间为[0,365],其中0代表1月1日,1代表1月2日,以此类推 */
int tm_isdst; /* 夏令时标识符,实行夏令时的时候,tm_isdst为正。不实行夏令时的时候,tm_isdst为0;不了解情况时,tm_isdst()为负。

介绍两个魔法方法:

__str__和__repr__
>>> class A():
	def __str__(self):
		return 'What a Fuck?'

	
>>> a=A()
>>> a
<__main__.A object at 0x000002327D2A3630>
>>> print(a)
What a Fuck?
>>> class B():
	def __repr__(self):
		return 'God!'

	
>>> b=B()
>>> print(b)
God!
>>> 

__repr__和__str__这两个方法都是用于显示的,__str__是面向用户的,而__repr__面向程序员。


class Me(object):
 
    def __init__(self, name, hobby):
        self.name = name
        self.hobby = hobby
 
    def __str__(self):
        return (' __str__(): '+self.name + '   ' + self.hobby)
 
    def  __repr__(self):
        return ('__repr__(): '+self.name + '   ' + self.hobby)
 
 
me = Me('frank', 'swiming')
print(me)
 ----->
__str__(): frank   swiming

计时器最终代码:

import time as t
class myTimer():

    def __init__(self):
        self.unit=['年','月','日','小时','分钟','秒']
        self.prompt='未开始计时!'
        self.lasted=[]
        self.begin=0
        self.end=0
    def __str__(self):
        return self.prompt
    
    __repr__=__str__

    def __add__(self,other):
        prompt='总共运行了:'
        result=[]
        for index in range(6):
            result.append(self.lasted[index]+other.lasted[index])
            if result[index]:
                prompt+=(str(result[index]))+self.unit[index]
        return prompt        
    #开始计时
    def start(self):
        self.begin=t.localtime()
        #为了防止不调用stop就直接str的
        self.prompt='请先调用stop()方法停止计时!'
        print('计时开始...')
        
    #结束计时
    def stop(self):
        if self.begin:
            self.end=t.localtime()
            #调用自身方法,一定不要忘了self...
            self._calc()
            print('计时结束!')
        else:
            print('请先调用start开始计时!')
        
    #内部方法,计算运行时间
    def _calc(self):
        self.lasted=[]
        self.prompt='总共运行了:'
        #6个队列存储6个时间分段
        for index in range(6):
            self.lasted.append(self.end[index]-self.begin[index])
            #为0的时候就是False,否则为True
            if self.lasted[index]:
                self.prompt+=str(self.lasted[index])+self.unit[index]
        #为下一次计时初始化
        self.begin=0
        self.end=0
           

魔法方法:属性访问
非魔法方法:
1.类名.属性名
2.getattr(类名,‘属性名’,[默认值])

>>> class A:
	def __init__(self):
		self.x='Bingo!'

		
>>> a=A()
>>> a.x
'Bingo!'
>>> getattr(a,'x','zgd')
'Bingo!'
>>> getattr(a,'y','zgd')
'zgd'
>>> 

属性访问相关魔法方法:
1.__getattr__(self,name)
定义当用户视图获取一个不存在的属性时的行为
2.__getattribute__(self,name)
定义该类的属性被访问时的行为
3.__setattr__(self,name,value)
定义当一个属性被设置时的行为
4.__delattr__(self,name)
定义当一个属性被删除时的行为

魔法方法:描述符 (Property的原理)
描述符就是将某种类型的类的实例指派给另一个类的属性(由一个人的儿子变成另一个人的孙子?)

__get__(self,instance,owner)

用于访问属性,它返回属性的值

__set__(self,instance,value)

将在属性分配操作中调用,不返回任何内容

__delete__(self,instance)

控制删除操作,不返回任何内容

魔法方法:定制序列
在Python中的协议没有那么正式,更像是一种指南。
一、容器类型的协议
如果说定制的容器是不可变的话,只需要定义__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__(self):定义当迭代容器中的元素的行为
__reversed__(self):定义当被reversed()调用时的行为
__contains__(self,item):定义当使用成员测试运算符(in
or not in)时的行为

先学习一下两个知识点:
一.列表推导式
列表推导式提供了一种可以快速创建list的简便方法,应用列表穿件列表时,列表中的元素来源于其他序列、可迭代对象或创建的一个满足一定条件的序列。
1.使用[]生成list
基本格式:
[表达式 for 变量 in 列表]或者[表达式 for 变量 in 列表 if 条件
]
example:
简单点的:

>>> list1=['Bob','Alive','Death','Aid']
>>> [item.upper() for item in list1]
['BOB', 'ALIVE', 'DEATH', 'AID']

复杂点的:
求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的元组列表。

>>> [(x,y) for x in range(0,5) if x%2==0 for y in range(0,5) if y%2==1]
[(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)]

这里顺带一提,python3和python2对于range()函数的返回值是不一样的,2中返回的是一个列表,可以直接打印出来,3中返回的是一个对象,得通过循环打印出来:

>>> for item in range(10):
	print(item)

	
0
1
2
3
4
5
6
7
8
9

二、字典(dict)的fromkeys方法
fromkeys()函数用于创建一个新字典,以序列seq中元素做字典的键,value为字典所有键对应的初始值,语法为:
dict.formkeys(seq[,value])
返回值是字典。
ex:

seq=['name','age','sex']
dict11=dict.fromkeys(seq)
print('新的字典为:%s' % str(dict11))
-->
新的字典为 : {'age': None, 'name': None, 'sex': None}

这里dict可以替换为空字典:{}

来个练习:
编写一个不可改变的自定义列表,要求记录列表中每个元素被访问的次数。

这里,我们可以将每个元素所在的下标作为key值,利用字典(dict)【可以理解成Java中的HashMap】存储起来。

>>> class Ryelist:
	def __init__(self,*args):
		print(args)
		self.values=[x for x in args]
		self.dicts={}.fromkeys(range(len(self.values)),0)
	def __len__(self):
		return len(self.values)
	def __getitem__(self,key):
		self.dicts[key]+=1
		return self.dicts[key]

	
>>> test=Ryelist(1,3,5,7)
(1, 3, 5, 7)
>>> test[1]
1
>>> test.dicts
{0: 0, 1: 1, 2: 0, 3: 0}
>>> 

魔法方法:迭代器
python的迭代器提供了两个BIF:
next()、iter()
调用对象的iter()返回它的迭代器
调用next()返回下一个值
当没有下一个对象的时候抛出异常。
ex:

>>> list1=['Rye','Catcher','MySelf']
>>>> item=iter(list1)
>>> next(item)
'Rye'
>>> next(item)
'Catcher'
>>> 

这两个BIF对应的魔法方法为:

__iter__()、__next__()

ex:
定义一个斐波那契数列:

>>> class Fib:
	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
		return self.a

	
>>> fibs=Fib()
>>> for each in fibs:
	if each<20:
		print(each)
	else :
		break;

	
1
1
2
3
5
8
13
>>> 

这里加了限制20以内的,不然会一直输出,会报异常的。。
可以再定义的时候就限制一下大小,如下:

>>> class Fib:
	def __init__(self,num=10):
		self.a=0
		self.b=1
		self.num=num
	def __iter__(self):
		return self
	def __next__(self):
		self.a,self.b=self.b,self.a+self.b
		if self.a<self.num:
			return self.a
		else :
			raise StopIteration

		
>>> fib=Fib(100)
>>> for each in fib:
	print(each)

	
1
1
2
3
5
8
13
21
34
55
89
>>> 

生成器
python的生成器是一个返回可以迭代对象的函数。
生成器函数与一般函数的不同点:
1.生成器函数包含一个或多个yield
2.当调用生成器函数时,函数将返回一个对象,但是不会立刻向下执行
3.想iter和next方法等都是自动实现的,所以我们可以通过next方法对对象进行迭代
4.一旦函数被yield,函数会暂停,控制权返回调用者
5.局部变量和他们的状态会被保存,直到下一次调用
6.函数终止的时候, StopIteration会被自动抛出
ex:

>>> def myGen():
	print('调用生成器')
	yield 1
	yield 2

	
>>> gen=myGen()
>>> next(gen)
调用生成器
1
>>> next(gen)
2
>>> next(gen)
Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    next(gen)
StopIteration
>>> 

这里可以将yield当成return,只不过区别是return 下面的语句不会执行,而yield底下的语句会在下次调用的时候继续执行,直到没有yield的时候抛出StopIteration异常。
使用yield实现斐波那契数列:

>>> def libs():
	a=0
	b=1
	while True:
		a,b=b,a+b
		yield a

>>> for each in libs():
	if each >100:
		break
	print(each,end=' ')

	
1 1 2 3 5 8 13 21 34 55 89 


yield每次暂停,print中加一个end=’ ',表示已空白符作为分割符,这样就不会一列一列输出了。

除了列表推导式外还有字典推导式
列表推导式例子:

>>> a=[i for i in range(100) if not(i%2) and i%3]
>>> a
[2, 4, 8, 10, 14, 16, 20, 22, 26, 28, 32, 34, 38, 40, 44, 46, 50, 52, 56, 58, 62, 64, 68, 70, 74, 76, 80, 82, 86, 88, 92, 94, 98]
>>> 
``字典推导式:
字典和集合推导式是列表推导式思想的延续,语法差不多,只不过产生的是字典和集合而已,字典推导式如下:
{key_expr:value_expr for value in collection if condition}
ex:

b={i:i % 2==0 for i in range(10)}
b
{0: True, 1: False, 2: True, 3: False, 4: True, 5: False, 6: True, 7: False, 8: True, 9: False}

集合(set)推导式:

a={i for i in {1,2,3,4,3,2,1}}
a
{1, 2, 3, 4}

因为集合没有重复元素嘛,所以这样。列表,字典,集合推导式原理都是一样的。

模块就是程序

容器–>数据的封装
函数–>语句的封装
类----->方法和属性的封装
模块–>模块就是程序

实际上,将代码保存为一个py文件,就可以当做一个模块,即一个程序。为了能保证这个模块能被我们启动的idle调用,需要将两者放在同一文件夹下。
在这里插入图片描述
因为有命名空间的限制,所以引用模块里的方法变量的时候,前面一定要先加上模块的名字。
导入模块的三种方法:
第一种:import 模块名
第二种:from 模块名 import 函数名【导入模块某个函数】
这个第二种主要是应对一种情况,就是模块名比较长,每次调用前还要输入模块名,这样有时候也就有点麻烦了;采用这种方式后,可以直接将模块里面的函数导入,这样我们就可以不用加模块名而直接引用了。【不过这样很容易导致命名混乱,强烈不推荐使用】
第三种:from 模块名 as 新名字
这种最好了,估计用这种的最多。
至此,初学部分结束,下面开启看书总结。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值