pythonic和面向对象

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)

p.age, p.code
(10, 10)

我们在person初始化的方法上写了,2个默认值。
对一切皆对象的 Python 来说,类自己当然也是对象:

type(Person)

dir(Person)
['__class__', '__delattr__', '__dict__', ..., '__init__','total' ...]
Person.__class__

使用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

可以看到我们打印出了这个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(,1) //注意传递的是cls

A.class_foo(1)
# executing class_foo(,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']

>>> Circle.__dict__['area']

所以,子类重写父类的方法,其实只是把相同的属性名绑定到了不同的函数对象。可见 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表达式返回一个函数对象。
这样吧我们写一个完整的继承代码把

pythonic和面向对象_第1张图片
pythonic和面向对象_第2张图片

输出

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]

好了,今天的讲解也到这里了,我得去写代码了。。。

你可能感兴趣的:(pythonic和面向对象)