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.
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.
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.
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.
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.
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`).
pyenv install x.x.x
. Then set the Python to use with pyenv global x.x.x
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.
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 to
cmd 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
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.
Python development is generally done by the following setup.
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.
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
# 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
# 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.
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.
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).gfortran
is necessary anyway, so it may be better to install it obediently considering the maintenance of other environments.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.
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
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.
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).
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`.
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 ...).
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)).
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 ()
.
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.
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).
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?
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)
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
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
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.
self
for regular member methods and cls
for class methods (although the argument name can be anything, by convention self
and cls
are used. There is).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 ()
.
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
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
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).
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.
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.
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.
'module' object has no attribute'xxxx'
.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)).
ʻ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.
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()]
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.
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.
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'
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)
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
See also below for anything other than those listed here. [python] 10 real pitfalls of Python that are too detailed to convey
Recommended Posts