[
  {
    "path": ".gitattributes",
    "content": "*.md linguist-documentation=false\n*.md linguist-language=Python\n"
  },
  {
    "path": ".github/workflows/python-app.yml",
    "content": "# This workflow will install Python dependencies, run tests and lint with a single version of Python\n# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions\n\nname: Python application\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v2\n    - name: Set up Python 3.10\n      uses: actions/setup-python@v2\n      with:\n        python-version: \"3.10\"\n    - name: Install dependencies\n      run: |\n        python -m pip install --upgrade pip\n        pip install flake8 pytest\n        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi\n    - name: Lint with flake8\n      run: |\n        # stop the build if there are Python syntax errors or undefined names\n        flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics\n        # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide\n        flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics\n    - name: Test with pytest\n      run: |\n        pytest\n"
  },
  {
    "path": ".gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\npip-wheel-metadata/\nshare/python-wheels/\n*.egg-info/\n.installed.cfg\n*.egg\nMANIFEST\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.nox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n*.py,cover\n.hypothesis/\n.pytest_cache/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\ndb.sqlite3\ndb.sqlite3-journal\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# IPython\nprofile_default/\nipython_config.py\n\n# pyenv\n.python-version\n\n# pipenv\n#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.\n#   However, in case of collaboration, if having platform-specific dependencies or dependencies\n#   having no cross-platform support, pipenv may install dependencies that don't work, or not\n#   install all needed dependencies.\n#Pipfile.lock\n\n# celery beat schedule file\ncelerybeat-schedule\n\n# SageMath parsed files\n*.sage.py\n\n# Environments\n.env\n.venv\nenv/\nvenv/\nENV/\nenv.bak/\nvenv.bak/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n.dmypy.json\ndmypy.json\n\n# Pyre type checker\n.pyre/\n\n# VSCODE\n.vscode\n.idea\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: python\npython:\n  - \"3.8.3\"\n# command to install dependencies\ninstall:\n  - make deps\n# command to run tests\nscript:\n  - make tests\n"
  },
  {
    "path": "CONTRIBUTORS",
    "content": "Rigel Di Scala <zedr@zedr.com>\nZachary Anglin <zach@anglin.com>\nAirbusDriver <https://github.com/AirbusDriver>\nMicheal <https://github.com/mpkocher>\nErik OShaughnessy <https://github.com/JnyJny>\nMukhammad Karimov <https://github.com/heykarimoff>\nsitnarf <https://github.com/sitnarf>\nMiguel Gonzalez <https://github.com/migonzalvar>\nAnvar <https://github.com/arpanetus>\nMartin Pavlásek <https://github.com/mpavlase>\nShahrukh Khan <https://github.com/shahrukhx01>\nAaron Law <https://github.com/AaronLaw>\nFredson Chaves <https://github.com/fredsonchaves07>\nMartinThoma <https://github.com/MartinThoma>\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 Ryan McDermott\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE\n"
  },
  {
    "path": "Makefile",
    "content": ".PHONY: deps clean tests\n\nENV=.env\nPYTHON=python3\nPYTHON_VERSION=$(shell ${PYTHON} -V | cut -d \" \" -f 2 | cut -c1-3)\nSITE_PACKAGES=${ENV}/lib/python${PYTHON_VERSION}/site-packages\nIN_ENV=source ${ENV}/bin/activate;\n\ndefault: tests\n\n${ENV}:\n\t@echo \"Creating Python environment...\" >&2\n\t@${PYTHON} -m venv ${ENV}\n\t@echo \"Updating pip...\" >&2\n\t@${IN_ENV} pip install -U pip\n\n${SITE_PACKAGES}/pytest.py:\n\t@${IN_ENV} pip install -r requirements.txt\n\ndeps: ${SITE_PACKAGES}/pytest.py\n\ntests: ${ENV} ${SITE_PACKAGES}/pytest.py\n\t@${IN_ENV} pytest\n\nclean:\n\t@rm -rf ${ENV} .env .pytest_cache\n"
  },
  {
    "path": "README.md",
    "content": "# کد تمیز در پایتون\n\n## فهرست مطالب\n  1. [مقدمه](#مقدمه)\n  2. [متغیر ها](#متغیر-ها)\n  3. [توابع](#توابع)\n  5. [کلاس ها](#کلاس-ها)\n     * [S: Single Responsibility Principle (SRP)](#single-responsibility-principle-srp)\n     * [O: Open/Closed Principle (OCP)](#openclosed-principle-ocp)\n     * [L: Liskov Substitution Principle (LSP)](#liskov-substitution-principle-lsp)\n     * [I: Interface Segregation Principle (ISP)](#interface-segregation-principle-isp)\n     * [D: Dependency Inversion Principle (DIP)](#dependency-inversion-principle-dip)\n  6. [Don't repeat yourself (DRY)](#dont-repeat-yourself-dry)\n\n## مقدمه\n\nاصول مهندسی نرم افزار، از کتاب [*کد تمیز*](https://www.digikala.com/product/dkp-4964829/%DA%A9%D8%AA%D8%A7%D8%A8-clean-code-a-handbook-of-agile-software-craftsmanship-%D8%A7%D8%AB%D8%B1-robert-c-martin-%D8%A7%D9%86%D8%AA%D8%B4%D8%A7%D8%B1%D8%A7%D8%AA-pearson/) نوشته ی Robert C. Martin، برای پایتون. این یک راهنمای تولید نیست، این یک راهنما برای تولید نرم افزار های خوانا، قابل استفاده مجدد و قابل از نو بازسازی است.\nنیازی بر سرسختگیری بر هر اصل گفته شده در اینجا نیست، و فقط تعداد کمی از آنها به صورت عمومی مورد تایید هستند. این ها چیزی جز اصول نیستند، اما اصول کدنویسی شده ای توسط سالها تجربه از نویسنده های *کد تمیز* هستند.\n## **متغیر ها**\n### از اسم های متغیر با معنا و قابل تلفظ استفاده کنید\n\n**بد:**\n\n```python\nimport datetime\n\n\nymdstr = datetime.date.today().strftime(\"%y-%m-%d\")\n```\n\nبه علاوه، نیازی به استفاده کردن تایپ `str` برای اسم نیست.\n\n**خوب**:\n\n```python\nimport datetime\n\n\ncurrent_date: str = datetime.date.today().strftime(\"%y-%m-%d\")\n```\n**[⬆ برگشت به بالا](#فهرست-مطالب)**\n\n### از واژگان یکسان برای همان نوع متغیر استفاده کنید\n**بد:**\nما در اینجا از چند اسم برای یک موجود استفاده میکنیم:\n\n```python\ndef get_user_info(): pass\ndef get_client_data(): pass\ndef get_customer_record(): pass\n```\n\n**خوب**:\nاگر موجودیت یکسان است، باید در ارجاع به آن در توابع خود ثابت قدم باشید:\n\n```python\ndef get_user_info(): pass\ndef get_user_data(): pass\ndef get_user_record(): pass\n```\n\n**حتی بهتر**\n\nپایتون (همچنین) یک زبان برنامه نویسی شی گرا است. اگر منطقی است، توابع را همراه با پیاده‌سازی مشخص موجودیت در کد خود، به‌عنوان ویژگی‌های نمونه، متدهای ویژگی یا متدها بسته‌بندی کنید\n\n```python\nfrom typing import Union, Dict\n\n\nclass Record:\n    pass\n\n\nclass User:\n    info : str\n\n    @property\n    def data(self) -> Dict[str, str]:\n        return {}\n\n    def get_record(self) -> Union[Record, None]:\n        return Record()\n```\n\n**[⬆ برگشت به بالا](#فهرست-مطالب)**\n\n### از اسامی قابل جست و جو استفاده کنید\nما بیشتر کد میخوانیم تا بنویسیم. این خیلی مهم است که کدی که مینویسیم خوانا و قابل جستجو باشد. با نام گذاری *نکردن* متغیر هایی که برای برنامه قابل فهم باشد، به خواننده هایمان آسیب میرسانیم. اسامی متغیرهایتان را قابل جست و جو کنید.\n\n**بد:**\n\n```python\nimport time\n\n\n# What is the number 86400 for again?\ntime.sleep(86400)\n```\n\n**خوب**:\n\n```python\nimport time\n\n\n# Declare them in the global namespace for the module.\nSECONDS_IN_A_DAY = 60 * 60 * 24\ntime.sleep(SECONDS_IN_A_DAY)\n```\n**[⬆ برگشت به بالا](#فهرست-مطالب)**\n\n### از متغیر های توضیحی استفاده کنید\n**بد:**\n\n```python\nimport re\n\n\naddress = \"One Infinite Loop, Cupertino 95014\"\ncity_zip_code_regex = r\"^[^,\\\\]+[,\\\\\\s]+(.+?)\\s*(\\d{5})?$\"\n\nmatches = re.match(city_zip_code_regex, address)\nif matches:\n    print(f\"{matches[1]}: {matches[2]}\")\n```\n\n**بد نیست**:\n\nبهتر است، اما هنوز به شدت به رجکس وابسته ایم.\n```python\nimport re\n\n\naddress = \"One Infinite Loop, Cupertino 95014\"\ncity_zip_code_regex = r\"^[^,\\\\]+[,\\\\\\s]+(.+?)\\s*(\\d{5})?$\"\nmatches = re.match(city_zip_code_regex, address)\n\nif matches:\n    city, zip_code = matches.groups()\n    print(f\"{city}: {zip_code}\")\n```\n\n**خوب**:\n\n\nوابستگی به رجکس را با نام گذاری الگوهای فرعی کمتر کنید.\n\n```python\nimport re\n\n\naddress = \"One Infinite Loop, Cupertino 95014\"\ncity_zip_code_regex = r\"^[^,\\\\]+[,\\\\\\s]+(?P<city>.+?)\\s*(?P<zip_code>\\d{5})?$\"\n\nmatches = re.match(city_zip_code_regex, address)\nif matches:\n    print(f\"{matches['city']}, {matches['zip_code']}\")\n```\n**[⬆ برگشت به بالا](#فهرست-مطالب)**\n\n### از نقشه برداری ذهنی خودداری کنید\n\nخواننده ی کدتان را مجبور نکنید که اسامی متغیرهای شمارا ترجمه کنند.\nصریح بهتر از ضمنی است.\n\n**بد:**\n\n```python\nseq = (\"Austin\", \"New York\", \"San Francisco\")\n\nfor item in seq:\n    #do_stuff()\n    #do_some_other_stuff()\n\n    # Wait, what's `item` again?\n    print(item)\n```\n\n**خوب**:\n\n```python\nlocations = (\"Austin\", \"New York\", \"San Francisco\")\n\nfor location in locations:\n    #do_stuff()\n    #do_some_other_stuff()\n    # ...\n    print(location)\n```\n**[⬆ برگشت به بالا](#فهرست-مطالب)**\n\n\n### توضیحات اضافی ننویسید\n\nاگر اسم کلاس/شیء شما چیزی را میگوید، نیازی نیست که آنرا در اسامی متغیر هایتان تکرار کنید.\n\n**بد:**\n\n```python\nclass Car:\n    car_make: str\n    car_model: str\n    car_color: str\n```\n\n**خوب**:\n\n```python\nclass Car:\n    make: str\n    model: str\n    color: str\n```\n\n**[⬆ برگشت به بالا](#فهرست-مطالب)**\n\n### از آرگومان های پیشفرض به جای شروط یک خطی استفاده کنید.\n\n**بد**\n\nچرا بنویسیم :\n\n```python\nimport hashlib\n\n\ndef create_micro_brewery(name):\n    name = \"Hipster Brew Co.\" if name is None else name\n    slug = hashlib.sha1(name.encode()).hexdigest()\n    # etc.\n```\n\n...زمانی که میتوانید از یک آرگومان پیشفرض استفاده کنید ؟ این همچنین خواننده را کاملا روشن میکند که شما برای آرگومانتان یک رشته میخواهید.\n\n**خوب**:\n\n```python\nimport hashlib\n\n\ndef create_micro_brewery(name: str = \"Hipster Brew Co.\"):\n    slug = hashlib.sha1(name.encode()).hexdigest()\n    # etc.\n```\n\n**[⬆ برگشت به بالا](#فهرست-مطالب)**\n\n### آرگومان های توابع (ترجیحاً دو یا کمتر)\n\nکم کردن مقادیر پارامتر های توابع بسیار مهم است چون تست کردن آنهارا راحت تر میکند. بیشتر از سه تا منجر به انفجاری ترکیبی میشود چون باید حالت های مختلف را با آرگومان های متفاوت تست کنید.\n\nآرگومان نداشتن حالت آیده آل است. یکی یا دوتا خوب است، و باید از سه تا اجتناب کرد. \nهرچیزی بیشتر از آن باید یک رقم شود. معمولا اگر بیشتر از دو آرگومان دارید، کد شما دارد چند کار را باهم انجام میدهد. در شرایطی که اینگونه نیست، اغلب اوقات یک شی سطح بالاتر به عنوان یک آرگومان کافی است.\n\n**بد:**\n\n```python\ndef create_menu(title, body, button_text, cancellable):\n    pass\n```\n\n**به سبک جاوا**:\n\n```python\nclass Menu:\n    def __init__(self, config: dict):\n        self.title = config[\"title\"]\n        self.body = config[\"body\"]\n        # ...\n\nmenu = Menu(\n    {\n        \"title\": \"My Menu\",\n        \"body\": \"Something about my menu\",\n        \"button_text\": \"OK\",\n        \"cancellable\": False\n    }\n)\n```\n\n**این هم خوب است**\n\n```python\nclass MenuConfig:\n    \"\"\"A configuration for the Menu.\n\n    Attributes:\n        title: The title of the Menu.\n        body: The body of the Menu.\n        button_text: The text for the button label.\n        cancellable: Can it be cancelled?\n    \"\"\"\n    title: str\n    body: str\n    button_text: str\n    cancellable: bool = False\n\n\ndef create_menu(config: MenuConfig) -> None:\n    title = config.title\n    body = config.body\n    # ...\n\n\nconfig = MenuConfig()\nconfig.title = \"My delicious menu\"\nconfig.body = \"A description of the various items on the menu\"\nconfig.button_text = \"Order now!\"\n# The instance attribute overrides the default class attribute.\nconfig.cancellable = True\n\ncreate_menu(config)\n```\n\n**تفننی**\n\n```python\nfrom typing import NamedTuple\n\n\nclass MenuConfig(NamedTuple):\n    \"\"\"A configuration for the Menu.\n\n    Attributes:\n        title: The title of the Menu.\n        body: The body of the Menu.\n        button_text: The text for the button label.\n        cancellable: Can it be cancelled?\n    \"\"\"\n    title: str\n    body: str\n    button_text: str\n    cancellable: bool = False\n\n\ndef create_menu(config: MenuConfig):\n    title, body, button_text, cancellable = config\n    # ...\n\n\ncreate_menu(\n    MenuConfig(\n        title=\"My delicious menu\",\n        body=\"A description of the various items on the menu\",\n        button_text=\"Order now!\"\n    )\n)\n```\n\n**تفننی تر**\n\n```python\nfrom dataclasses import astuple, dataclass\n\n\n@dataclass\nclass MenuConfig:\n    \"\"\"A configuration for the Menu.\n\n    Attributes:\n        title: The title of the Menu.\n        body: The body of the Menu.\n        button_text: The text for the button label.\n        cancellable: Can it be cancelled?\n    \"\"\"\n    title: str\n    body: str\n    button_text: str\n    cancellable: bool = False\n\ndef create_menu(config: MenuConfig):\n    title, body, button_text, cancellable = astuple(config)\n    # ...\n\n\ncreate_menu(\n    MenuConfig(\n        title=\"My delicious menu\",\n        body=\"A description of the various items on the menu\",\n        button_text=\"Order now!\"\n    )\n)\n```\n\n**باز هم تفننی تر، فقط پایتون 3.8+**\n\n```python\nfrom typing import TypedDict\n\n\nclass MenuConfig(TypedDict):\n    \"\"\"A configuration for the Menu.\n\n    Attributes:\n        title: The title of the Menu.\n        body: The body of the Menu.\n        button_text: The text for the button label.\n        cancellable: Can it be cancelled?\n    \"\"\"\n    title: str\n    body: str\n    button_text: str\n    cancellable: bool\n\n\ndef create_menu(config: MenuConfig):\n    title = config[\"title\"]\n    # ...\n\n\ncreate_menu(\n    # You need to supply all the parameters\n    MenuConfig(\n        title=\"My delicious menu\",\n        body=\"A description of the various items on the menu\",\n        button_text=\"Order now!\",\n        cancellable=True\n    )\n)\n```\n**[⬆ برگشت به بالا](#فهرست-مطالب)**\n\n## **توابع**\n### توابع فقط باید یک کار انجام دهند.\nاین مهم ترین قانون در طراحی نرم افزار است. وقتی توابع بیشتر از یک کار انجام میدهند، سخت تر میتوان آنهارا نوشت و تست و استدلال کرد. وقتی که یک تابع را فقط به یک رفتار ایزوله میکنید، به راحتی میتوان آنهارا از نو نوشت و کدتان بسیار تمیزتر خواهد بود. اگر فقط همین مورد را از این راهنما یاد بگیرید، از بسیاری از برنامه نویس ها جلوتر خواهید بود.\n\n**بد:**\n\n```python\nfrom typing import List\n\n\nclass Client:\n    active: bool\n\n\ndef email(client: Client) -> None:\n    pass\n\n\ndef email_clients(clients: List[Client]) -> None:\n    \"\"\"Filter active clients and send them an email.\n    \"\"\"\n    for client in clients:\n        if client.active:\n            email(client)\n```\n\n**خوب**:\n\n```python\nfrom typing import List\n\n\nclass Client:\n    active: bool\n\n\ndef email(client: Client) -> None:\n    pass\n\n\ndef get_active_clients(clients: List[Client]) -> List[Client]:\n    \"\"\"Filter active clients.\n    \"\"\"\n    return [client for client in clients if client.active]\n\n\ndef email_clients(clients: List[Client]) -> None:\n    \"\"\"Send an email to a given list of clients.\n    \"\"\"\n    for client in get_active_clients(clients):\n        email(client)\n```\n\nآیا اکنون فرصتی برای استفاده از چنریتور ها می بینید؟\n\n**حتی بهتر**\n\n```python\nfrom typing import Generator, Iterator\n\n\nclass Client:\n    active: bool\n\n\ndef email(client: Client):\n    pass\n\n\ndef active_clients(clients: Iterator[Client]) -> Generator[Client, None, None]:\n    \"\"\"Only active clients\"\"\"\n    return (client for client in clients if client.active)\n\n\ndef email_client(clients: Iterator[Client]) -> None:\n    \"\"\"Send an email to a given list of clients.\n    \"\"\"\n    for client in active_clients(clients):\n        email(client)\n```\n\n\n### اسامی توابع باید کاری که انجام میدهند را بگویند.\n\n**بد:**\n\n```python\nclass Email:\n    def handle(self) -> None:\n        pass\n\nmessage = Email()\n# What is this supposed to do again?\nmessage.handle()\n```\n\n**خوب:**\n\n```python\nclass Email:\n    def send(self) -> None:\n        \"\"\"Send this message\"\"\"\n\nmessage = Email()\nmessage.send()\n```\n\n**[⬆ برگشت به بالا](#فهرست-مطالب)**\n\n### توابع باید فقط یک مرحله از انتزاع داشته باشند.\n\nوقتی که کدتان بیشتر از یک مرحله انتزاع دارد، کدتان دارد زیاد کار انجام میدهد. تکه تکه کردن توابع باعث خوانایی کد و تست نویسی آسان تر میشود.\n\n**بد:**\n\n```python\n# type: ignore\n\ndef parse_better_js_alternative(code: str) -> None:\n    regexes = [\n        # ...\n    ]\n\n    statements = code.split('\\n')\n    tokens = []\n    for regex in regexes:\n        for statement in statements:\n            pass\n\n    ast = []\n    for token in tokens:\n        pass\n\n    for node in ast:\n        pass\n```\n\n**خوب:**\n\n```python\nfrom typing import Tuple, List, Dict\n\n\nREGEXES: Tuple = (\n   # ...\n)\n\n\ndef parse_better_js_alternative(code: str) -> None:\n    tokens: List = tokenize(code)\n    syntax_tree: List = parse(tokens)\n\n    for node in syntax_tree:\n        pass\n\n\ndef tokenize(code: str) -> List:\n    statements = code.split()\n    tokens: List[Dict] = []\n    for regex in REGEXES:\n        for statement in statements:\n            pass\n\n    return tokens\n\n\ndef parse(tokens: List) -> List:\n    syntax_tree: List[Dict] = []\n    for token in tokens:\n        pass\n\n    return syntax_tree\n```\n\n**[⬆ برگشت به بالا](#فهرست-مطالب)**\n\n### از فلگ ها برای پارامتر های تابعتان استفاده نکنید.\n\nفلگ ها به کاربر ها میگویند که این تابع بیشتر از یک کار انجام میدهد. توابع باید یک کار انجام دهند. توابعتان را تکه تکه کنید اگر کدهای متفاوتی بر حسب یک بولین هستند.\n\n**بد:**\n\n```python\nfrom tempfile import gettempdir\nfrom pathlib import Path\n\n\ndef create_file(name: str, temp: bool) -> None:\n    if temp:\n        (Path(gettempdir()) / name).touch()\n    else:\n        Path(name).touch()\n```\n\n**خوب:**\n\n```python\nfrom tempfile import gettempdir\nfrom pathlib import Path\n\n\ndef create_file(name: str) -> None:\n    Path(name).touch()\n\n\ndef create_temp_file(name: str) -> None:\n    (Path(gettempdir()) / name).touch()\n```\n\n**[⬆ برگشت به بالا](#فهرست-مطالب)**\n\n### از تاثیرات جانبی خودداری کنید\n\nیک تابع هنگامی اثر جانبی دارد که کاری بجز گرفتن یک مقدار و برگرداندن مقدار یا مقدار هایی دیگر انجام دهد. برای مثال، یک اثر جانبی میتواند نوشتن به یک فایل، تغییر دادن متغیر های گلوبال و یا انتقال تمامی اموالتان به یک غریبه باشد.\nحالا، بعضی اوقات نیاز است که برنامه شما اثرات جانبی داشته باشد - برای مثال، همانند مثال قبلی، نیاز داشته باشید که به یک فایل بنویسید. در این شرایط، شما باید متمرکز باشید و مشخص کنید که در کجا اثرات جانبی ایجاد میکنید. چندین تابع و کلاس نداشته باشید که به یک فایل مینویسند، بلکه یک و فقط یک سرویس داشته باشید که تمامی این کارها را انجام میدهد. \nنکته اصیل اجتناب از دام های رایج مثل تبادل وضعیت بین چندین شیء بدون هیچ ساختمان، استفاده از دیتاتایپ های قابل تغییر که هرچیزی بتواند به آن بنویسد یا استفاده کردن نمونه ای از یک کلاس به جای متمرکز کردن مکان هایی که اثرات جانبی خواهید داشت. \nاگر بتوانید این کار را انجام دهید، از بیشتر برنامه نویس ها خوشحال تر خواهید بود.\n\n\n**بد:**\n\n```python\n# type: ignore\n\n# This is a module-level name.\n# It's good practice to define these as immutable values, such as a string.\n# However...\nfullname = \"Ryan McDermott\"\n\ndef split_into_first_and_last_name() -> None:\n    # The use of the global keyword here is changing the meaning of the\n    # the following line. This function is now mutating the module-level\n    # state and introducing a side-effect!\n    global fullname\n    fullname = fullname.split()\n\nsplit_into_first_and_last_name()\n\n# MyPy will spot the problem, complaining about 'Incompatible types in\n# assignment: (expression has type \"List[str]\", variable has type \"str\")'\nprint(fullname)  # [\"Ryan\", \"McDermott\"]\n\n# OK. It worked the first time, but what will happen if we call the\n# function again?\n```\n\n**خوب:**\n\n```python\nfrom typing import List, AnyStr\n\n\ndef split_into_first_and_last_name(name: AnyStr) -> List[AnyStr]:\n    return name.split()\n\nfullname = \"Ryan McDermott\"\nname, surname = split_into_first_and_last_name(fullname)\n\nprint(name, surname)  # => Ryan McDermott\n```\n**همچنین خوب :**\n\n```python\nfrom dataclasses import dataclass\n\n\n@dataclass\nclass Person:\n    name: str\n\n    @property\n    def name_as_first_and_last(self) -> list:\n        return self.name.split()\n\n\n# The reason why we create instances of classes is to manage state!\nperson = Person(\"Ryan McDermott\")\nprint(person.name)  # => \"Ryan McDermott\"\nprint(person.name_as_first_and_last)  # => [\"Ryan\", \"McDermott\"]\n```\n\n**[⬆ برگشت به بالا](#فهرست-مطالب)**\n\n## **کلاس ها**\n\n### **Single Responsibility Principle (SRP)**\n\nرابرت سی. مارتین مینویسد :\n\n> یک کلاس باید فقط یک دلیل برای تغییر داشته باشد.\n\n\"  دلایل تغییر \" ذاتاً مسئولیت هایی است که توسط یک کلاس یا تابع مدیریت میشود.\n\nدر مثال های زیر، ما یک عنصر HTML را میسازیم که یک کامنت و ورژن را نشان میدهد.\n\n**بد :**\n```python\nfrom importlib import metadata\n\n\nclass VersionCommentElement:\n   \"\"\"An element that renders an HTML comment with the program's version number\n   \"\"\"\n\n   def get_version(self) -> str:\n       \"\"\"Get the package version\"\"\"\n       return metadata.version(\"pip\")\n   \n   def render(self) -> None:\n       print(f'<!-- Version: {self.get_version()} -->')\n\n\nVersionCommentElement().render()\n```\nاین کلاس دو وظیفه دارد:\n* گرفتن نسخه ی پکیج پایتون\n* رندر کردن آن به یک عنصر HTML\n\nهر تغییری در یکی از آن ها، ریسک تاثیر گذاشتن روی آن یکی را ایجاد میکند.\nما میتوانیم کلاس را از نو بنویسیم و مسئولیت ها را جدا کنیم.\n\n**خوب :**\n```python\nfrom importlib import metadata\n\n\ndef get_version(pkg_name:str) -> str:\n    \"\"\"Retrieve the version of a given package\"\"\"\n    return metadata.version(pkg_name)\n\n\nclass VersionCommentElement:\n   \"\"\"An element that renders an HTML comment with the program's version number\n   \"\"\"\n\n   def __init__(self, version: str):\n       self.version = version\n   \n   def render(self) -> None:\n       print(f'<!-- Version: {self.version} -->')\n\n\nVersionCommentElement(get_version(\"pip\")).render()\n```\nنتیجه این خواهد بود که کلاس فقط باید رندر    کردن را به عهده بگیرد. ورژن را هنگام نمونه گیری دریافت میکند و متن توسط تابعی جدا به نام `get_version()` گرفته میشود. تغییر دادن کلاس هیچ تاثیری روی آن یکی ندارد، و بالعکس، تا زمانی که قرارداد های بینشان تغییر نکند، یعنی فانکشن یک متن برگرداند و متود `__init__` کلاس یک رشته را دریافت کند.\n\nو همینطور، تابع `get_version()` قابل استفاده در همه جا است.\n\n### **Open/Closed Principle (OCP)**\n\n> “ قابلیت های جدید را با گسترش دادن ایجاد کنید، نه با تغییر دادن(آن). “ Uncle Bob.\n\nاشیاء باید برای گسترش دادن دردسترس باشند، اما بسته برای تغییرات. باید امکان تقویت عملکرد ارائه شده توسط یک شیء (برای مثال، یک کلاس) بدون تغییر دادن قرارداد های داخلی آن باشد. یک شیء میتواند این قابلیت را هنگامی ایجاد کند که طوری نوشته شده باشد که اجازه اینکار را به راحتی بدهد.\n\nدر مثال بعدی، تلاش میکنیم یک فریم ورک وب ساده پیاده سازی کنیم که درخواست های HTTP را هندل و پاسخی را برمیگرداند. کلاس `View` یک متد `.get()` دارد که زمانی صدا زده خواهد شد که سرور HTTP یک درخواست GET دریافت کند.\n\nکلاس `View` به طور قصد ساده است و پاسخ های `text/plain` برمیگرداند. ما همچنین پاسخ هایی بر پایه فایل های تمپلیت میخواهیم پس با کلاس `TemplateView` از آن ارث بری میکنیم.\n\n**بد:**\n```python\nfrom dataclasses import dataclass\n\n\n@dataclass\nclass Response:\n    \"\"\"An HTTP response\"\"\"\n\n    status: int\n    content_type: str\n    body: str\n\n\nclass View:\n    \"\"\"A simple view that returns plain text responses\"\"\"\n\n    def get(self, request) -> Response:\n        \"\"\"Handle a GET request and return a message in the response\"\"\"\n        return Response(\n            status=200,\n            content_type='text/plain',\n            body=\"Welcome to my web site\"\n        )\n\n\nclass TemplateView(View):\n    \"\"\"A view that returns HTML responses based on a template file.\"\"\"\n\n    def get(self, request) -> Response:\n        \"\"\"Handle a GET request and return an HTML document in the response\"\"\"\n        with open(\"index.html\") as fd:\n            return Response(\n                status=200,\n                content_type='text/html',\n                body=fd.read()\n            )\n\n```\n\nکلاس `TemplateView` رفتار های داخلی والدش را تغییر داده تا بتواند عملکرد های پیشرفته تر اضافه کند. با اینکار، کلاس `TemplateView` به والدش تکیه میکند که عملکرد `.get()` تغییر نکند، که حالا باید در زمان منجمد شود. برای مثال، نمی‌توانیم برخی بررسی‌های اضافی را در تمام کلاس‌های مشتق از `View` معرفی کنیم، زیرا این رفتار حداقل در یک نوع فرعی لغو شده است و ما باید آن را به‌روزرسانی کنیم.  \n\nبیایید کلاس های خود را از نو طراحی کنیم تا این مشکل حل شود و اجازه دهیم تا کلاس `View` به تمیزی گسترش (نه تغییر) داده شود.\n\n**خوب :**\n```python\nfrom dataclasses import dataclass\n\n\n@dataclass\nclass Response:\n    \"\"\"An HTTP response\"\"\"\n\n    status: int\n    content_type: str\n    body: str\n\n\nclass View:\n    \"\"\"A simple view that returns plain text responses\"\"\"\n\n    content_type = \"text/plain\"\n\n    def render_body(self) -> str:\n        \"\"\"Render the message body of the response\"\"\"\n        return \"Welcome to my web site\"\n\n    def get(self, request) -> Response:\n        \"\"\"Handle a GET request and return a message in the response\"\"\"\n        return Response(\n            status=200,\n            content_type=self.content_type,\n            body=self.render_body()\n        )\n\n\nclass TemplateView(View):\n    \"\"\"A view that returns HTML responses based on a template file.\"\"\"\n\n    content_type = \"text/html\"\n    template_file = \"index.html\"\n\n    def render_body(self) -> str:\n        \"\"\"Render the message body as HTML\"\"\"\n        with open(self.template_file) as fd:\n            return fd.read()\n\n\n```\nتوجه داشته باشید که نیاز داشتیم `render_body()` را از نو نویسی کنیم تا منبع بدنه را عوض کنیم، اما این کلاس، تنها یک مسئولیت به درستی تعیین شده دارد که **کلاس های فرعی را دعوت میکند که آن را از نو نویسی کنند**. جوری ساخته شده است که اجازه ی گسترش داده شدن توسط کلاس های فرعی را بدهد.\nیک راه خوب دیگر برای استفاده از قدرت های ارث بری و ترکیب اشیاء استفاده از [Mixins](https://docs.djangoproject.com/en/4.1/topics/class-based-views/mixins/) ها است.\n\nمیکسین ها کلاس های ریشه و ساده ای هستند که به طور انحصاری با سایر کلاس های مرتبط استفاده می شوند. آنها با کلاس هدف با استفاده از وراثت چندگانه \"مخلوط\" می شوند تا رفتار هدف را تغییر دهند.\n\nچند قانون :\n - میکسین ها باید از `object` ارث بری کنند.\n - میکسین ها همیشه قبل از کلاس هدف میایند. برای مثال : \n\n`class Foo(MixinA, MixinB, TargetClass): ...`\n\n**همچنین خوب :**\n```python\nfrom dataclasses import dataclass, field\nfrom typing import Protocol\n\n\n@dataclass\nclass Response:\n    \"\"\"An HTTP response\"\"\"\n\n    status: int\n    content_type: str\n    body: str\n    headers: dict = field(default_factory=dict)\n\n\nclass View:\n    \"\"\"A simple view that returns plain text responses\"\"\"\n\n    content_type = \"text/plain\"\n\n    def render_body(self) -> str:\n        \"\"\"Render the message body of the response\"\"\"\n        return \"Welcome to my web site\"\n\n    def get(self, request) -> Response:\n        \"\"\"Handle a GET request and return a message in the response\"\"\"\n        return Response(\n            status=200,\n            content_type=self.content_type,\n            body=self.render_body()\n        )\n\n\nclass TemplateRenderMixin:\n    \"\"\"A mixin class for views that render HTML documents using a template file\n\n    Not to be used by itself!\n    \"\"\"\n    template_file: str = \"\"\n\n    def render_body(self) -> str:\n        \"\"\"Render the message body as HTML\"\"\"\n        if not self.template_file:\n            raise ValueError(\"The path to a template file must be given.\")\n\n        with open(self.template_file) as fd:\n            return fd.read()\n\n\nclass ContentLengthMixin:\n    \"\"\"A mixin class for views that injects a Content-Length header in the\n    response\n\n    Not to be used by itself!\n    \"\"\"\n\n    def get(self, request) -> Response:\n        \"\"\"Introspect and amend the response to inject the new header\"\"\"\n        response = super().get(request) # type: ignore\n        response.headers['Content-Length'] = len(response.body)\n        return response\n\n\nclass TemplateView(TemplateRenderMixin, ContentLengthMixin, View):\n    \"\"\"A view that returns HTML responses based on a template file.\"\"\"\n\n    content_type = \"text/html\"\n    template_file = \"index.html\"\n\n```\n\nهمانطور که میبینید، میکسین ها ترکیب اشیاء را، با بسته بندی کردن عملکرد های مشابه و تبدیل آنها به یک کلاس قابل استفاده دوباره با یک مسئولیت و اجازه جدا کردن آنها، آسان میکنند.\nفریم ورک مشهور جنگو استفاده زیادی از میکسین ها میکند تا ویو های مبتنی بر کلاس خود را بسازد.\n\n### **Liskov Substitution Principle (LSP)**\n\n> “ توابعی که از اشاره گر ها یا ارجاع ها به کلاس های پایه استفاده میکنند باید بتوانند اشیاء کلاس ارث بری شده را بدون دانستن استفاد کنند. “ Uncle Bob.\n\nاین اصل به افتخار Barbara Liskov نامگذاری شده، که با دانشمند کامپیوتر دیگری به نام Jeannette Wing در مقاله ی \"A behavioral notion of subtyping (1994)\" همکاری کرده است. \nیک اصل اصلی مقاله این است که \" یک نوع فرعی باید رفتار متود های نوع اصلی خود را حفظ و همچنین تمام ویژگی‌های تغییرناپذیر و تاریخی نوع اصلی خود را نگه دارد.\n\nاین به این معناست که، یک تابع که یک نوع اصلی را قبول میکند باید همچنین نوع های فرعی آن را بدون هیچ تغیری قبول کند.\n\nمیتوانید مشکل کد زیر را پیدا کنید ؟\n\n**بد :**\n```python\nfrom dataclasses import dataclass\n\n\n@dataclass\nclass Response:\n    \"\"\"An HTTP response\"\"\"\n\n    status: int\n    content_type: str\n    body: str\n\n\nclass View:\n    \"\"\"A simple view that returns plain text responses\"\"\"\n\n    content_type = \"text/plain\"\n\n    def render_body(self) -> str:\n        \"\"\"Render the message body of the response\"\"\"\n        return \"Welcome to my web site\"\n\n    def get(self, request) -> Response:\n        \"\"\"Handle a GET request and return a message in the response\"\"\"\n        return Response(\n            status=200,\n            content_type=self.content_type,\n            body=self.render_body()\n        )\n\n\nclass TemplateView(View):\n    \"\"\"A view that returns HTML responses based on a template file.\"\"\"\n\n    content_type = \"text/html\"\n\n    def get(self, request, template_file: str) -> Response: # type: ignore\n        \"\"\"Render the message body as HTML\"\"\"\n        with open(template_file) as fd:\n            return Response(\n                status=200,\n                content_type=self.content_type,\n                body=fd.read()\n            )\n\n\ndef render(view: View, request) -> Response:\n    \"\"\"Render a View\"\"\"\n    return view.get(request)\n\n```\n\nانتظار میرود که فانکشن `render()` به خوبی بتواند با `View` و زیرکلاسش `TemplateView`  کار کند، اما زیرکلاسش این سازگاری را با تغییر متود `.get()` از بین برده است. \nتابع خطای `TypeError` را هنگامی که با `TemplateView` استفاده شود برمیگرداند.\n\nاگر بخواهیم که تابع `render()` با هر زیرنوعی از `View` کار کند، باید توجه کنیم که پروتوکل عمومی آن را نشکنیم. اما از کجا بدانیم که چه چیزی یک کلاس را تشکیل میدهد؟ Type Hinter هایی مثل *mypy*  اگر اشتباهاتی مثل این ببینند، اخطار هایی به این شکل برمیگردانند :\n```\nerror: Signature of \"get\" incompatible with supertype \"View\"\n<string>:36: note:      Superclass:\n<string>:36: note:          def get(self, request: Any) -> Response\n<string>:36: note:      Subclass:\n<string>:36: note:          def get(self, request: Any, template_file: str) -> Response\n```\n\n### **Interface Segregation Principle (ISP)**\n\n> اینترفیس ها را کوچک نگه دارید تا کاربر ها نیاز  وابسته به چیزهایی که از آنها بی نیازند نشوند. Uncle Bob.\n\nچندین زبان برنامه نویسی مشهور شیء گرا مثل Go و Java مفهمومی به نام اینترفیس ها دارند. اینترفیس ها متود های عمومی و ویژگی های یک شیء را بدون پیاده سازی آن تعریف میکند. آنها زمانی مفید هستند که نمی خواهیم امضای یک تابع را با یک شیء مشخص مرتبط کنیم.\nپایتون اینترفیس ندارد. اما به جایش Abstract Base Clase دارد که کمی متقاوت هستند، اما میتوانند همانکار را انجام دهند.\n\n**خوب**\n```python\n\nfrom abc import ABCMeta, abstractmethod\n\n\n# Define the Abstract Class for a generic Greeter object\nclass Greeter(metaclass=ABCMeta):\n    \"\"\"An object that can perform a greeting action.\"\"\"\n\n    @staticmethod\n    @abstractmethod\n    def greet(name: str) -> None:\n        \"\"\"Display a greeting for the user with the given name\"\"\"\n\n\nclass FriendlyActor(Greeter):\n    \"\"\"An actor that greets the user with a friendly salutation\"\"\"\n\n    @staticmethod\n    def greet(name: str) -> None:\n        \"\"\"Greet a person by name\"\"\"\n        print(f\"Hello {name}!\")\n\n\ndef welcome_user(user_name: str, actor: Greeter):\n    \"\"\"Welcome a user with a given name using the provided actor\"\"\"\n    actor.greet(user_name)\n\n\nwelcome_user(\"Barbara\", FriendlyActor())\n```\nحالا این سناریو را در نظر بگیرید : میخواهیم تعداد مشخصی سند PDF داشته باشیم که ما نوشتیم و میخواهیم به بازدید کننده های وبسایتمان داده شوند. ما از یک وب فریمورک پایتون استفاده میکنیم و شاید وسوسه شویم که کلاسی را طراحی کنیم که این اسناد را مدیریت کند، پس یک کلاس پایه انتزاعی جامع برای سند خود طراحی می کنیم.\n\n**خطا**\n```python\nimport abc\n\n\nclass Persistable(metaclass=abc.ABCMeta):\n    \"\"\"Serialize a file to data and back\"\"\"\n\n    @property\n    @abc.abstractmethod\n    def data(self) -> bytes:\n        \"\"\"The raw data of the file\"\"\"\n\n    @classmethod\n    @abc.abstractmethod\n    def load(cls, name: str):\n        \"\"\"Load the file from disk\"\"\"\n\n    @abc.abstractmethod\n    def save(self) -> None:\n        \"\"\"Save the file to disk\"\"\"\n\n\n# We just want to serve the documents, so our concrete PDF document\n# implementation just needs to implement the `.load()` method and have\n# a public attribute named `data`.\n\nclass PDFDocument(Persistable):\n    \"\"\"A PDF document\"\"\"\n\n    @property\n    def data(self) -> bytes:\n        \"\"\"The raw bytes of the PDF document\"\"\"\n        ... # Code goes here - omitted for brevity\n\n    @classmethod\n    def load(cls, name: str):\n        \"\"\"Load the file from the local filesystem\"\"\"\n        ... # Code goes here - omitted for brevity\n\n\ndef view(request):\n    \"\"\"A web view that handles a GET request for a document\"\"\"\n    requested_name = request.qs['name'] # We want to validate this!\n    return PDFDocument.load(requested_name).data\n\n```\nاما نمیتونیم! اگر متود `.save()` را پیاده سازی نکنیم یک خطا به ما نشان داده میشود :\n\n```\nCan't instantiate abstract class PDFDocument with abstract method save.\n```\nاین اعصاب خورد کن است. ما واقعا نیازی به پیاده سازی `.save()` در اینجا نداریم. میتوانیم یک متود بنویسیم که هیچ کاری نکند یا خطای `NotImplementedError` را برگرداند اما این فقط کد اضافی ای است که باید مراقبش باشیم.\n\nدر عین حال، اگر `.save()` را از کلاس انتزاعی حذف کنیم نیاز خواهیم داشت بعدا برای اینکه کاربران بتوانند اسنادشان را ارسال کنند از نو پیاده سازی کنیم که دوباره مارا به خانه ی اول برمیگرداند.\n\nمشکل اینجاست که ما یک *اینترفیس* نوشتیم که قابلیت هایی دارد که ما در حال حاظر به آنها یا نیاز نداریم یا استفاده نمیکنیم.\n\nراه حل این است که اینترفیست را به قطعات کوچک تر که کارهای جدا میکنند تکه تکه کنیم.\n\n**خوب**\n```python\nimport abc\n\n\nclass DataCarrier(metaclass=abc.ABCMeta):\n    \"\"\"Carries a data payload\"\"\"\n    @property\n    def data(self):\n        ...\n\nclass Loadable(DataCarrier):\n    \"\"\"Can load data from storage by name\"\"\"\n    @classmethod\n    @abc.abstractmethod\n    def load(cls, name: str):\n        ...\n\nclass Saveable(DataCarrier):\n    \"\"\"Can save data to storage\"\"\"\n    @abc.abstractmethod\n    def save(self) -> None:\n        ...\n\n\nclass PDFDocument(Loadable):\n    \"\"\"A PDF document\"\"\"\n\n    @property\n    def data(self) -> bytes:\n        \"\"\"The raw bytes of the PDF document\"\"\"\n        ... # Code goes here - omitted for brevity\n\n    @classmethod\n    def load(cls, name: str):\n        \"\"\"Load the file from the local filesystem\"\"\"\n        ... # Code goes here - omitted for brevity\n\n\ndef view(request):\n    \"\"\"A web view that handles a GET request for a document\"\"\"\n    requested_name = request.qs['name'] # We want to validate this!\n    return PDFDocument.load(requested_name).data\n\n```\n\n### **Dependency Inversion Principle (DIP)**\n\n> “به انتزاع وابسته شوید، نه جزئیات مشخص.”,\n> Uncle Bob.\n\nتصور کنید میخواستیم که یک وب ویو درست کنیم که پاسخ HTTP ای را برمیگرداند که ردیف هایی از فایل CSV ای که ساختیم برمیگراند. میخواهیم از نویسنده ی CSV ای استفاده کنیم که توسط کتابخانه ی استاندارد پایتون ارائه میشود.\n\n**بد**\n```python\nimport csv\nfrom io import StringIO\n\n\nclass StreamingHttpResponse:\n    \"\"\"A streaming HTTP response\"\"\"\n    ... # implementation code goes here\n\n\ndef some_view(request):\n   rows = (\n       ['First row', 'Foo', 'Bar', 'Baz'],\n       ['Second row', 'A', 'B', 'C', '\"Testing\"', \"Here's a quote\"]\n   )\n   # Define a generator to stream data directly to the client\n   def stream():\n       buffer_ = StringIO()\n       writer = csv.writer(buffer_, delimiter=';', quotechar='\"')\n       for row in rows:\n           writer.writerow(row)\n           buffer_.seek(0)\n           data = buffer_.read()\n           buffer_.seek(0)\n           buffer_.truncate()\n           yield data\n\n   # Create the streaming response  object with the appropriate CSV header.\n   response = StreamingHttpResponse(stream(), content_type='text/csv')\n   response['Content-Disposition'] = 'attachment; filename=\"somefilename.csv\"'\n\n   return response\n\n```\nاولین پیاده‌سازی ما حول رابط نویسنده CSV با دستکاری یک شی `StringIO` (که شبه فایل است) و انجام چندین عملیات سطح پایین به منظور جداسازی ردیف‌ها از نویسنده کار می‌کند.\n\nیک راه بهتر این است که از این واقعیت استفاده کنیم که نویسنده به یک شی با متد `.write()‍‍` برای انجام کار ما نیاز دارد.\nچرا یک شی ساختگی که بلافاصله ردیف جدید ساخته شده را برمی گرداند، به آن منتقل نکنیم تا کلاس ‍`StreamingHttpResponse` بتواند بلافاصله آن را به کلاینت بازگرداند؟\n\n**خوب**\n```python\nimport csv\n\n\nclass Echo:\n   \"\"\"An object that implements just the write method of the file-like\n   interface.\n   \"\"\"\n   def write(self, value):\n       \"\"\"Write the value by returning it, instead of storing in a buffer.\"\"\"\n       return value\n\ndef some_streaming_csv_view(request):\n   \"\"\"A view that streams a large CSV file.\"\"\"\n   rows = (\n       ['First row', 'Foo', 'Bar', 'Baz'],\n       ['Second row', 'A', 'B', 'C', '\"Testing\"', \"Here's a quote\"]\n   )\n   writer = csv.writer(Echo(), delimiter=';', quotechar='\"')\n   return StreamingHttpResponse(\n       (writer.writerow(row) for row in rows),\n       content_type=\"text/csv\",\n       headers={'Content-Disposition': 'attachment; filename=\"somefilename.csv\"'},\n   )\n\n```\nخیلی بهتر شد، و مثل جادو کار میکند! دلیل اینکه پیاده سازی آن بهتر از قبلیست باید واضخ باشد: کد کمتر و بازدهی بیشتر برای رسیدن به پاسخ یکسان. ما تصمیم گرفتیم که از واقعیت این که کلاس نویسنده به انتزاع `.write()` از شیء ای که دریافت میکند وابسته است، بدون اینکه به جزئیات سطح پایین عملکرد متود توجه ای کند.\nاین مثال از [ارسالی به مستندات جنگو](https://code.djangoproject.com/ticket/21179) توسط این نویسنده گرفته شده است.\n\n**[⬆ برگشت به بالا](#فهرست-مطالب)**\n\n## **Don't repeat yourself (DRY)**\n\nتلاش کنید که اصل [DRY](https://fa.wikipedia.org/wiki/Don%27t_repeat_yourself) را متوجه بشوید.\n\nبهترین تلاشتان را بکنید که کدی را دوباره ننویسید. تکرار کد بد است چون به این معنیست که هنگام ایجاد تغییر، باید بیشتر از دو جا را تغییر دهید.\n\nتصور کنید که صاحب رستورانی هستید و میخواهید آمار انبارتان را داشته باشید: تمامی گوجه ها، پیاز ها، سیر ها، ادویه ها و... . اگر چندین لیست داشته باشید که آمار اینهارا ثبت کنند، هروقت که غذایی با گوجه سرو کنید باید تمامی این لیست هارا آپدیت کنید. اما اگر فقط یک لیست داشته باشید، فقط یک جا را باید آپدیت کنید!\n\nبیشتر اوقات شما وقتی کد را چندین بار تکرار میکنید که دو چیز یا بیشتر کمی متفاوت داشته باشید، که بسیار شبیه به هم باشند، اما این شباهتشان شمارا به داشتن دو تابع یا بیشتر مجبور میکنند که اکثراً یک کار را انجام میدهند. حذف کردن کد های تکراری به معنی ساختن انتزاعی است که بتواند این کارهارا با یک تابع/ماژول/کلاس انجام دهد.\n\nدرست ساختن انتزاع مهم است. انتزاع بد میتواند از کد تکراری هم بدتر باشد! با این، اگر میتوانید یک انتزاع خوب بسازید، انجامش دهید! خودتان را تکرار نکنید، وگرنه مجبور میشوید چندین جا را برای تغییر کوچکی آپدیت کنید.\n\n**بد:**\n\n```python\nfrom typing import List, Dict\nfrom dataclasses import dataclass\n\n@dataclass\nclass Developer:\n    def __init__(self, experience: float, github_link: str) -> None:\n        self._experience = experience\n        self._github_link = github_link\n        \n    @property\n    def experience(self) -> float:\n        return self._experience\n    \n    @property\n    def github_link(self) -> str:\n        return self._github_link\n    \n@dataclass\nclass Manager:\n    def __init__(self, experience: float, github_link: str) -> None:\n        self._experience = experience\n        self._github_link = github_link\n        \n    @property\n    def experience(self) -> float:\n        return self._experience\n    \n    @property\n    def github_link(self) -> str:\n        return self._github_link\n    \n\ndef get_developer_list(developers: List[Developer]) -> List[Dict]:\n    developers_list = []\n    for developer in developers:\n        developers_list.append({\n        'experience' : developer.experience,\n        'github_link' : developer.github_link\n            })\n    return developers_list\n\ndef get_manager_list(managers: List[Manager]) -> List[Dict]:\n    managers_list = []\n    for manager in managers:\n        managers_list.append({\n        'experience' : manager.experience,\n        'github_link' : manager.github_link\n            })\n    return managers_list\n\n## create list objects of developers\ncompany_developers = [\n    Developer(experience=2.5, github_link='https://github.com/1'),\n    Developer(experience=1.5, github_link='https://github.com/2')\n]\ncompany_developers_list = get_developer_list(developers=company_developers)\n\n## create list objects of managers\ncompany_managers = [\n    Manager(experience=4.5, github_link='https://github.com/3'),\n    Manager(experience=5.7, github_link='https://github.com/4')\n]\ncompany_managers_list = get_manager_list(managers=company_managers)\n```\n\n**خوب:**\n\n```python\nfrom typing import List, Dict\nfrom dataclasses import dataclass\n\n@dataclass\nclass Employee:\n    def __init__(self, experience: float, github_link: str) -> None:\n        self._experience = experience\n        self._github_link = github_link\n        \n    @property\n    def experience(self) -> float:\n        return self._experience\n    \n    @property\n    def github_link(self) -> str:\n        return self._github_link\n    \n\n\ndef get_employee_list(employees: List[Employee]) -> List[Dict]:\n    employees_list = []\n    for employee in employees:\n        employees_list.append({\n        'experience' : employee.experience,\n        'github_link' : employee.github_link\n            })\n    return employees_list\n\n## create list objects of developers\ncompany_developers = [\n    Employee(experience=2.5, github_link='https://github.com/1'),\n    Employee(experience=1.5, github_link='https://github.com/2')\n]\ncompany_developers_list = get_employee_list(employees=company_developers)\n\n## create list objects of managers\ncompany_managers = [\n    Employee(experience=4.5, github_link='https://github.com/3'),\n    Employee(experience=5.7, github_link='https://github.com/4')\n]\ncompany_managers_list = get_employee_list(employees=company_managers)\n```\n\n**[⬆ برگشت به بالا](#فهرست-مطالب)**\n"
  },
  {
    "path": "conftest.py",
    "content": "import importlib\nimport re\nimport time\nimport typing\nfrom pathlib import Path\n\nimport pytest\nfrom mypy import api\n\ncode_rxp = re.compile('```python(.*?)```', re.DOTALL | re.MULTILINE)\n\n\nclass MyPyValidationError(BaseException):\n    \"\"\"A validation error occurred when MyPy attempted to validate the code\"\"\"\n\n\ndef fake_print(*args, **kwargs):\n    \"\"\"Dummy replacement for print() that does nothing\"\"\"\n    pass\n\n\ndef pytest_collect_file(parent, path):\n    \"\"\"Collect all file suitable for use in tests\"\"\"\n    if path.basename == \"README.md\":\n        return ReadmeFile.from_parent(parent, path=Path(path))\n\n\nclass ReadmeFile(pytest.File):\n    \"\"\"A Markdown formatted readme file containing code snippets\"\"\"\n\n    def collect(self):\n        \"\"\"Collect all code snippets\"\"\"\n        raw_text = self.fspath.open().read()\n        for idx, code in enumerate(code_rxp.findall(raw_text), 1):\n            yield ReadmeItem.from_parent(\n                self, name=str(idx), spec=code.strip()\n            )\n\n\ndef _with_patched_sleep(func, *args, **kwargs):\n    \"\"\"Patch the sleep function so that it does nothing\"\"\"\n    _sleep = time.sleep\n    time.sleep = lambda *args: None\n    try:\n        return func(*args, **kwargs)\n    finally:\n        time.sleep = _sleep\n\n\nclass ReadmeItem(pytest.Item):\n    \"\"\"A readme test item that validates a code snippet\"\"\"\n    builtins = (\n        ('typing', typing),\n        ('datetime', importlib.import_module('datetime')),\n        ('hashlib', importlib.import_module('hashlib')),\n        ('print', fake_print)\n    )\n\n    def __init__(self, name, parent, spec):\n        super().__init__(name, parent)\n        self.spec = spec\n\n    def runtest(self):\n        \"\"\"Run the test\"\"\"\n        builtins = dict(self.builtins)\n        byte_code = compile(self.spec, '<inline>', 'exec')\n        _with_patched_sleep(exec, byte_code, builtins)\n        msg, _, error = api.run(['--no-color-output', '-c', self.spec])\n        if error:\n            # Ignore missing errors related to the injected names\n            for name in builtins:\n                if f\"Name '{name}' is not defined\" in msg:\n                    break\n            else:\n                raise MyPyValidationError(msg)\n\n    def repr_failure(self, excinfo, **kwargs):\n        \"\"\" called when self.runtest() raises an exception. \"\"\"\n        return (\n            f\"Code snippet {self.name} raised an error: {excinfo.value}. \"\n            f\"The executed code was: {self.spec}\"\n        )\n\n    def reportinfo(self):\n        \"\"\"Report some basic information on the test outcome\"\"\"\n        return self.fspath, 0, \"usecase: {}\".format(self.name)\n"
  },
  {
    "path": "requirements.txt",
    "content": "pytest\nmypy\n"
  }
]