Python类与类的关系\字典高级用法\元类\混入\生成器\gitt

一、类与类的关系

  • is-a 继承

    继承指的是一个类(称为子类、子接口)继承另外的
    一个类(称为父类、父接口)的功能,
    并可以增加它自己的新功能的能力。
  • has-a 关联/聚合/合成

    关联体现的是两个类之间语义级别的一种强依赖关系,比如我和我的朋友,
    这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,
    一般是长期性的,而且双方的关系一般是平等的。
    关联可以是单向、双向的。表现在代码层面,
    为被关联类B以类的属性形式出现在关联类A中,
    也可能是关联类A引用了一个类型为被关联类B的全局变量。 
    
    聚合是关联关系的一种特例,它体现的是整体与部分的关系,
    即has-a的关系。此时整体与部分之间是可分离的,
    它们可以具有各自的生命周期,部分可以属于多个整体对象,
    也可以为多个整体对象共享。比如计算机与CPU、公司与员工的关系等,
    比如一个航母编队包括海空母舰、驱护舰艇、舰载飞机及核动力攻击潜艇等。
    表现在代码层面,和关联关系是一致的,只能从语义级别来区分。 
    
    组合也是关联关系的一种特例,它体现的是一种contains-a的关系,
    这种关系比聚合更强,也称为强聚合。它同样体现整体与部分间的关系,
    但此时整体与部分是不可分的,整体的生命周期结束也就意味着部分的生命周
    期结束,比如人和人的大脑。表现在代码层面,和关联关系是一致的,
    只能从语义级别来区分。 
    
  • use-a 依赖

简单的理解,依赖就是一个类A使用到了另一个类B,而这种使用关系是具有偶然性的、
临时性的、非常弱的,但是类B的变化会影响到类A。
比如某人要过河,需要借用一条船,此时人与船之间的关系就是依赖。 
表现在代码层面为: 类B作为参数被类A在某个method方法中使用。 

类与类关系的强弱程度依次为:组合>聚合>关联>依赖

【参考:https://blog.csdn.net/u014470581/article/details/62036457

二、彩蛋

1、python之禅

import this

这里写图片描述

2、python漫画

import antigravity

3、查看帮助

#查看关键字
help("keywords")

三、字典高级用法

1、字典推导式

list1 = ['a','b','c']
dict1 = {k:i for i,k in enumerate(list1) }
print(dict1)
结果为:
{'a': 0, 'b': 1, 'c': 2}

2、字典按值排序

dict1 = {'a': 1,'b': 6,'c': 55,'d': 1,'f': 0}

sort = sorted(zip(dict1.values(),dict1.keys()))
sort_dict1 = {v:k for k,v in sort}
print(sort_dict1)
结果为:
{'f': 0, 'a': 1, 'd': 1, 'b': 6, 'c': 55}

3、字典值过滤

dict1 = {'a': 1,'b': 6,'c': 55,'d': 1,'f': 0}
# 方式1
dict1_gt1 = {key: value for key, value in dict1.items()
                    if value > 1}
print(dict1_gt1)

# 方式2
dict1_gt2 = {x:dict1[x] for x in filter(lambda x:dict1[x] > 1,dict1)}

print(dict1_gt2)
结果为:
{'b': 6, 'c': 55}
{'b': 6, 'c': 55}

四、查找最大或最小的N个元素

使用堆区的大根堆与小根堆来实现。

大根堆:数据以类似树的结构把按大到小排序;

小根堆:数据以类似树的结构把按小到大排序.

import heapq

list1 = [34, 25, 12, 99, 87, 63, 58, 78, 88, 92]
list2 = [
        {'name': 'IBM', 'shares': 100, 'price': 91.1},
        {'name': 'AAPL', 'shares': 50, 'price': 543.22},
        {'name': 'FB', 'shares': 200, 'price': 21.09},
        {'name': 'HPQ', 'shares': 35, 'price': 31.75},
        {'name': 'YHOO', 'shares': 45, 'price': 16.35},
        {'name': 'ACME', 'shares': 75, 'price': 115.65}
    ]
# 列表取前5个最大的值
print(heapq.nlargest(5, list1))
# 列表取前5个最小的值
print(heapq.nsmallest(3, list1))

# 元素按'price'排序取前2个最大的值
print(heapq.nlargest(2, list2, key=lambda x: x['price']))
print(heapq.nlargest(2, list2, key=lambda x: x['shares']))
结果为:
[99, 92, 88, 87, 78]
[12, 25, 34]
[{'name': 'AAPL', 'shares': 50, 'price': 543.22}, {'name': 'ACME', 'shares': 75, 'price': 115.65}]
[{'name': 'FB', 'shares': 200, 'price': 21.09}, {'name': 'IBM', 'shares': 100, 'price': 91.1}]

五、查找列表中元素出现频率较多的前三个元素

import random
from collections import Counter

list1 = [random.randint(1,10) for i in range(20)]

counter = Counter(list1)
print(list1)

# 查找出现频率最多的前3个元素
print(counter.most_common(3))
结果为:
[10, 8, 7, 2, 10, 7, 6, 9, 1, 10, 7, 3, 3, 10, 8, 10, 4, 6, 8, 10]
[(10, 6), (8, 3), (7, 3)]

10出现6次,8和7各出现3次。

六、元类

  • 元数据 - 描述数据的数据
  • 元类 - 描述类的类

元类是不能直接创建实例的,否则会报错,错误信息为:

Can't instantiate abstract class A with abstract methods salary
# 导入创建元类的包
from abc import ABCMeta, abstractmethod


# 元数据 - 描述数据的数据
# 元类 - 描述类的类

class Employee(metaclass=ABCMeta):
    __slots__ = ('name',)

    def __init__(self, name):
        self.name = name

    @property
    @abstractmethod
    def salary(self):
        pass


class Manager(Employee):
    __slots__ = ('name',)

    @property
    def salary(self):
        return 15000


class Programmer(Employee):
    __slots__ = ('name', '_working_hour')

    def __init__(self, name):
        super(Programmer, self).__init__(name)
        self._working_hour = 0

    @property
    def working_hour(self):
        return self._working_hour

    @working_hour.setter
    def working_hour(self, working_hour):
        self._working_hour = working_hour \
            if working_hour > 0 else 0

    @property
    def salary(self):
        return 200 * self.working_hour


class Salesman(Employee):
    __slots__ = ('name', 'sales')

    def __init__(self, name):
        super(Salesman, self).__init__(name)
        self.sales = 0

    @property
    def salary(self):
        return 1800 + self.sales * 0.05


def main():
    emps = [
        Manager('刘备'), Programmer('诸葛亮'),
        Programmer('关羽'), Salesman('张飞'),
        Salesman('马超'), Programmer('黄忠')
    ]
    for emp in emps:
        # 有了__slots__限制,所以不能添加不存在的属性
        # emp.gender = 'Male'
        if isinstance(emp, Programmer):
            hour = int(input(f'请输入{emp.name}本月工作时间: '))
            emp.working_hour = hour
        elif isinstance(emp, Salesman):
            sales = float(input(f'请输入{emp.name}本月销售额: '))
            emp.sales = sales
        print('%s月薪为: %.2f元' % (emp.name, emp.salary))


if __name__ == '__main__':
    main()
  • @property

    把方法属性化,在调用方法时可以不用括号,可以直接赋值。

  • @abstractmethod

    把方法设置成抽象方法,具体功能由子类实现。

  • _working_hour

    受保护的属性,不能直接访问,要通过setter装饰器来访问

    
    @property
      def working_hour(self):
          return self._working_hour
    
      @working_hour.setter
      def working_hour(self, working_hour):
          self._working_hour = working_hour \
              if working_hour > 0 else 0
  • __slots__

    限制属性数量,可以起到压缩内存的作用。

七、多重继承

class A:

    def foo(self):
        print('foo() in A')


class B(A):

    def foo(self):
        print('foo() in B')


class C(A):

    def foo(self):
        print('foo() in C')


class D(C, B):
    pass


def main():
    print(D.__mro__)
    obj = D()
    obj.foo()
    # 判断实例obj是否属于C类
    print(isinstance(obj,C))


if __name__ == '__main__':
    main()
结果为:
(<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
foo() in B
True
  • __mro__

    查看类中的属性和方法继承顺序。

    python2和python3使用的继承顺序算法不一样.python2用的是类似深度算法,第一个父类找不到属性或方法,就会去第一个父类的分类中查找,直到找到为止,找不到就会报错。python3用的是类似广度算法,第一个父类找不到,就会去第二个父类中查找。

八、生成器和迭代器

"""
生成器和迭代器
"""

# 用循环的方式实现斐波那契数列求解
def fib(n):
    a, b = 0, 1
    for _ in range(n):
        a, b = b, a + b
    return a

# 用生成器的方式实现斐波那契数列求解
def fib2(n):
    a, b = 0, 1
    for _ in range(n):
        a, b = b, a + b
        yield a

# 重写__iter__和__next__方法实现生成器
class Fib3:

    def __init__(self, n):
        self.n = n
        self.a, self.b = 0, 1
        self.idx = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.idx < self.n:
            self.a, self.b = self.b, self.a + self.b
            self.idx += 1
            return self.a
        raise StopIteration()


def main():
    print(tuple(Fib3(20)))
    fib3 = Fib3(20)
    for val in fib3:
        print(val)
    print(fib)
    print(fib(20))
    gen = fib2(20)
    print(gen)
    for val in gen:
        print(val)

    # 生成式
    gen2 = (x ** 3 for x in range(1, 11))
    print(gen2)
    for val in gen2:
        print(val)


if __name__ == '__main__':
    main()

省空间:生成器

省时间:生成式

一般优化是节省时间:使用缓存。

九、混入

class SetOnceMappingMixin:
    __slots__ = ()

    def __setitem__(self, key, value):
        if key in self:
            raise KeyError(str(key) + ' already set')
        return super().__setitem__(key, value)


class SetOnceDict(SetOnceMappingMixin, dict):
    pass


def main():
    dict1 = SetOnceDict()
    try:
        # 已经存在的key中的值保持不变
        dict1['username'] = 'jackfrued'
        dict1['username'] = 'hellokitty'
        dict1['username'] = 'wangdachui'
    except KeyError:
        pass
    print(dict1)


if __name__ == '__main__':
    main()
结果为:
{'username': 'jackfrued'}

python的mixin可以实现程序在运行的过程中,动态修改一个类的继承关系。

十、git

查看分支git branch
创建分支git branch develop   
切换分支git checkout develop
创建并切换分支git checkout -b develop
创建并切换分支git checkout - b issue123
切换分支git checkout develop
删除分支git branch -d issue123
所有文件放到暂存区git add .
查看暂存区状态git status
提交git commit -m '提交信息'
查看日志git log
文件还没放到暂存区时的文件回退git checkout -- 文件
提交文件后想回到其它版本git reset --hard 文件哈希id 或者版本号
git checkout master
合并git merge --no-ff develop
强行删除还没合并的分支git branch D
推送到服务器git push
拉取git pull

猜你喜欢

转载自blog.csdn.net/lm_is_dc/article/details/81869027