本文是笔者学习廖雪峰Python3教程的笔记,在此感谢廖老师的教程让我们这些初学者能够一步一步的进行下去.如果读者想学习完成的教程,请访问廖雪峰Python3教程,笔记如有侵权,请告知删除...
__slots__
- 使用__slots__来限制实例能添加的属性
- 使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
- 除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__。
class Student(object):
__slots__ = ('name', 'age')
@property
- 把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值
class Screen(object):
@property
def width(self):
return self._width
@width.setter
def width(self, value):
self._width = value
@property
def height(self):
return self._height
@height.setter
def height(self, value):
self._height = value
@property
def resoluation(self):
return self._width*self._height
MixIn
MixIn是一种多继承, 只需要在定义类型后面的小括号里用逗号分割添加新的继承类即可
class MyTCPServer(TCPServer, ForkingMixIn):
pass
```
#定制类
类似\_\_slots\_\_这种形如\_\_xxx\_\_的变量或者函数名就要注意,这些在Python中是有特殊用途的。例如\_\_len\_\_()方法是为了能让class作用于len()函数。
- ## \_\_str__
def str(self):
return 'Student object (name: %s)' % self.name
在类中写这段 使用print进行打印输出的时候就会按照格式显示,但是如果不用print打印则不会按照格式输出
这是因为直接显示变量调用的不是\_\_str\_\_而是\_\_repr\_\_()来返回用户看到的字符串,而\_\_repr\_\_()返回的是程序开发者所看到的字符串,也就是说\_\_repr\_\_()是为调试服务的.
解决办法是在写一个\_\_repr\_\_()方法,但是由于\_\_str\_\_和\_\_repr\_\_()方法通常一样,所以简单的写法为
```class Student(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Student object (name=%s)' % self.name
__repr__ = __str__
```
- ## \_\_iter\_\_
如果一个类想被用于for...in循环,类似list和tuple.那就必须实现一个\_\_iter\_\_()方法,该方法的返回值是一个可迭代的对象,然后Python的for循环就会不断调用\_\_next\_\_()方法拿到循环的下一个值,知道遇到stopIteration抛出异常为止
```
#斐波那契数列
class Fib(object):
def __init__(self):
self.a, self.b = 0, 1 # 初始化两个计数器a,b
def __iter__(self):
return self # 实例本身就是迭代对象,故返回自己
def __next__(self):
self.a, self.b = self.b, self.a + self.b # 计算下一个值
if self.a > 100000: # 退出循环的条件
raise StopIteration();
return self.a # 返回下一个值
-
__getitem__
实现了__iter__方法之后,虽然能够使用for循环进行迭代,但是并不能像list似的使用下标来访问其中的元素,若要实现该功能则需要实现__getitem__()方法
class Fib(object):
def __getitem__(self, n):
a, b = 1, 1
for x in range(n):
a, b = b, a + b
return a
这样做虽然可以使用下标进行访问了,但是对于list(range(10))[2:9]这样的切片方法却行不通,原因是getitem()传入的参数可能是一个int,也可能是一个切片对象slice,这个时候就需要就传入的参数进行判断了
-
__getattr__
使用Python的另一个机制是写一个getattr()方法,动态返回一个属性。可以避免因为调用不存在的属性出现的错误.这个方法只有在没有找到属性的情况下才会调用, 这个方法同样可以返回一个函数.
class Student(object):
def __init__(self):
self.name = 'Michael'
def __getattr__(self, attr):
if attr=='score':
return 99
# 返回一个函数
class Student(object):
def __getattr__(self, attr):
if attr=='age':
return lambda: 25
这样在调用Student类的score这个不存在的属性的时候就不会出现错误信息而是返回99这个数
- __call__
一个对象实例可以有自己的属性和方法,当我们调用实例方法时使用__call__可以直接在实例本身上调用方法.
任何类,只需要定义一个__call__()方法,就可以直接对实例进行调用.
class Student(object):
def __init__(self, name):
self.name = name
def __call__(self):
print('My name is %s.' % self.name)
# 调用方法:
s = Student('Joe')
s() # self参数不要传入
My name is Joe.
枚举类
- Python中的枚举类型需要先从enum模块中引入Enum类.
然后创建一个枚举
from enum import Enum
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
如上所示即获得了Month类型的枚举,可以使用Month.Jan, Month.Feb 这种类型进行访问, 也可以使用forin来遍历
for name, member in Month.__members__.items():
print(name, '=>', member, ',', member.value)
member.value是自动给枚举赋值的,赋值从1开始
- 如果要精确的控制枚举类型, 可以从Enum派生出自定义类.
from enum import Enum, unique
@unique
class Weekday(Enum):
Sun = 0 # Sun的value被设定为0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6
其中装饰器@unique的作用是检查name所对应的value值是否唯一
-
访问方式有很多
例如:
Weekday['Tue']
Weekday(1)
Weekday.Sun
Weekday.Tue.value
......
元类
-
type()
Python是一门动态语言,他所有的类和方法都不是在编译的时候创建的,而是在运行的时候创建的.
type()既可以返回一个class类型,也使用type()可以在运行时动态的创建一个class.无需经过
class name(object):
来定义- 首先定义一个方法
def fn(self, name = 'world'): print('Hello %s' % name)
- 使用type()方法创建一个class
Hello = type('Hello', (object, ), dict(hello = fn))
- type()的三个参数
1.第一个参数是定义的class的名字
2.第二个参数是继承的类,这是一个tuple.如果不是多继承的话,需要传入一个单元素的元组(object,)
3.第三个参数是方法名与函数的绑定,将在类外面定义的函数绑定到类的方法上