ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Python - Clean code - better/good/bad examples
    Python 2021. 2. 10. 11:10

    github.com/zedr/clean-code-python

     

    zedr/clean-code-python

    :bathtub: Clean Code concepts adapted for Python. Contribute to zedr/clean-code-python development by creating an account on GitHub.

    github.com


    Use meaningful and pronounceable variable names

    import datetime
    
    ## bad
    ymdstr = datetime.date.today().strftime("%y-%m-%d")
    
    ## good
    current_date: str = datetime.date.today().strftime("%y-%m-%d")

    Use the same vocabulary for the same type of variable

    ## bad
    def get_user_info(): pass
    def get_client_data(): pass
    def get_customer_record(): pass
    
    ## good
    def get_user_info(): pass
    def get_user_data(): pass
    def get_user_record(): pass
    
    ## better
    from typing import Union, Dict, Text
    
    class Record:
        pass
    
    class User:
        info : str
    
        @property
        def data(self) -> Dict[Text, Text]:
            return {}
    
        def get_record(self) -> Union[Record, None]:
            return Record()

     

    Use searchable names

    import time
    
    ## bad 
    time.sleep(86400)
    
    ## good
    SECONDS_IN_A_DAY = 60 * 60 * 24
    time.sleep(SECONDS_IN_A_DAY)

    Use explanatory variables

    ## bad
    import re
    
    address = "One Infinite Loop, Cupertino 95014"
    city_zip_code_regex = r"^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$"
    
    matches = re.match(city_zip_code_regex, address)
    if matches:
        print(f"{matches[1]}: {matches[2]}")
        
    ## good
    address = "One Infinite Loop, Cupertino 95014"
    city_zip_code_regex = r"^[^,\\]+[,\\\s]+(?P<city>.+?)\s*(?P<zip_code>\d{5})?$"
    
    matches = re.match(city_zip_code_regex, address)
    if matches:
        print(f"{matches['city']}, {matches['zip_code']}")

    Avoid Mental Mapping

    seq = ("Austin", "New York", "San Francisco")
    
    ## bad
    for item in seq:
        print(item)
        
    ## good
    for location in locations:
        print(location)

    Don"t add unneeded context

    ## bad
    
    class Car:
        car_make: str
        car_model: str
        car_color: str
    
    ## good
    class Car:
        make: str
        model: str
        color: str

    Use default arguments instead of short circuiting or conditionals

    from typing import Text
    import hashlib
    
    ## bad
    def create_micro_brewery(name):
        name = "Hipster Brew Co." if name is None else name
        slug = hashlib.sha1(name.encode()).hexdigest()
        # etc.
    
    ## good
    def create_micro_brewery(name: Text = "Hipster Brew Co."):
        slug = hashlib.sha1(name.encode()).hexdigest()
        # etc.

    Functions should do one thing

    from typing import List
    
    class Client:
        active: bool
    
    
    def email(client: Client) -> None:
        pass
    
    
    def email_clients(clients: List[Client]) -> None:
        """Filter active clients and send them an email.
        """
        for client in clients:
            if client.active:
                email(client)
                
    ## good
    def get_active_clients(clients: List[Client]) -> List[Client]:
        """Filter active clients.
        """
        return [client for client in clients if client.active]
    
    ## good
    def email_clients(clients: List[Client]) -> None:
        """Send an email to a given list of clients.
        """
        for client in get_active_clients(clients):
            email(client)
            
     ## better       
     def active_clients(clients: Iterator[Client]) -> Generator[Client, None, None]:
        """Only active clients"""
        return (client for client in clients if client.active)
    
    ## better
    def email_client(clients: Iterator[Client]) -> None:
        """Send an email to a given list of clients.
        """
        for client in active_clients(clients):
            email(client)

    Function names should say what they do

    class Email:
    	## bad
        def handle(self) -> None:
            pass
    	## good
    	def send(self) -> None:
            """Send this message"""
    
    message = Email()
    message.send()

    Don't use flags as function parameters

    • flag를 통해 분기로 다른 일을 한다면 함수가 두 개 이상의 일은 한다는 것이므로 분리시켜야함
    from typing import Text
    from tempfile import gettempdir
    from pathlib import Path
    
    ## bad
    def create_file(name: Text, temp: bool) -> None:
        if temp:
            (Path(gettempdir()) / name).touch()
        else:
            Path(name).touch()
            
     ## good        
    def create_file(name: Text) -> None:
        Path(name).touch()
    
    ## good
    def create_temp_file(name: Text) -> None:
        (Path(gettempdir()) / name).touch()

    Comments

    • 비즈니스 로직이 복잡한 경우에만 주석을 달자. 코드 자체를 설명할 필요는 없음
    • 주석으로 된 코드는 남기지 않기 - git 으로 관리
    • 코드 위치 남기지 않기 

    'Python' 카테고리의 다른 글

    OOP - 상속,변수, 초기화- Crawling/Custom Exceptions  (0) 2022.01.13
    [TEST] 2.테스트 코드 작성하기  (0) 2021.10.24
    객체 지향 프로그래밍 - 크롤러 개발  (0) 2021.10.12
    Python 3.8 new features  (0) 2021.02.10
    Process / thread  (0) 2020.11.04
Designed by Tistory.