美文网首页
pythonic和面向对象

pythonic和面向对象

作者: 我是上帝可爱多 | 来源:发表于2017-08-02 14:22 被阅读33次

    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]
    

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

    相关文章

      网友评论

          本文标题:pythonic和面向对象

          本文链接:https://www.haomeiwen.com/subject/fsuelxtx.html