Tips to look at before you start writing Python

I stumbled upon various points using Python, but here are some tips I should have known before I started writing so that I could avoid such traps and have a comfortable Python Life.

About Python 2 and 3

There are 2 and 3 series in Python, and 3 series has changes that affect backward compatibility. In other words, Python3 code may not work in Python2 (and vice versa).

Python3 has improved various points in Python2, and if you use it from now on, it is basically done with the latest version of Python3 (also below, I have specified what will be improved with Python3). Best of all, Python 2 ends support as of January 1, 2020. So there is no reason to use Python 2 from now on. Those who still use Python 2 are dissed by elementary school students.

However, there are some packages out there that aren't yet compatible with Python3, and whether or not you hit those packages in your project is a fateful diversion. You can check the support status in a list from here. However, I think that most packages are already supported or should be run with Python3 [There is also automatic conversion from 2 to 3](http://docs.python.jp/2/library/2to3. html). On the contrary, if it does not support Python 3, it can be said that the maintenance status should be doubted. For Google App Engine, the second generation finally supports Python 3. Even OpenAI, a leading research institute for artificial intelligence, has shifted to Python 3, so those who say "machine learning is not yet around" are not at least advanced. Being human, you don't have to rely on what you say.

Python setup

When developing Python, it is almost essential to install pip and virtualenv in addition to Python itself, so here is a summary of how to set up Python, pip, and virtualenv in each environment.

If you want to do machine learning

I think there are many reasons why I want to do machine learning as a reason to choose Python, so I will introduce the method for that first. To build an environment for machine learning, we recommend using Miniconda regardless of whether it is Mac / Linux / Windows.

Miniconda

The installation method is as shown on the above page. Miniconda has a function to create an environment (virtual environment) for each application, and it is easy to install machine learning related packages. In addition, cuda required for GPU and mingw, which is a Windows build environment, can be installed. It's possible, and it's easier to deploy tools other than simple packages. About TensorFlow, in addition to installing tools around the GPU by installing with conda, it operates at high speed in the case of CPU version (Details tensorflow-in-anaconda /)).

You can create a general machine learning environment such as scikit-learn on Jupyter Notebook with the following command after installing Miniconda.

conda create -n ml_env numpy scipy scikit-learn matplotlib jupyter
activate ml_env

I created an environment called ml_env with conda create and enabled it with ʻactivate. For details on how to use the conda` command, refer to here (it does not start for Windows / Powershell. For details, see [Windows section] ](Https://qiita.com/icoxfog417/items/e8f97a6acad07903b5b0#windows%E3%81%AE%E5%A0%B4%E5%90%88) Reference).

The environment of Miniconda is also provided in Dockerfile, and you can easily create a container by inheriting it with FROM continuumio / miniconda3 etc.

If you want to share a machine learning environment with a Docker container, or if you are thinking of deploying to a PaaS environment such as Heroku, we recommend that you consider using Docker (Heroku supports docker push with Container Registry function. I'm doing it.

Anaconda is not recommended as a machine learning environment for the following two reasons.

Note that even with Miniconda, if you do not regularly delete unused packages with conda clean --all, you will be able to take a few G lightly **. This is to cache packages that conda has downloaded once. Even if you are using an old package that you are not using now, it will remain as long as you do not delete it, so it is good to delete it.

Introduction of Python

For Mac / Linux

Python is included by default, but it may not match the version you want to develop. Therefore, it is good to use pyenv so that you can switch the Python version to be used for each project. However, as mentioned above, if you use Miniconda, you can manage the version of Python here, so you do not need to install pyenv. Furthermore, when using Miniconda, it is better not to install pyenv because command batting occurs and the shell hangs when activating the virtual environment (ʻactivate`).

Python used in each project is set in pyenv local x.x.x. After installing a new Python environment with pyenv, pyenv rehash is required. If you still can't find the installation, try restarting the terminal.

For Windows

You can install it normally, but Miniconda is recommended.

Please note that as of 2018, [ʻactivatedoes not start yet in PowerShell](https://github.com/conda/conda/issues/626). If you don't want to switch tocmd every time, you can use it by installing pscondaenvs (the following is the case of installing in the global environment ( root`)).

conda install -n root -c pscondaenvs pscondaenvs

Introduction of package management (pip) / virtual environment construction library (virtualenv)

Package management is introduced to install libraries, and virtual environment is introduced to isolate the Python version and libraries to be used for each project.

Since pip is installed as standard from Python 3.4, there is no need to install it separately at present. If you want to use old Python, install it with get_pip.py.

virtualenv can be installed with pip install virtualenv.

However, officially, it is recommended to use Pipenv which includes the function of pip / virtualenv. With Pipenv, like npm in Node.js, it is easy to write out dependent libraries at the same time as installation, and separate development / production installation libraries.

Development flow in Python

Python development is generally done by the following setup.

  1. Create a virtual environment for your project In Python, the libraries required to run the project are not installed globally, but are usually installed in individual virtual environments, and the tools for that are virtualenv, conda, etc.
  2. Install the required modules in the virtual environment After activating the virtual environment, use pip etc. to install the libraries required for the project. Write the installed library to a file so that others can install it. On the contrary, when using tools created by other people, install the dependent libraries written in the file.
  3. Create and execute a Python program

When rewritten as a command, it has the following form. Here are three ways to use the new pipenv, the traditional pip / virtualenv, and the conda.

When using pipenv

In pipenv, there is no need to explicitly instruct the creation of a virtual environment. If you install with pipenv install, it will create a virtual environment and install it there. However, it is created in a path that is not well understood by default, and it is difficult to receive the benefits of code storage in an integrated development environment as it is.

Therefore, it is better to set PIPENV_VENV_IN_PROJECT = 1 (or true) before use. By doing this, a virtual environment will be built in the current folder .venv.

# 1.Create a project folder
mkdir myproject 
cd myproject

# 2.Install the required libraries with pipenv

pipenv install xxxx

##Library used only for development(Library used for test etc.)To`-dev`Put on

pipenv install --dev xxxx

##Libraries installed with pipenv are automatically Pipfile.Written to lock. If you want to load and install it, just run pipenv install

pipenv install

# 3.Execute
pipenv run python xxx.py

##If you want to start a shell, use pipenv shell

pipenv shell

#When deleting the created environment,

pipenv --rm

When using pip / virtualenv

# 1.Create a project folder
mkdir myproject 
cd myproject

# 2.Creating a virtual environment venv is a folder name and the environment for the project is prepared here
virtualenv venv 

# 3.Activate the virtual environment and install the required modules with pip
#For Windows, venv/Scripts/activate.bat In addition, if you use the shell of Git, you can do it with source in the same way
#Note that if you do not activate the virtual environment, it will be installed globally, so deactivate it.

source venv/bin/activate

pip install xxxx

#List created with pip freeze(requirements.txt)When installing from
pip install -r requirements.txt

# 4.Execute
python xxx.py

When using conda

# 1.Create a virtual environment(something like virtualenv)
conda create -n my_env numpy scipy

##Display a list of virtual environments
conda info -e

# 2.Enable virtual environment
activate my_env # Windows
source activate my_env # Max/Linux

##Additional installation in virtual environment(When specifying the version conda install scipy=0.12.0 etc.)
conda install scikit-learn

##Install with pip for things that can't be obtained with conda(Support by putting pip in the virtual environment)
conda install pip
pip install Flask

##Update installed packages(conda itself is conda update conda)
conda update numpy

# 3.Export the environment built with conda/Read
conda env export > environment.yml
conda env create -f environment.yml

# 4.Disable virtual environment
deactivate # Windows
source deactivate # Max/Linux

For details, refer to here.

About management by Git

The above virtual environment folders (venv, etc.) and .pyc files should be excluded for version control. The .pyc file is a file for speeding up execution, and once executed, one file is created for each file. If you put this in version control, the file will be doubled, so you need to remove it (you can also add the -B option or set the environment variable PYTHONDONTWRITEBYTECODE to prevent it from being generated. Yes (reference)). For other files that should be ignored, refer to Python .gitignore.

Tips

In addition, depending on the library, there are some that cannot be entered obediently with pip install. This is noticeable on Windows. In many cases, it can be avoided by conda install, but if it still does not solve the problem, take the following actions.

  1. Find the appropriate package in Unofficial Windows Binaries for Python Extension Packages and install it with pip install <file_path> (aside) However, by using wheel, the dependent libraries can be included in the repository in a compiled state. This can prevent the situation where pip install cannot be performed in the environment of the other party when distributing and deploying. For details Document reference).
  2. If an exe file is provided, [do your best to install easy_install](http://qiita.com/icoxfog417/items/c91ba9555a247e9e8979#easy_install%E3%81%AE%E3%82%A4 % E3% 83% B3% E3% 82% B9% E3% 83% 88% E3% 83% BC% E3% 83% AB) Install.
  3. If you have no choice but to compile ... Install Visual Studio first. After that, set the environment variables by referring to the following.
  1. As a last resort, develop in a Linux environment using Windows Subsystem for Linux. For the setup method, refer to here. With this last resort, the "can't" situation on Windows has virtually disappeared.

Now that the Python development environment is in place, here are some points to keep in mind when developing with Python, which is the main subject.

File encoding must be declared (2 only)

Please note that Japanese characters will be garbled unless the following is added to the beginning of each file. As mentioned in here, it's a good idea to always put it at the beginning of the file.

# -*- coding: utf-8 -*-

In Python3, the default encoding is UTF-8, so this support is unnecessary (PEP 3120 --Using UTF-8 as the default source encoding. / dev / peps / pep-3120 /)).

As mentioned below, if it is assumed that both Python 2/3 will be supported, and if you want to receive the benefits of Python 3 (especially unicode unification), you should also import the following ([here](http: http:). //methane.hatenablog.jp/entry/2014/01/18/Python_2/3_%E4%B8%A1%E5%AF%BE%E5%BF%9C%E3%81%AE%E3%81%9F% E3% 82% 81% E3% 81% AB_% 60unicode_literals% 60_% E3% 82% 92% E4% BD% BF% E3% 81% 86% E3% 81% B9% E3% 81% 8D% E3% 81% 8B) Reference).

from __future__ import division, print_function, absolute_import, unicode_literals

There is a coding guide and you can check it in the integrated development environment

Python has an officially defined coding guide (PEP8) (original/ [Japanese translation](http: //) pep8-ja.readthedocs.io/ja/latest/)), many integrated development environments allow checking using this.

It is convenient because you can check the points such as too many line breaks and the presence of whitespace characters in detail, and you can correct the points that you overlooked. On the contrary, if you do not put it in from the beginning, it will be difficult to fix it later, so let's put it in when setting up the environment.

As the name implies, the package pep8, which checks for PEP8 compliance, is currently unmaintained and [pycodestyle](https: //). Please note that it is github.com/PyCQA/pycodestyle) (The background is that it is confusing whether the package name "pep8" is a convention or a tool, so Renamed Because it was suggested).

If you want to keep only logical checks (unnecessary imports, unused variables, etc.) together with pep8, pycodestyle that checks pep8 and pyflakes that perform logical checks are packed [flake8](http: //: flake8.pycqa.org/en/latest/) is recommended. Pylint can be checked in various ways, but there are many scenes that can be annoying, and you have to pay a reasonable cost to set it to an appropriate level.

Therefore, I would like to recommend the path of flake8 first, and then move to Pylint when it is necessary to improve the coding standard.

Unit test framework is installed as standard

Python comes standard with ʻunittest` (http://docs.python.jp/2/library/unittest.html), so you don't need to add a package for unit testing.

ʻUnittest2` looks like a new framework, but it's basically not necessary to introduce it because it is for using the unit test framework for the new version in the old version (as an aside, I gave this number) I'd like you to stop using the package name, such as urllib2).

Strings include regular strings and unicode strings (2 only)

In Python, the normal character string str and the Unicode character string ʻunicode` are separated.

str = "abc" # An ordinary string
uni_str = u"abc" # A Unicode string

Internally, there is not much problem with str as it is, but if external input / external output such as Web application is involved, it is better to unify with unicode (when using framework, which one You need to know if it's coming in or if you should pass the value). In Python3, it is unified to unicode. Also, in Python2, you can unify to ʻunicode by using from future import unicode_literals`.

The result of division does not become float type (2 only)

In Python2 system, the result of division between integers such as 1/3 does not become float type.

>>> 1/3
0
>>> 3/2
1

This is solved in Python3 (in the above example, it becomes a normal arithmetic operation result such as 0.333 ..., 1.5). If you want to make Python2 the same as Python3, you can solve it by performing the following import at the beginning.

from __future__ import division

In addition, there is also a sign // in division. At first glance, this seems to be an operator for making a quotient, but it is not. Strictly speaking, the operation by // is the "maximum integer value that does not exceed the calculation result". For example, if 3 is divided by 2, it will be 1.5, and the maximum integer that does not exceed this will be 1. This is as good as a quotient, but the problem is when the value is negative.

>>> -3 / 2
-2

The result changes just because the sign becomes negative. What's this? You might think, but if it's negative, the maximum integer that doesn't exceed -1.5 is -2, which is a specification, not a bug. And this specification is similar in Python3. Therefore, if you want to calculate the quotient safely, it is better to calculate so that the result is a float and truncate after the decimal point. For Python3, this simply truncates the result calculated by /.

In addition, there is a built-in function called divmod that calculates the quotient and the remainder at the same time, but be careful because the" quotient "in this function is the same as the operation result of//(as long as the document says" quotient " , I think this is a bug, but ...).

Rounding specifications are bank rounding (from 3)

The round process, which is rounding in Python, is bank rounding (also called rounding to nearest even numbers, JIS rounding, and ISO rounding). Specifically, when the number after the decimal point is "0.5", it is moved closer to an even number. This is a process that is performed because if 0.5 is always rounded up to a plus, the value of the total after rounding (rounded up) will be larger in the total before and after rounding = there will be a bias ( See Wikipedia's Rounding for details).

>>> round(3 / 2)
2
>>> round(1 / 2)
0

Since 1/2 = 0.5, I think it is 1, but this is a story of arithmetic rounding, and in the case of bank rounding, as mentioned above, it is rounded to" even number closest to 0.5 ", that is, 0. Note that ** Python2 is arithmetic rounding, so be careful **.

Other languages that use bank rounding include C # (see [here] for details [https://qiita.com/nekonenene/items/05b85048feb05a6bb9ee#%E4%B8%80%E8%A6%] See A7% E8% A1% A8)).

There is a new style class and an old style class (2 only)

In the well-introduced class declaration below, it is an old style class.

class MyClass():
    pass

What is different from the old style class? There are many things, but at least creating with the old style class now has no merit. In the old style class, the super that calls the parent class doesn't work, so I don't know what the inheritance is for.

Therefore, the class is declared as follows.

class MyClass(object):
    pass

It means inheriting ʻobject`. From Python3, it becomes a new style class by default old style class is deleted.

In addition, Python3 simplifies the calling process of the parent class. In Python2, it was a complicated calling method such as super (child class name, self) .parent_method (), but in Python3 it can be called normally with super (). Parent_method ().

No abstract class / interface

Inheritance is possible, but there is no mechanism to force implementation in lower classes. However, since Python 2.6, abc has been added as standard, and it is possible to implement a pseudo abstract class (abc is an abbreviation for abstract base class).

from abc import ABCMeta

class MyABC:
    __metaclass__ = ABCMeta
    
    def describe(self):
        print("I'm abc")
    
    @abstractmethod
    def must_implements(self):
        pass

In Python3, you can use metaclass when creating a class, so you can write it more simply.

from abc import ABCMeta

class MyABC(metaclass=ABCMeta):
    ...

You can also register a class that uses register under your control (subclass). However, since it simply "makes it look like that", tuple is not actually an inherited class of MyABC even in the following example, and the methods actually implemented in MyABC cannot be used.

MyABC.register(tuple)

assert issubclass(tuple, MyABC)
assert isinstance((), MyABC)

().describe()  # Attribute Error

Even though it is True in ʻis instance`, it seems to be confusing to get an Attribute Error in the method, so I can not imagine the usage scene very much. I think it's better to inherit it normally. Of course, a method that normally declares a class and is forced to implement can raise an exception in the parent class.

Multiple inheritance is possible

Python will be one of the few languages that supports multiple inheritance.

class MultiInheritance(Base1, Base2, Base3):
...

The solution is performed in order from the left, and in the above, if it is not in itself, the search is performed as Base1, then Base2, and so on. super is the leftmost class when called normally.

As mentioned above, Python doesn't have an interface, so you'll use multiple inheritance instead (or Module / Mix-in). I think it's best not to use multiple inheritance for any other purpose. However, since everyone looks like a class, it is better to decide the rule of the class name such as starting with ʻI` for the one used as an interface (or creating a class such as Interface / Module and inheriting it).

There are two constructors (what I think)

In Python, __new__ and __init__ are both constructors, aren't they? There are two functions that look like. Basically, use __init__. However, as you can see from the argument self, __init__ is "initialization process after the instance is created", not strictly a constructor. __new__ is the process of returning the instance for initialization with __init__. If you want to do it, you can return an instance other than your own class, but the merit is not so much. Is it used for singleton implementation?

Hidden attributes exist in class

Python instances have hidden attributes surrounded by two underscores (also in the class / function definition itself), like the __init __ above. These are used to store meta information and perform basic operations (such as behavior when setting / retrieving values for attributes). Details are detailed in Data Model, but the ones that are often used / useful are as follows.

Attribute name Contents
__class__ Class definition.__class__.__name__You can get the class name with
__dict__ All attributes(Including method)A dictionary version of
__doc__ Of classes and methodsdocstringCan be obtained. If you don't know how to use it, but it's a hassle to find the source code or API documentation, you can quickly see it.
Method name Contents
__getattr__ Called when attribute access is performed and the target attribute does not exist
__getattribute__ Always called when accessing attributes
__setattr__ Called when assigning to an attribute
__delattr__ Called when deleting an attribute(del obj.xxx)
__getstate__ Object serialization(Pickle)I do
__setstate__ Restore from serialized objects
__str__ Method for stringifying a class(So-called toString)
__repr__ Method to output instance notation(Notation of type and some members)

__Str__ is similar to __repr__, but __str__ is for humans to know the contents of variables (Readable), and __repr__ is for checking if the variable is of the intended type ( Unambiguous) (Reference). It is a good use to include shape in __repr__ in a matrix variable etc., and you can check whether the intended variable is received and processed. It is intentional to format the instance state with __str__ so that it can be read by humans when it is output to the log console.

There are many cases where you want to access with the attribute ʻobj.xxxinstead of the character string such as ʻobj ["xxx"], in which case the above __getattr__ etc. is valid. Below, Soundcloud-python implementation example (obj passed in __init__ is from Web API Obtained dictionary type object).

class Resource(object):
    """Object wrapper for resources.

    Provides an object interface to resources returned by the Soundcloud API.
    """
    def __init__(self, obj):
        self.obj = obj

    def __getstate__(self):
        return self.obj.items()

    def __setstate__(self, items):
        if not hasattr(self, 'obj'):
            self.obj = {}
        for key, val in items:
            self.obj[key] = val

    def __getattr__(self, name):
        if name in self.obj:
            return self.obj.get(name)
        raise AttributeError

    def fields(self):
        return self.obj

    def keys(self):
        return self.obj.keys()

It is a technique that can be used when you want to dynamically change the attribute according to the response of the other party, such as a WebAPI wrapper. For details on how to use it, see [here](https://www.inkling.com/read/learning-python-mark-lutz-4th/chapter-37/-getattr --- and --- getattribute--) detailed.

Attributes such as instance / class definitions can be extracted with the ʻinspect` module.

>>> import inspect
>>> inspect.getmembers(some_instance)

No Enum (2 only)

Standard installation from Python 3.4.1, but until then there is no Enum. If you want to use it, install and use enum with pip install enum34.

import enum


class Color(enum.Enum):
    Red = 10
    Blue = 20
    Yellow = 30

>>> Color.Red == Color.Red
True

>>> Color.Red == 10
False
#This is False because Enum is an Enum type object. There is also an IntEnum that makes this True

>>> Color.Red == Color(10)
True
#You can create the corresponding Enum by passing a value to the constructor

>>> Color.Red == Color["Red"]
True
#When creating from a name[]Specify the name with

>>> {Color.Red:"red", Color.Blue:"blue"}
{<Color.Blue: 20>: 'blue', <Color.Red: 10>: 'red'}
#Can also be used as a list key

If you want to define the character string of each item, you can use it together with __str__. This is useful when you do not want to disperse the definition when displaying labels.

class Color(enum.Enum):
    Red = 10
    Blue = 20
    Yellow = 30
    
    def __str__(self):
        if self.value == Color.Red.value:
            return "Red"
        elif self.value == Color.Blue.value:
            return "Blue"
        elif self.value == Color.Yellow.value:
            return "Blue"
>>> print(Color.Red)
Red

No Private or Protected

There is no, but it is customary to add __ or _ at the beginning of private ones. There is no concept equivalent to so-called Protected, such as wanting to show it only to inherited classes. So what's the difference between __ and _? The degree to which this is hidden from the outside changes.

class Test(object):
    def __init__(self):
        self.__a = 'a' # two underscores
        self._b = 'b' # one underscore

>>> t = Test()
>>> t._b
'b'

>>> t.__a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__a'
t.__a isn't found because it no longer exists due to namemangling

>>> t._Test__a
'a'

As mentioned above, if you have one underscore, you can access it as usual (it will warn you if you check it with PEP), but if you have two underscores, you can not access it unless you do _Test__a. It makes it a private form (usually invisible).


Reference
The meaning of a single- and a double-underscore before an object name in Python Difference between _, __ and xx in Python

There is no const / final

You can't define constants in Python. However, since the tuple described later is an immutable list, it is possible to create a pseudo constant by using this (I feel that const is fine if there is an immutable list ... ).

Here, in PEP8, constants should be connected with all capital letters and underscores, but there is no check for this.

The first argument of the method is reserved

class Test(object):
    def __init__():
        pass

    def get_num(self):
        return 1

    def add_num(self, num):
        return self.get_num() + num
    
    @classmethod
    def test_print(cls):
        print "test"

The get_num above clearly seems to take one argument, but it's effectively a method with no arguments. Then, the member functions in the same class are called using this implicit first argument self and cls so that they are self.get_num ().

Lists and tuples (+ variadic arguments)

In Python, there is an object called a tuple, which is roughly an "immutable list". These have different declaration methods.

v_list = [10, 20, 30] # list
v_tuple = (10, 20, 30) # tuple

v_list[1] = 11 # ok
v_tuple[1] = 11 # error! 'tuple' object does not support item assignment

Tuples can also be the key to dictionaries due to their characteristics. Lists and tuples are also deeply involved in functions / methods that handle variadic arguments.

def out_with_tuple(a,b,*args):
    # a,Arguments after b are combined into tuple
    print(a,b,args)

>>> out_with_tuple(1,2,3,4,5)
(1, 2, (3, 4, 5))

def out_with_dict(a,b,**args):
    print(a,b,args)

>>> out_with_dict(1,2,one=3,two=4,three=5)
(1, 2, {'three': 5, 'two': 4, 'one': 3})

It's easy to think of * as a pointer, but it represents an arbitrary number of arguments and can be grouped into tuples for * and dictionaries for ** (can be used together).

Then, if the caller uses *, **, the list / tuple value can be expanded and passed as an argument.

>>> def out(a,b):
...    print(a,b)

>>> out([1,2])  #If you pass the list normally, naturally NG
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: out() takes exactly 2 arguments (1 given)


>>> out(*[1,2])
(1,2)  # *Expands the elements in the list and out(1,2)Will be the same as calling

>>> out_with_dict(**{"a":1,"b":2})
(1, 2, {})  #Similar to the above**Expands the arguments passed in the dictionary

Default argument must be immutable

The value given as the default argument of the method or function must be immutable. That's usually the case, so there's no problem, but be aware that empty arrays are mutable.

>>> class ArrayDefault():
>>>    def __init__(self, array=[]):
>>>        self.array = array  #! mutable default value

>>> a = ArrayDefault()
>>> len(a.array)
0
>>> a.array += [1,2,3]
>>> a.array
[1,2,3]

>>> b = ArrayDefault()
>>> b.array
[1, 2, 3]  # !!!!!

For some reason, the value is pre-filled in the instance of b which has nothing to do with ʻa`. It looks completely complicated and bizarre, which is why the argument must be immutable. The scope of the default argument seems to be the same as that method / function, and if it is not immutable, it behaves like a global variable and behaves as described above.

Therefore, in the above case, it is necessary to change to the process of setting None as the default argument and setting [] if None. As with arrays, be careful in cases where references are set as initial values.

Default Parameter Values in Python

Cannot overload method

In Python, you cannot use overloads that have different arguments and are defined with the same name. Therefore, if you want to use overload, you need to use the default argument or determine the argument type internally to handle it by branching within one method. Also, class methods and member methods with the same name are not allowed.

However, by using singledispatch, conditional branching can be eliminated and an overloaded implementation can be realized (standard from Python 3.4). powered by).

Operator calculations can be implemented (operator overload)

In Python, it is possible to implement calculations with operators such as + and - (so-called operator overloading) (Reference). ).

class Point(object):
    def __init__(self, x, y):
        self.x = 0 if x is None else x
        self.y = 0 if y is None else y
    def __add__(self, other):
        x = self.x + other.x
        y = self.y + other.y
        return Point(x, y)
    def __str__(self):
        return "x:{0}, y:{1}".format(self.x, self.y)

>>> print(Point(1, 2))
x:1, y:2
>>> print(Point(1, 2) + Point(1, 2))
x:2, y:4

You can also implement logical operators such as == and >. However, it is quite difficult to define all operators without any gaps. If it is a numerical operation system, it is better to check if there is a suitable library rather than implementing it by yourself.

Can describe type definition (from 3)

Starting with Python3 (especially from Python3.5), you can write types for the return values of arguments and functions.

def greeting(name: str) -> str:
    return 'Hello ' + name

Starting with Python 3.6, variables can also have type information (PEP 526).

my_string: str
my_dict: Dict[str, int] = {}

This is called type annotation, and although it does not give an error at runtime, it can be checked in advance using this information. Tools for checking include mypy, which allows you to check type integrity before execution. See below for details.

Typed world starting with Python

In addition, there are some that have @ that looks the same as Java annotation, but this is not an annotation but a "decorator", and its behavior is completely different and this affects the execution of the function. As the name "decorate" implies, it functions as a "function that wraps a function".

import functools

def makebold(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        return "<b>" + func(*args, **kwargs) + "</b>"
    return wrapper

def makeitalic(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        return "<i>" + func(*args, **kwargs) + "</i>"
    return wrapper

@makebold
@makeitalic
def hello(your_name):
    return "hello {0}.".format(your_name)

>>> print hello("hoge") ## returns <b><i>hello hoge.</i></b>

Reference: How can I make a chain of function decorators in Python?

The above is the same as executing makebold (makeitalic (hello)) (your_name) (executed sequentially from the decorator closer to the function definition). If you want to check before executing the method (permission etc. Check Overrides, Etc.), or when you want to add processing before and after execution (measurement of execution time, etc.). In addition, functools.wrap is to prevent the information of the function from being replaced with the decorated function instead of the original function by decorating (here. 20090427 / 1240838573)).

It's pretty hard to get the decorator given to a method Therefore, for metaprogramming purposes (such as getting an annotated method and executing it), it is better to upgrade it to Python3 and use the annotation.

About namespaces and imports

In Python, namespaces are (automatically) cut for each file without declaring a namespace or package. The name of the namespace cut for each file is synonymous with the file name, so when calling TestClass defined in package / test_class.py, it is necessary to use from package.test_class import TestClass. There is.

Also, since it is cut in file units, an import declaration is required when referencing files in the same folder. Note that the folder is recognized as a package if there is a file called __init__.py (it does not have to be from Python3).

As with Java, if you want to import by package / class name (like from package import TestClass), you can handle it by writing the import statement of the file in __init__.py. This is because the from package part is read in __init__.py in the folder, so if there is an import statement here, it will be the same as importing the file.

Note that when importing a cross-referenced file (A refers to B and B refers to A), it becomes a deadlock and cannot be imported. To avoid this, it is necessary to devise such as importing in the necessary processing instead of the beginning of the file (Reference python)).

Any file can be executed as a script

ʻIf name == "main": can describe what happens when it is run as a script (when run with python xxx.py`) (see Top Level Script Environment (http: // docs) .python.jp/2/library/main.html)).

if __name__ == "__main__":
    print "Run Script"

It doesn't matter if this is the file that defines the class or the file that defines the function. Therefore, if you want to check the operation of the class you are defining for a moment, put the above if statement at the bottom of the file and write the process for checking the operation under it python xxx.py You can check it by setting . This is very convenient.

Processing can be described in an array (list comprehension notation)

In Python, operations in arrays are possible as follows.

>>> [ x for x in [1, 2, 3, 4, 5] if x > 3]
[4, 5]

>>> [ x*2 for x in [1, 2, 3, 4, 5]]
[2, 4, 6, 8, 10]

#It is also possible to use functions
>>>def calc_double(x):
>>>    return x*2

>>> [ calc_double(x) for x in [1, 2, 3, 4, 5]]
[2, 4, 6, 8, 10] 

It works the same as built-in functions such as map and filter, but in some cases it is easier to write with greater readability. From Python3, map and filter will return [iterator] instead of list itself [http://stackoverflow.com/questions/1303347/getting-a-map-to-return-a] -list-in-python-3-x), so if you want to handle it in list like Python2, use list comprehension notation, if you want to chain from iterator to subsequent processing, use map / filter etc. It is easy to support both versions if you keep it. Also, It seems that the execution speed is fast.

Starting with Python3.6, it is possible to handle asynchronous iterators with this list comprehension (PEP 530). ..

result = [i async for i in async_iter() if i % 2]
result = [await fun() for fun in async_funcs if await condition()]

Creating an anonymous function

In Python you can create anonymous functions by using lambda.

>>> list(map(lambda x: x * 2, range(5)))
[0, 2, 4, 6, 8]

In the above, map is used and the function lambda x: x * 2 is applied to each value of range (5). The function created by lambda can also be assigned to a variable, and the above is equivalent to the following.

>>> f = lambda x: x * 2
>>> list(map(f, range(5)))
[0, 2, 4, 6, 8]

Combined with the above list comprehension notation, the following processing is also applied.

>>> f = lambda a, b: a + b
>>> [f(*z) for z in zip([1, 2, 3], [4, 5, 6])]
[5, 7, 9]

zip is a convenient function that takes multiple arrays as arguments and puts them together by index, andzip ([1, 2, 3], [4, 5, 6])is[(1, 4), ( 2, 5), (3, 6)]. This is expanded to the argument of the function f using*and processed.

About the for statement

Python for statements are like for each and cannot be indexed by default. If you want to use index in a loop statement, do as follows.

for index, value in enumerate(list):
    print "index:" + index

If you just want to turn by index, you can also write as follows (since there is no such thing as list.length in Python, uselen (list)to get the length).

for index in range(len(list)):
    print "index:" + index

As a convenient property, you can set else in the Python for statement (although while may be used more often).

child = "Bob"
for c in ["Alice", "Tom", "Ann", "Cony"]:
    if c == child:
        break
else:
    print("{} is not here.".format(child))

The process defined by ʻelse is processed when break` is not executed. Therefore, it can be used to describe the processing when the detection cannot be performed in the loop.

About the if statement

Since Python does not have a switch statement, if-else is used instead. Well, you might think, but Python has indentation and if is pretty clean, so this isn't too much of a problem.

Also, for this reason, you may think that you cannot write a one-line if statement (so-called ternary operator) in Python, but in Python 2.5 or later you can write as follows ([PEP 308-] --Conditional Expressions](see http://legacy.python.org/dev/peps/pep-0308/).

>>> test = 1
>>> "test eq 1" if test == 1 else "test not eq 1"
'test eq 1'

There is a syntax for implementing asynchronous processing (from 3)

From Python3.5, asynchronous processing can be easily implemented using the syntax ʻasync / ʻawait (although it was possible to implement with ʻasyncio before that, as a grammar Implemented). When processing a certain continuous process (tasks` in the following) in multiple processes, it can be written as follows.

import asyncio
import random


tasks = asyncio.Queue()
for t in range(10):
    tasks.put_nowait(t)


async def execute(p):
    while not tasks.empty():
        t = await tasks.get()
        await asyncio.sleep(random.randint(0, 3))  # emulate the waiting time until task t finish
        print("Process{} done task {}".format(p, t))
    return True


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    execution = asyncio.wait([execute(process_no) for process_no in range(2)])
    loop.run_until_complete(execution)

The execution result is as follows (* Of course, the result will be different each time it is executed).

Process1 done task 0
Process0 done task 1
Process1 done task 2
Process0 done task 3
Process1 done task 4
Process0 done task 5
Process1 done task 6
Process0 done task 7
Process0 done task 9
Process1 done task 8

Please refer to the following article for details.

Asynchronous processing in Python: asyncio reverse lookup reference

From Python 3.6, it's now easier to create asynchronous iterators using yield ([PEP 525](https://docs.python.org/3.6/whatsnew/3.6.html#" whatsnew36-pep525)).

async def ticker(delay, to):
    """Yield numbers from 0 to *to* every *delay* seconds."""
    for i in range(to):
        yield i
        await asyncio.sleep(delay)

The created package can be published (PyPI)

In Python, there is a site called PyPI that hosts packages, and by publishing the package created here, it can be widely used by other people with pip install etc. You can get it (like Maven in Java, rubygems.org in Ruby, nuget in .NET).

As for this method, if you search normally, the old method will often get caught, so please refer to the following for the latest upload method.

Publish the library created in Python to PyPI

Other

See also below for anything other than those listed here. [python] 10 real pitfalls of Python that are too detailed to convey

Recommended Posts

Tips to look at before you start writing Python
Before writing Python code
Start to Selenium using python
3 Reasons Beginners to Start Python
~ Tips for beginners to Python ③ ~
Nice to meet you with python
Easy Python to learn while writing
Convert memo at once with Python 2to3
Tips to make Python here-documents easier to read
Data analysis in Python Summary of sources to look at first for beginners
python tips
Start python
Python Tips
Python tips
[Tips] Easy-to-read writing when connecting functions in Python
How to start Python (Flask) when EC2 starts
Writing logs to CSV file (Python, C language)
To you who develop Python under Windows & proxy
System trade starting with Python3: Bio-health stocks to look at in the new Corona