Coding Convention 2_GOOGLE - SubarnaSaha08/JUMCMS-Jahangirnagar-University-Medical-Center-Management-System GitHub Wiki
Python coding style
This style guide report is based on Google Python Style Guide . Here are the key points:
Imports
Use import statements for packages and modules only, not for individual types, classes, or functions.
Pros
The namespace management convention is simple. The source of each identifier is indicated in a consistent way; x.Obj says that object Obj is defined in module x.
Cons
Module names can still collide. Some module names are inconveniently long.
Decisions
- Use import x for importing packages and modules.
- Use from x import y where x is the package prefix and y is the module name with no prefix.
Examples
from sound.effects import echo
import numpy as np
Nested/Local/Inner Classes and Functions
Nested local functions or classes are fine when used to close over a local variable. Inner classes are fine.
Pros
Allows definition of utility classes and functions that are only used inside of a very limited scope. Very ADT-y. Commonly used for implementing decorators.
Cons
Nested functions and classes cannot be directly tested. Nesting can make the outer function longer and less readable.
Decision
They are fine with some caveats. Avoid nested functions or classes except when closing over a local value other than self or cls. Do not nest a function just to hide it from users of a module. Instead, prefix its name with an _ at the module level so that it can still be accessed by tests.
Default Iterators and Operators
Use default iterators and operators for types that support them, like lists, dictionaries, and files.
Pros
The default iterators and operators are simple and efficient. They express the operation directly, without extra method calls. A function that uses default operators is generic. It can be used with any type that supports the operation.
Cons
You can’t tell the type of objects by reading the method names (unless the variable has type annotations). This is also an advantage.
Decision
Use default iterators and operators for types that support them, like lists, dictionaries, and files. The built-in types define iterator methods, too. Prefer these methods to methods that return lists, except that you should not mutate a container while iterating over it.
Yes: for key in adict: ...
if obj in alist: ...
for line in afile: ...
for k, v in adict.items(): ...
Conditional Expressions
Okay for simple cases.
Pros
Shorter and more convenient than an if statement.
Cons
May be harder to read than an if statement. The condition may be difficult to locate if the expression is long
Decision
Okay to use for simple cases. Each portion must fit on one line: true-expression, if-expression, else-expression. Use a complete if statement when things get more complicated.
Example
Yes:
one_line = 'yes' if predicate(value) else 'no'
slightly_split = ('yes' if predicate(value)
else 'no, nein, nyet')
the_longest_ternary_style_that_can_be_done = (
'yes, true, affirmative, confirmed, correct'
if predicate(value)
else 'no, false, negative, nay')
True/False Evaluations
Use the “implicit” false if at all possible (with a few caveats).
Pros
Conditions using Python booleans are easier to read and less error-prone. In most cases, they’re also faster.
Cons
May look strange to C/C++ developers.
Decision
Use the “implicit” false if possible, e.g., if foo: rather than if foo != []:
Examples
Yes: if not users:
print('no users')
if i % 10 == 0:
self.handle_multiple_of_ten()
def f(x=None):
if x is None:
x = []
No: if len(users) == 0:
print('no users')
if not i % 10:
self.handle_multiple_of_ten()
def f(x=None):
x = x or []
Semicolons
Do not terminate your lines with semicolons, and do not use semicolons to put two statements on the same line.
Yes: foo_bar(self, width, height, color='black', design=None, x='foo',
emphasis=None, highlight=0)
Yes: if (width == 0 and height == 0 and
color == 'red' and emphasis == 'strong'):
(bridge_questions.clarification_on
.average_airspeed_of.unladen_swallow) = 'African or European?'
with (
very_long_first_expression_function() as spam,
very_long_second_expression_function() as beans,
third_thing() as eggs,
):
place_order(eggs, beans, spam, beans)
Line length
Maximum line length is 80 characters. Explicit exceptions to the 80 character limit:
- Long import statements.
- URLs, pathnames, or long flags in comments.
Example
Yes: foo_bar(self, width, height, color='black', design=None, x='foo',
emphasis=None, highlight=0)
Yes: if (width == 0 and height == 0 and
color == 'red' and emphasis == 'strong'):
(bridge_questions.clarification_on
.average_airspeed_of.unladen_swallow) = 'African or European?'
with (
very_long_first_expression_function() as spam,
very_long_second_expression_function() as beans,
third_thing() as eggs,
):
place_order(eggs, beans, spam, beans)
Parentheses
Use parentheses sparingly.It is fine, though not required, to use parentheses around tuples. Do not use them in return statements or conditional statements unless using parentheses for implied line continuation or to indicate a tuple.
Yes: if foo:
bar()
while x:
x = bar()
if x and y:
bar()
if not x:
bar()
# For a 1 item tuple the ()s are more visually obvious than the comma.
onesie = (foo,)
return foo
return spam, beans
return (spam, beans)
for (x, y) in dict.items(): ...
Indentation
Indent your code blocks with 4 spaces. Never use tabs. Implied line continuation should align wrapped elements vertically (see line length examples), or use a hanging 4-space indent. Closing (round, square or curly) brackets can be placed at the end of the expression, or on separate lines, but then should be indented the same as the line with the corresponding opening bracket.
Yes: # Aligned with opening delimiter.
foo = long_function_name(var_one, var_two,
var_three, var_four)
meal = (spam,
beans)
# Aligned with opening delimiter in a dictionary.
foo = {
'long_dictionary_key': value1 +
value2,
...
}
# 4-space hanging indent; nothing on first line.
foo = long_function_name(
var_one, var_two, var_three,
var_four)
meal = (
spam,
beans)
# 4-space hanging indent; nothing on first line,
# closing parenthesis on a new line.
foo = long_function_name(
var_one, var_two, var_three,
var_four
)
meal = (
spam,
beans,
)
# 4-space hanging indent in a dictionary.
foo = {
'long_dictionary_key':
long_dictionary_value,
...
}
Trailing commas in sequences of items
Trailing commas in sequences of items are recommended only when the closing container token ], ), or } does not appear on the same line as the final element, as well as for tuples with a single element. The presence of a trailing comma is also used as a hint to our Python code auto-formatter Black or Pyink to direct it to auto-format the container of items to one item per line when the , after the final element is present.
Yes: golomb3 = [0, 1, 3]
golomb4 = [
0,
1,
4,
6,
]
No: golomb4 = [
0,
1,
4,
6,]
Blank Lines
Two blank lines between top-level definitions, be they function or class definitions. One blank line between method definitions and between the docstring of a class and the first method. No blank line following a def line. Use single blank lines as you judge appropriate within functions or methods.
Blank lines need not be anchored to the definition. For example, related comments immediately preceding function, class, and method definitions can make sense. Consider if your comment might be more useful as part of the docstring.
Whitespace
Follow standard typographic rules for the use of spaces around punctuation.
No whitespace inside parentheses, brackets or braces.
Yes: spam(ham[1], {'eggs': 2}, [])
No whitespace before a comma, semicolon, or colon. Do use whitespace after a comma, semicolon, or colon, except at the end of the line.
Yes: if x == 4:
print(x, y)
x, y = y, x
Modules
Every file should contain license boilerplate. Choose the appropriate boilerplate for the license used by the project (for example, Apache 2.0, BSD, LGPL, GPL).Files should start with a docstring describing the contents and usage of the module.
"""A one-line summary of the module or program, terminated by a period.
Leave one blank line. The rest of this docstring should contain an
overall description of the module or program. Optionally, it may also
contain a brief description of exported classes and functions and/or usage
examples.
Typical usage example:
foo = ClassFoo()
bar = foo.FunctionBar()
"""
Functions and Methods
In this section, “function” means a method, function, generator, or property.A docstring is mandatory for every function that has one or more of the following properties:
- being part of the public API
- nontrivial size
- non-obvious logic
A docstring should give enough information to write a call to the function without reading the function’s code. The docstring should describe the function’s calling syntax and its semantics, but generally not its implementation details, unless those details are relevant to how the function is to be used. For example, a function that mutates one of its arguments as a side effect should note that in its docstring. Otherwise, subtle but important details of a function’s implementation that are not relevant to the caller are better expressed as comments alongside the code than within the function’s docstring.
def fetch_smalltable_rows(
table_handle: smalltable.Table,
keys: Sequence[bytes | str],
require_all_keys: bool = False,
) -> Mapping[bytes, tuple[str, ...]]:
"""Fetches rows from a Smalltable.
Retrieves rows pertaining to the given keys from the Table instance
represented by table_handle. String keys will be UTF-8 encoded.
Args:
table_handle: An open smalltable.Table instance.
keys: A sequence of strings representing the key of each table
row to fetch. String keys will be UTF-8 encoded.
require_all_keys: If True only rows with values set for all keys will be
returned.
Returns:
A dict mapping keys to the corresponding table row data
fetched. Each row is represented as a tuple of strings. For
example:
{b'Serak': ('Rigel VII', 'Preparer'),
b'Zim': ('Irk', 'Invader'),
b'Lrrr': ('Omicron Persei 8', 'Emperor')}
Returned keys are always bytes. If a key from the keys argument is
missing from the dictionary, then that row was not found in the
table (and require_all_keys must have been False).
Raises:
IOError: An error occurred accessing the smalltable.
"""
Classes
Classes should have a docstring below the class definition describing the class. Public attributes, excluding properties, should be documented here in an Attributes section and follow the same formatting as a function’s Args section.
class SampleClass:
"""Summary of class here.
Longer class information...
Longer class information...
Attributes:
likes_spam: A boolean indicating if we like SPAM or not.
eggs: An integer count of the eggs we have laid.
"""
def __init__(self, likes_spam: bool = False):
"""Initializes the instance based on spam preference.
Args:
likes_spam: Defines if instance exhibits this preference.
"""
self.likes_spam = likes_spam
self.eggs = 0
@property
def butter_sticks(self) -> int:
"""The number of butter sticks we have."""
Block and Inline Comments
The final place to have comments is in tricky parts of the code. If you’re going to have to explain it at the next code review, you should comment it now. Complicated operations get a few lines of comments before the operations commence. Non-obvious ones get comments at the end of the line.
# We use a weighted dictionary search to find out where i is in
# the array. We extrapolate position based on the largest num
# in the array and the array size and then do binary search to
# get the exact number.
if i & (i-1) == 0: # True if i is 0 or a power of 2.
String
Use an f-string, the % operator, or the format method for formatting strings, even when the parameters are all strings. Use your best judgment to decide between string formatting options. A single join with + is okay but do not format with +.
Yes: x = f'name: {name}; score: {n}'
x = '%s, %s!' % (imperative, expletive)
x = '{}, {}'.format(first, second)
x = 'name: %s; score: %d' % (name, n)
x = 'name: %(name)s; score: %(score)d' % {'name':name, 'score':n}
x = 'name: {}; score: {}'.format(name, n)
x = a + b