1 类的定义
假设需要定义一个人
# person.py
class Person:
def __init__(self, age=18, code=3):
self.age, self.code = age, code
def total(self):
return self.age + self.code
上述是一个构造函数,如果在java里面我们这样玩,会这样写:
public class Person{
private int age;
private int code;
public Person(age,code){
this.age = age;
this.code = code
}
getter,setter省略...
}
我们需要注意的是python这种连等方式。
from person import *
p = Person(10, 10) # __init__ 被调用
type(p)
<class 'person.Person'>
p.age, p.code
(10, 10)
我们在person初始化的方法上写了,2个默认值。
对一切皆对象的 Python 来说,类自己当然也是对象:
type(Person)
<class 'type'>
dir(Person)
['__class__', '__delattr__', '__dict__', ..., '__init__','total' ...]
Person.__class__
<class 'type'>
使用dir()函数可以查看对像内所有属于及方法,在python中任何东西都是对像,一种数据类型,一个模块等,都有自己的属性和方法,除了常用方法外,其它的你不需要全部记住它,交给dir()函数就好了。
查看列表都有哪些方法
dir([ ])
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__',
'__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__',
'__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__',
'__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__',
'__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count',
'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
很好,我们的到了列表所有的方法,熟悉的有append,insert等,具体不说明了。好我们继续看
class Person:
...
def set(self, x, y):
self.x, self.y = x, y
p = Person(10, 10)
p.set(0, 0)
p.x, p.y
(0, 0)
p.set(...) 其实只是一个语法糖,你也可以写成 Point.set(p, ...),这样就能明显看出 p 就是 self 参数了:
Point.set(p, 0, 0)
p.x, p.y
(0, 0)
上面这种写法,是一样的。
访问控制
Python 没有 public / protected / private 这样的访问控制,如果你非要表示“私有”,习惯是加双下划线前缀。
class Point:
def __init__(self, x=0, y=0):
self.__x, self.__y = x, y
def set(self, x, y):
self.__x, self.__y = x, y
def __f(self):
pass
__x、__y 和 __f 就相当于私有了:
>>> p.__x
...
AttributeError: 'Point' object has no attribute '__x'
>>> p.__f()
...
AttributeError: 'Point' object has no attribute '__f'
尝试打印 Point 实例:
>>> p = Point(10, 10)
>>> p
<point.Point object at 0x000000000272AA20>
可以看到我们打印出了这个p对象,如果我们想换一种方式呢?
class Point:
def __repr__(self):
return 'Point({}, {})'.format(self.__x, self.__y)
>>> repr(p)
'Point(10, 10)'
我们在一个类中自定义了一个repr方法,调用他。下面我们来看一些野路子。。。
装饰器@staticmethod和@classmethod有什么区别?
class A(object):
def foo(self,x):
print "executing foo(%s,%s)"%(self,x)
@classmethod
def class_foo(cls,x):
print "executing class_foo(%s,%s)"%(cls,x)
@staticmethod
def static_foo(x):
print "executing static_foo(%s)"%x
a=A()
a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>,1)
a.class_foo(1)
# executing class_foo(<class '__main__.A'>,1) //注意传递的是cls
A.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)
一个简单的例子很直接说明了classmethod的用法
class Kls(object):
no_inst = 0
def __init__(self):
Kls.no_inst = Kls.no_inst + 1
@classmethod
def get_no_of_instance(cls_obj):
return cls_obj.no_inst
ik1 = Kls()
ik2 = Kls()
ik3 = Kls()
print ik1.get_no_of_instance()
print Kls.get_no_of_instance()
// output 3
2 类的继承
举一个教科书中最常见的例子。Circle 和 Rectangle 继承自 Shape,不同的图形,面积(area)计算方式不同。
# shape.py
class Shape:
def area(self):
return 0.0
class Circle(Shape):
def __init__(self, r=0.0):
self.r = r
def area(self):
return math.pi * self.r * self.r
class Rectangle(Shape):
def __init__(self, a, b):
self.a, self.b = a, b
def area(self):
return self.a * self.b
>>> from shape import *
>>> circle = Circle(3.0)
>>> circle.area()
28.274333882308138
>>> rectangle = Rectangle(2.0, 3.0)
>>> rectangle.area()
6.0
继承的方式很简单,在类名上加个括号就行。
如果 Circle 没有定义自己的 area:
class Circle(Shape):
pass
>>> Shape.area is Circle.area
True
一旦 Circle 定义了自己的 area,从 Shape 继承而来的那个 area 就被重写(overwrite)了:
>>> from shape import *
>>> Shape.area is Circle.area
False
通过类的字典更能明显地看清这一点:
>>> Shape.__dict__['area']
<function Shape.area at 0x0000000001FDB9D8>
>>> Circle.__dict__['area']
<function Circle.area at 0x0000000001FDBB70>
所以,子类重写父类的方法,其实只是把相同的属性名绑定到了不同的函数对象。可见 Python 是没有覆写(override)的概念的。
甚至可以动态的添加方法:
class Circle(Shape):
...
# def area(self):
# return math.pi * self.r * self.r
# 为 Circle 添加 area 方法。
Circle.area = lambda self: math.pi * self.r * self.r
lambda表达式返回一个函数对象。
这样吧我们写一个完整的继承代码把
输出
3 多态
如前所述,Python 没有覆写(override)的概念。严格来讲,Python 并不支持「多态」。
#!/usr/bin/env Python
class Animal:
def __init__(self, name=""):
self.name = name
def talk(self):
pass
class Cat(Animal):
def talk(self):
print "Meow!"
class Dog(Animal):
def talk(self):
print "Woof!"
a = Animal()
a.talk()
c = Cat("Missy")
c.talk()
d = Dog("Rocky")
d.talk()
其实我没有虎你,python里的多态看起来确实很low。。。下面讲一个知识点
#!/usr/bin/env Python
class ProtectMe:
def __init__(self):
self.me = "qiwsir"
self.__name = "kivi"
@property
def name(self):
return self.__name
if __name__ == "__main__":
p = ProtectMe()
print p.name
怎么样知道如何访问私有属性了把。。
最后给大家带来一波福利,我这里只贴代码了,大家细看
itertools库
迭代器(生成器)在Python中是一种很常用也很好用的数据结构,比起列表(list)来说,迭代器最大的优势就是延迟计算,按需使用,从而提高开发体验和运行效率,以至于在Python 3中map,filter等操作返回的不再是列表而是迭代器。
itertools.accumulate
>>> import itertools
>>> x = itertools.accumulate(range(10))
>>> print(list(x))
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
原函数是这样写的
def accumulate(iterable, func=operator.add):
'Return running totals'
# accumulate([1,2,3,4,5]) --> 1 3 6 10 15
# accumulate([1,2,3,4,5], operator.mul) --> 1 2 6 24 120
it = iter(iterable)
try:
total = next(it)
except StopIteration:
return
yield total
for element in it:
total = func(total, element)
yield total
data = [3, 4, 6, 2, 1, 9, 0, 7, 5, 8]
>>> list(accumulate(data, operator.mul)) # running product
[3, 12, 72, 144, 144, 1296, 0, 0, 0, 0]
itertools.chain
>>> x = itertools.chain(range(3), range(4), [3,2,1])
>>> print(list(x))
[0, 1, 2, 0, 1, 2, 3, 3, 2, 1]
itertools.combinations
求列表或生成器中指定数目的元素不重复的所有组合
>>> x = itertools.combinations(range(4), 3)
>>> print(list(x))
[(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)]
itertools.compress
按照真值表筛选元素
>>> x = itertools.compress(range(5), (True, False, True, True, False))
>>> print(list(x))
[0, 2, 3]
itertools.islice
def islice(iterable, *args):
# islice('ABCDEFG', 2) --> A B
# islice('ABCDEFG', 2, 4) --> C D
# islice('ABCDEFG', 2, None) --> C D E F G
# islice('ABCDEFG', 0, None, 2) --> A C E G
s = slice(*args)
it = iter(range(s.start or 0, s.stop or sys.maxsize, s.step or 1))
try:
nexti = next(it)
except StopIteration:
return
for i, element in enumerate(iterable):
if i == nexti:
yield element
nexti = next(it)
itertools.count(start=0, step=1)
# count(10) --> 10 11 12 13 14 ...
# count(2.5, 0.5) -> 2.5 3.0 3.5 ...
n = start
while True:
yield n
n += step
>>> x = itertools.count(start=20, step=-1)
>>> print(list(itertools.islice(x, 0, 5, 2)))
[20, 18, 16, 14,12]
itertools.cycle
>>> x = itertools.cycle('ABC')
>>> print(list(itertools.islice(x, 0, 10, 1)))
['A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C', 'A']
itertools.filterfalse
>>> x = itertools.filterfalse(lambda e: e < 5, (1, 5, 3, 6, 9, 4))
>>> print(list(x))
[5, 6, 9]
itertools.groupby
>>> x = itertools.groupby(range(10), lambda x: x < 5 or x > 8)
>>> for condition, numbers in x:
... print(condition, list(numbers))
True [0, 1, 2, 3, 4]
False [5, 6, 7, 8]
True [9]
好了,今天的讲解也到这里了,我得去写代码了。。。