【python代码小技巧】职场大佬写的代码,堪称“满分作文”

2023-12-18 19:01:33

目录

🌱🌱前言

🐬🐬正文

🌲🌲python技巧1-整齐规范的命名

📌使用范围

🚗python代码举例

🚩输出

🌲🌲python技巧2-装饰器@的使用

📌使用范围?

🚗python代码举例

🚩输出

🌲🌲python技巧3-封装类

📌使用范围

🚗python代码举例

🚩输出

🌲🌲python技巧4-封装钩子

📌使用范围

🚗python代码说明

🚗python代码举例1

🚩输出1

🚗python代码举例2

a.py文件

b.py文件

🚩输出2

💯💯结语


🌱🌱前言

????????代码世界有很多令人大呼小叫的技巧🎅🎅!有的代码像🎉魔术师🎉一样巧妙地隐藏了自己,有的像🌟魔法师🌟一样让你眼花缭乱,还有的像💪???????瑜伽大师?💪???????一样灵活自如。它们让我们惊叹不已,让我们觉得自己仿佛置身于编码的魔幻世界。今天就来分享我见过的令人🎃???????膛目结舌🎃??????????????的代码技巧吧!

> 提醒:如若大佬亲临本文,请在评论区留下足迹,让我这个小白膜拜一下。

?

????????其实,说到代码技巧,不一定是什么惊艳的花式操作,整齐规范的命名,恰到好处的注释,合理的封装类,甚至封装功能文件,封装钩子等等都是让我这代码小白直呼NB的 代码技巧。本篇就来讲解下我在职场中遇到的python代码技巧

????????前两天看到#IT圈茶余饭后的“鄙视链”#活动里的一个博主讲的编程语言也有鄙视链:

  • C 语言工程师鄙视 C++ 工程师。
  • C++ 工程师鄙视 Java 和 C# 工程师。
  • Java 工程师和 C# 工程师则互相鄙视。
  • 而 C# 工程师又鄙视 Visual Basic 工程师和会把 C# 念成「C 井」的工程师,
  • 会把 C# 念成「C 井」的工程师则鄙视认为 HTML 是一种程序语言的设计师。
  • 用 Python 3 的工程师鄙视还在用 Python 2 的工程师。

......

????????看完这篇文字,再看看自己code文件夹下的一堆.py文件,我的沉默震耳欲聋,哼哼,但是有什么关系,试问目前最火AI领域哪一个不是用python写的?

🐬🐬正文

🌲🌲python技巧1-整齐规范的命名

????????不论是变量命名、还是函数命名、抑或是文件命名都需要能一下子从命名就能看出这个变量或者函数的大致含义。甚至有时规范的命名能帮你有效避免一些bug的出现。

📌使用范围

????????如下代码,本来看起来是很正常不过的代码,但是就是因为有一个变量叫mask,另一个算法包也叫mask,这种情况就很不巧,得不到想要的结果是必然的,假如你有一大串代码,你需要从几百行代码里面一行行定位才能找到问题。与其如此,为何不在定义变量的时候就避开这个矛盾呢。

🚗python代码举例

from skimage import io
from pycocotools import mask

def get_area_bbox(label):
    encoded_label = mask.encode(label)
    area = mask.area(encoded_label)
    bounding_box = mask.toBbox(encoded_label)
    return area, bounding_box

img = io.imread('/data/img/001.png')
mask = io.imread('/data/label/001.png')

area,bbox = get_area_bbox(mask)#mask变量名称与pycocotools.mask的mask包名称冲突
print(area,bbox)

修改后代码:

from skimage import io
from pycocotools import mask

def get_area_bbox(label):
    encoded_label = mask.encode(label)
    area = mask.area(encoded_label)
    bounding_box = mask.toBbox(encoded_label)
    return area, bounding_box

img = io.imread('/data/img/001.png')
label = io.imread('/data/label/001.png')

area,bbox = get_area_bbox(label)#label变量名称与pycocotools.mask的mask包名不冲突
print(area,bbox)

🚩输出

7316  [15, 34, 77, 152]

?


🌲🌲python技巧2-装饰器@的使用

????????python中的@表示修饰符,可以在模块或者类的定义层内对函数进行修饰。用做函数的修饰符,可以在模块或者类的定义层内对函数进行修饰;通常出现在函数定义的前一行,不允许和函数定义在同一行。

📌使用范围?

? ? ? ?装饰器可以使用在任何一个函数实例之前,?一个修饰符就是一个函数,它将被修饰的函数作为参数,并返回修饰后的同名函数或其他可调用的东西(如果返回不是一个可调用的对象那么会报错)。

🚗python代码举例

#Example 1
def test(func):
    print("a")
    return func()
    
@test     #从这里可以看出@test等价于 test(xxx())
def xxx():
    print('Hello world!')

🚩输出

????????运行结果为:

a
Hello world!

????????通常可以用在一堆相同功能的前面加上装饰器,如下方法使用(每个类中的具体操作省略了没写):

from mmseg.registry import TRANSFORMS

try:
    import albumentations
    from albumentations import Compose
    ALBU_INSTALLED = True
except ImportError:
    albumentations = None
    Compose = None
    ALBU_INSTALLED = False


@TRANSFORMS.register_module()
class ResizeToMultiple(BaseTransform):
        return repr_str


@TRANSFORMS.register_module()
class Rerange(BaseTransform):
        return repr_str


@TRANSFORMS.register_module()
class CLAHE(BaseTransform):
        return repr_str


@TRANSFORMS.register_module()
class RandomCrop(BaseTransform):
        return self.__class__.__name__ + f'(crop_size={self.crop_size})'


@TRANSFORMS.register_module()
class RandomRotate(BaseTransform):
        return repr_str


@TRANSFORMS.register_module()
class RGB2Gray(BaseTransform):
        return repr_str


@TRANSFORMS.register_module()
class AdjustGamma(BaseTransform):
        return self.__class__.__name__ + f'(gamma={self.gamma})'


@TRANSFORMS.register_module()
class SegRescale(BaseTransform):
        return self.__class__.__name__ + f'(scale_factor={self.scale_factor})'


@TRANSFORMS.register_module()
class PhotoMetricDistortion(BaseTransform):
        return repr_str


@TRANSFORMS.register_module()
class RandomCutOut(BaseTransform):
        return repr_str


@TRANSFORMS.register_module()
class RandomRotFlip(BaseTransform):
        return repr_str


@TRANSFORMS.register_module()
class RandomFlip(MMCV_RandomFlip):
                results['swap_seg_labels'] = self.swap_seg_labels


@TRANSFORMS.register_module()
class Resize(MMCV_Resize):
                results[seg_key] = gt_seg


@TRANSFORMS.register_module()
class RandomMosaic(BaseTransform):
        return repr_str


@TRANSFORMS.register_module()
class GenerateEdge(BaseTransform):
        return repr_str


@TRANSFORMS.register_module()
class ResizeShortestEdge(BaseTransform):
        return self.resize(results)


@TRANSFORMS.register_module()
class BioMedical3DRandomCrop(BaseTransform):
        return self.__class__.__name__ + f'(crop_shape={self.crop_shape})'


@TRANSFORMS.register_module()
class BioMedicalGaussianNoise(BaseTransform):
        return repr_str


@TRANSFORMS.register_module()
class BioMedicalGaussianBlur(BaseTransform):
        return repr_str


@TRANSFORMS.register_module()
class BioMedicalRandomGamma(BaseTransform):
        return repr_str


@TRANSFORMS.register_module()
class BioMedical3DPad(BaseTransform):
        return repr_str


@TRANSFORMS.register_module()
class BioMedical3DRandomFlip(BaseTransform):
        return repr_str


@TRANSFORMS.register_module()
class Albu(BaseTransform):
        return repr_str


@TRANSFORMS.register_module()
class ConcatCDInput(BaseTransform):
        return repr_str


@TRANSFORMS.register_module()
class RandomDepthMix(BaseTransform):
        return results

🌲🌲python技巧3-封装类

????????类是python里的一个重要定义,在类的内部,使用 def 关键字来定义方法,与一般函数定义不同,类方法必须第一个参数为 self, self 代表的是类的实例(即你还未创建类的实例),其他参数和普通函数是完全一样。? ? ? ?

📌使用范围

????????一般由多个函数组成,并且函数的参数之间有联系建议使用类封装,可以更清晰明了看到类函数之间关系。

🚗python代码举例

class Circle(object):
   pi = 3.14  # 类属性

   def __init__(self, r):
       self.r = r  # 实例属性

   def get_area(self):
       """ 圆的面积 """
       # return self.r**2 * Circle.pi # 通过实例修改pi的值对面积无影响,这个pi为类属性的值
       return self.r**2 * self.pi  # 通过实例修改pi的值对面积我们圆的面积就会改变

circle1 = Circle(1)
print("area:",circle1.get_area())  # 调用方法 self不需要传入参数,不要忘记方法后的括号  输出 3.14

🚩输出

area: 3.14

?????????项目中最常用的地方就是在数据输入的地方:

from mmcv.transforms import LoadAnnotations as MMCV_LoadAnnotations

class LoadAnnotations(MMCV_LoadAnnotations):
    """Load annotations for semantic segmentation provided by dataset.
    """

    def __init__(
        self,
        reduce_zero_label=None,
        backend_args=None,
        imdecode_backend='pillow',
    ) -> None:
        super().__init__(
            with_bbox=False,
            with_label=False,
            with_seg=True,
            with_keypoints=False,
            imdecode_backend=imdecode_backend,
            backend_args=backend_args)
        self.reduce_zero_label = reduce_zero_label
        if self.reduce_zero_label is not None:
            warnings.warn('`reduce_zero_label` will be deprecated, '
                          'if you would like to ignore the zero label, please '
                          'set `reduce_zero_label=True` when dataset '
                          'initialized')
        self.imdecode_backend = imdecode_backend

    def _load_seg_map(self, results: dict) -> None:
        """Private function to load semantic segmentation annotations.

        Args:
            results (dict): Result dict from :obj:``mmcv.BaseDataset``.

        Returns:
            dict: The dict contains loaded semantic segmentation annotations.
        """

        img_bytes = fileio.get(
            results['seg_map_path'], backend_args=self.backend_args)
        gt_semantic_seg = mmcv.imfrombytes(
            img_bytes, flag='unchanged',
            backend=self.imdecode_backend).squeeze().astype(np.uint8)

        # reduce zero_label
        if self.reduce_zero_label is None:
            self.reduce_zero_label = results['reduce_zero_label']
        assert self.reduce_zero_label == results['reduce_zero_label'], \
            'Initialize dataset with `reduce_zero_label` as ' \
            f'{results["reduce_zero_label"]} but when load annotation ' \
            f'the `reduce_zero_label` is {self.reduce_zero_label}'
        if self.reduce_zero_label:
            # avoid using underflow conversion
            gt_semantic_seg[gt_semantic_seg == 0] = 255
            gt_semantic_seg = gt_semantic_seg - 1
            gt_semantic_seg[gt_semantic_seg == 254] = 255
        # modify if custom classes
        if results.get('label_map', None) is not None:
            # Add deep copy to solve bug of repeatedly
            # replace `gt_semantic_seg`, which is reported in
            # https://github.com/open-mmlab/mmsegmentation/pull/1445/
            gt_semantic_seg_copy = gt_semantic_seg.copy()
            for old_id, new_id in results['label_map'].items():
                gt_semantic_seg[gt_semantic_seg_copy == old_id] = new_id
        results['gt_seg_map'] = gt_semantic_seg
        results['seg_fields'].append('gt_seg_map')

    def __repr__(self) -> str:
        repr_str = self.__class__.__name__
        repr_str += f'(reduce_zero_label={self.reduce_zero_label}, '
        repr_str += f"imdecode_backend='{self.imdecode_backend}', "
        repr_str += f'backend_args={self.backend_args})'
        return repr_str


🌲🌲python技巧4-封装钩子

????????大工程里经常会听到钩子函数(hook function)这个概念,钩子hook,顾名思义,可以理解是一个挂钩,作用是有需要的时候挂一个东西上去。具体的解释是:钩子函数是把我们自己实现的hook函数在某一时刻挂接到目标挂载点上。

📌使用范围

????????什么情况下需要实现hook,就是一个功能(类/方法)自身无法满足所有需求,那么可以通过hook 就提供扩展自身能力的可能。举个例子一下就明白了。

🚗python代码说明

????????Programmer类实现三个功能:eat、code、sleep,但程序员也是普通人,不能每天都只吃饭、编码、睡觉,于是通过register_hook() 提供了做别的事情的能力。

🚗python代码举例1

import time
 
 
class Programmer(object):
    """程序员"""
 
    def __init__(self, name, hook=None):
        self.name = name
        self.hooks_func = hook
        self.now_date = time.strftime("%Y-%m-%d")
 
    def get_to_eat(self):
        print(f"{self.name} - {self.now_date}: eat.")
 
    def go_to_code(self):
        print(f"{self.name} - {self.now_date}: code.")
 
    def go_to_sleep(self):
        print(f"{self.name} - {self.now_date}: sleep.")
 
    def everyday(self):
        # 程序员日常三件事
        self.get_to_eat()
        self.go_to_code()
        self.go_to_sleep()
        # check the register_hook(hooked or unhooked)
        # hooked
        if self.hooks_func is not None:
            self.hooks_func(self.name)
 
 
def play_game(name):
    now_date = time.strftime("%Y-%m-%d")
    print(f"{name} - {now_date}: play game.")
 
 
def shopping(name):
    now_date = time.strftime("%Y-%m-%d")
    print(f"{name} - {now_date}: shopping.")
 
 
if __name__ == "__main__":
    # hook 作为参数传入
    tom = Programmer("Tom", hook=play_game)
    jerry = Programmer("Jerry", hook=shopping)
    spike = Programmer("Spike")
    # 今日事情
    tom.everyday()
    jerry.everyday()
    spike.everyday()

🚩输出1

Tom - 2023-12-18: eat.
Tom - 2023-12-18: code.
Tom - 2023-12-18: sleep.
Tom - 2023-12-18: play game.
Jerry - 2023-12-18: eat.
Jerry - 2023-12-18: code.
Jerry - 2023-12-18: sleep.
Jerry - 2023-12-18: shopping.
Spike - 2023-12-18: eat.
Spike - 2023-12-18: code.
Spike - 2023-12-18: sleep.

🚗python代码举例2

?????????hook还有一种用法:定义一个函数,然后作为参数塞到另一个类/方法里。

????????比如以下用法:

a.py文件

def get_path():
    """定义钩子函数"""
    path = '/data/images/'
    return os.path.listdir(path)
 
b.py文件

def test(get_path):
    # 调用 get_path 钩子函数
    num = len(get_path)
    print('num of img:',num)
 

????????两个文件看似没有直接的调用关系,在执行?b.py?文件时,可以间接的调用?a.py?文件中的get_path()钩子函数。

🚩输出2

num of img: 100

参考链接:python强大的hook函数


💯💯结语

????????本文讲解了常见的python代码小技巧——?整齐规范的命名,恰到好处的注释,合理的封装类,封装钩子等等,如果你由更好的python编码技巧,欢迎评论区留下足迹哦。

文章来源:https://blog.csdn.net/qq_38308388/article/details/135057107
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。