Возможности python 3, достойные того, чтобы ими пользовались

Создание Класса

Создание класса в Пайтоне – это очень просто. Вот простой пример:


Python

# Python 2.x syntax

class Vehicle(object): «»»docstring»»» def __init__(self): «»»Constructor»»» pass

1 2 3 4 5 6 7 8

# Python 2.x syntax  

classVehicle(object)

«»»docstring»»»

def__init__(self)

«»»Constructor»»»

pass

Этот класс не делает ничего конкретного, тем не менее, это очень хороший инструмент для изучения. Например, чтобы создать класс, мы используем ключевое слово class, за которым следует наименование класса. В Пайтоне, конвенция указывает на то, что наименование класса должно начинаться с заглавной буквы. Далее нам нужно открыть круглые скобки, за которыми следует слово object и закрытые скобки. «object» — то, на чем основан класс, или наследуется от него. Это называется базовым классом или родительским классом. Большая часть классов в Пайтоне основаны на объекте. У классов есть особый метод, под названием __init__.

Этот метод вызывается всякий раз, когда вы создаете (или создаете экземпляр) объект на основе этого класса. Метод __init__ вызывается единожды, и не может быть вызван снова внутри программы. Другое определение метода __init__ — это конструктор, кстати, этот термин редко встречается в Пайтоне. Вы можете подумать, почему я называю это методом, а не функцией? Функция меняет свое имя на «method», когда она находится внутри класса

Обратите внимание на то, что каждый метод должен иметь как минимум один аргумент, что в случае с обычной функцией уже не вяжется. В Python 3 нам не нужно прямо указывать, что мы наследуем у объекта

Вместо этого, мы можем написать это следующим образом:

Python

# Python 3.x syntax

class Vehicle: «»»docstring»»»

def __init__(self): «»»Constructor»»» pass

1 2 3 4 5 6 7 8

# Python 3.x syntax  

classVehicle

«»»docstring»»»

def__init__(self)

«»»Constructor»»»

pass

Обратите внимание на то, что единственная разница в том, что круглые скобки нам больше не нужны, когда мы основываем наш класс на объекте. Давайте немного расширим наше определение класса и дадим ему некоторые атрибуты и методы

Python

class Vehicle(object): «»»docstring»»»

def __init__(self, color, doors, tires): «»»Constructor»»» self.color = color self.doors = doors self.tires = tires def brake(self): «»» Stop the car «»» return «Braking» def drive(self): «»» Drive the car «»» return «I’m driving!»

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

classVehicle(object)

«»»docstring»»»

def__init__(self,color,doors,tires)

«»»Constructor»»»

self.color=color

self.doors=doors

self.tires=tires

defbrake(self)

«»»

        Stop the car         «»»

return»Braking»

defdrive(self)

«»»

        Drive the car         «»»

return»I’m driving!»

В данном примере мы добавили три атрибута и два метода. Эти три атрибута являются:

Python

self.color = color self.doors = doors self.tires = tires

1 2 3

self.color=color

self.doors=doors

self.tires=tires

Атрибуты описывают автомобиль. У него есть цвет, определенное количество дверей и колес. Также у него есть два метода. Метод описывает, что делает класс. В нашем случае, автомобиль может двигаться и останавливаться. Вы могли заметить, что все методы, включая первый, имеют интересный аргумент, под названием self. Давайте рассмотрим его внимательнее.

Source File Encoding

Code in the core Python distribution should always use UTF-8 (or ASCII in Python 2).

Files using ASCII (in Python 2) or UTF-8 (in Python 3) should not have an encoding declaration.

In the standard library, non-default encodings should be used only for test purposes or when a comment or docstring needs to mention an author name that contains non-ASCII characters; otherwise, using \x, \u, \U, or \N escapes is the preferred way to include non-ASCII data in string literals.

For Python 3.0 and beyond, the following policy is prescribed for the standard library (see PEP 3131): All identifiers in the Python standard library MUST use ASCII-only identifiers, and SHOULD use English words wherever feasible (in many cases, abbreviations and technical terms are used which aren’t English). In addition, string literals and comments must also be in ASCII. The only exceptions are (a) test cases testing the non-ASCII features, and (b) names of authors. Authors whose names are not based on the Latin alphabet (latin-1, ISO/IEC 8859-1 character set) MUST provide a transliteration of their names in this character set.

А теперь вернёмся к тем особенностям, которые были изложены в начале статьи

1. Использование генератора дважды

В данном примере, список будет содержать элементы только в первом случае, потому что генераторное выражение — это итератор, а итераторы, как мы уже знаем — сущности одноразовые. И при повторном использовании не будут отдавать никаких элементов.

2. Проверка вхождения элемента в генератор

А теперь дважды проверим, входит ли элемент в последовательность:

В данном примере, элемент будет входить в последовательность только 1 раз, по причине того, что проверка на вхождение проверяется путем перебора всех элементов последовательности последовательно, и как только элемент обнаружен, поиск прекращается. Для наглядности приведу пример:

Как мы видим, при создании списка из генераторного выражения, в нём оказываются все элементы, после искомого. При повторном же создании, вполне ожидаемо, список оказывается пуст.

3. Распаковка словаря

При использовании в цикле , словарь будет отдавать ключи:

Так как распаковка опирается на тот же протокол итератора, то и в переменных оказываются именно ключи:

Отличия цикла for в Python от других языков


Стоит отдельно остановиться на том, что цикл , в Python, устроен несколько иначе, чем в большинстве других языков. Он больше похож на , или же .

Если же, мы перепишем цикл с помощью цикла , используя индексы, то работать такой подход будет только с последовательностями:

А с итерируемыми объектами, последовательностями не являющимися, не будет:

Если же вам нужен , то следует использовать встроенную функцию :

Цикл использует итераторы

Как мы могли убедиться, цикл не использует индексы. Вместо этого он использует так называемые итераторы.

Итераторы — это такие штуки, которые, очевидно, можно итерировать 🙂 Получить итератор мы можем из любого итерируемого объекта.

Для этого нужно передать итерируемый объект во встроенную функцию :

После того, как мы получили итератор, мы можем передать его встроенной функции .

При каждом новом вызове, функция отдаёт один элемент. Если же в итераторе элементов больше не осталось, то функция породит исключение .

По-сути, это единственное, что мы может сделать с итератором: передать его функции . Как только итератор становится пустым и порождается исключение , он становится совершенно бесполезным.

Python __name__: Code Example

As specified above, when we execute a code file, for that code snippet, the value of variable becomes __main__ as the code is being executed directly, without being imported into any other file.

For example: Here we have a code file Script1.py,

When we run python Script1.py then:

This function is in Script1. Called from Script1.

Now, let’s create another python script file with name Script2.py and import the script Script1.py in it and try to call the function defined in the script Script1.

Here’s the code for Script2.py:

Now we run python Script2.py then:

Script1 is imported in some other file. This function is in Script1. Called from Script2.

When the statement is executed for Script1, inside the Script2, during that the variable had the value Script1(name of the module), but as the execution started with the script Script2, hence the variable for it will have the value __main__.

: Printing it’s Value

To understand it better, let’s print value of variable at every execution step.

Here is the code for the python script Script1.py:

That’s it, we won’t include anything else in the script. And here is the code for the script Script2.py:

Here is a live example:

NOTE: In the live example the scripts are main.py and Script1.py, the change in name of the scripts will not affect the functionality.

Most of the programming languages use the main method or function as the starting point of execution in any program. But what about Python? Generally, the execution of a python program(script) starts from the very first line that is at the indentation level 0 of that program. However, when a python program is executed, before its execution a variable is created. This variable can be used as an alternate for the main method in python.

  • ← Prev
  • Next →

Prescriptive: Naming Conventions

Never use the characters ‘l’ (lowercase letter el), ‘O’ (uppercase letter oh), or ‘I’ (uppercase letter eye) as single character variable names.

In some fonts, these characters are indistinguishable from the numerals one and zero. When tempted to use ‘l’, use ‘L’ instead.

Identifiers used in the standard library must be ASCII compatible as described in the

of PEP 3131.

Modules should have short, all-lowercase names. Underscores can be used in the module name if it improves readability. Python packages should also have short, all-lowercase names, although the use of underscores is discouraged.

When an extension module written in C or C++ has an accompanying Python module that provides a higher level (e.g. more object oriented) interface, the C/C++ module has a leading underscore (e.g. _socket).

Class names should normally use the CapWords convention.

The naming convention for functions may be used instead in cases where the interface is documented and used primarily as a callable.

Note that there is a separate convention for builtin names: most builtin names are single words (or two words run together), with the CapWords convention used only for exception names and builtin constants.

Names of type variables introduced in PEP 484 should normally use CapWords preferring short names: T, AnyStr, Num. It is recommended to add suffixes _co or _contra to the variables used to declare covariant or contravariant behavior correspondingly:

from typing import TypeVar

VT_co = TypeVar('VT_co', covariant=True)
KT_contra = TypeVar('KT_contra', contravariant=True)

Because exceptions should be classes, the class naming convention applies here. However, you should use the suffix «Error» on your exception names (if the exception actually is an error).

(Let’s hope that these variables are meant for use inside one module only.) The conventions are about the same as those for functions.

Modules that are designed for use via from M import * should use the __all__ mechanism to prevent exporting globals, or use the older convention of prefixing such globals with an underscore (which you might want to do to indicate these globals are «module non-public»).

Function names should be lowercase, with words separated by underscores as necessary to improve readability.

Variable names follow the same convention as function names.

mixedCase is allowed only in contexts where that’s already the prevailing style (e.g. threading.py), to retain backwards compatibility.

Always use self for the first argument to instance methods.

Always use cls for the first argument to class methods.

If a function argument’s name clashes with a reserved keyword, it is generally better to append a single trailing underscore rather than use an abbreviation or spelling corruption. Thus class_ is better than clss. (Perhaps better is to avoid such clashes by using a synonym.)

Use the function naming rules: lowercase with words separated by underscores as necessary to improve readability.

Use one leading underscore only for non-public methods and instance variables.

To avoid name clashes with subclasses, use two leading underscores to invoke Python’s name mangling rules.

Python mangles these names with the class name: if class Foo has an attribute named __a, it cannot be accessed by Foo.__a. (An insistent user could still gain access by calling Foo._Foo__a.) Generally, double leading underscores should be used only to avoid name conflicts with attributes in classes designed to be subclassed.

Note: there is some controversy about the use of __names (see below).

Constants are usually defined on a module level and written in all capital letters with underscores separating words. Examples include MAX_OVERFLOW and TOTAL.

namedtuple


is one of the easiest ways to clean up your code and make it more readable. It self-documents what is happening in the tuple. Namedtuples instances are just as memory efficient as regular tuples as they do not have per-instance dictionaries, making them faster than dictionaries.

Without naming each element in the tuple, it would read like this:

It is so much harder to understand what is going on in the first example. With a namedtuple, each field has a name. And you access it by name rather than position or index. Instead of , we can call it p.saturation. It’s easier to understand. And it looks cleaner.

Creating an instance of the namedtuple is easier than creating a dictionary.

Descriptive: Naming Styles

There are a lot of different naming styles. It helps to be able to recognize what naming style is being used, independently from what they are used for.

The following naming styles are commonly distinguished:

  • b (single lowercase letter)

  • B (single uppercase letter)

  • lowercase

  • lower_case_with_underscores

  • UPPERCASE

  • UPPER_CASE_WITH_UNDERSCORES

  • CapitalizedWords (or CapWords, or CamelCase — so named because of the bumpy look of its letters ). This is also sometimes known as StudlyCaps.

    Note: When using acronyms in CapWords, capitalize all the letters of the acronym. Thus HTTPServerError is better than HttpServerError.

  • mixedCase (differs from CapitalizedWords by initial lowercase character!)

  • Capitalized_Words_With_Underscores (ugly!)

There’s also the style of using a short unique prefix to group related names together. This is not used much in Python, but it is mentioned for completeness. For example, the os.stat() function returns a tuple whose items traditionally have names like st_mode, st_size, st_mtime and so on. (This is done to emphasize the correspondence with the fields of the POSIX system call struct, which helps programmers familiar with that.)

The X11 library uses a leading X for all its public functions. In Python, this style is generally deemed unnecessary because attribute and method names are prefixed with an object, and function names are prefixed with a module name.

In addition, the following special forms using leading or trailing underscores are recognized (these can generally be combined with any case convention):

Немного об импортах в питоне

12 ноября 2017 г.

Хотелось бы рассказать об одном моменте, связанном с системой импортов в питоне. Неподготовленному человеку может иногда показаться, что происходят нелогичные вещи, несоответствующие его ожиданиям. Так было со мной, когда я впервые столкнулся с данной проблемой.

Допустим есть такой проект:

project
|   main.py
|   test1.py
|   test2.py
|   config.py

main.py:

 1 import config as conf
 2 import test1
 3 import test2
 4 
 5 print('    in main')
 6 print(conf.test_var)
 7 test1.test1()
 8 print('    again in main')
 9 print(conf.test_var)
10 test2.test2()

test1.py:

1 import config as conf
2 
3 
4 def test1():
5     print('    in test1, executing test1()')
6     conf.test_var = 'test1'

test2.py:

1 import config as conf
2 
3 
4 def test2():
5     print('    in test2, executing test2()')
6     print(conf.test_var)

config.py:

1 test_var = 'initial_value'

Что будет если выполнить main.py? Сначала будет выведено начальное значение переменной. Затем будет вызвана функция test1, которая поменяет ее значение, будет выведено новое значение, но что будет потом в функции test2? Будет ли загружена заново переменная test_var? python main.py выведет следующее:

    in main
initial_value
    in test1, executing test1()
    again in main
test1
    in test2, executing test2()
test1

Можно было подумать (так было со мной), что последняя строчка будет другой — что там тоже должна быть выведена строка «initial_value», поскольку в модуле test2 config вроде бы заново импортируется, но python кэширует импорты, поэтому значение переменной не обновляется, а остается такой же как и в функции test1.

test1.py:

1 import config as conf
2 
3 
4 def test1():
5     print('    in test1, executing test1()')
6     print(id(conf.test_var))
7     conf.test_var = 'test1'
8     print(id(conf.test_var))

test2.py:

1 import config as conf
2 
3 
4 def test2():
5     print('    in test2, executing test2()')
6     print(id(conf.test_var))
7     print(conf.test_var)

python main.py:

    in main
initial_value
    in test1, executing test1()
140355198581312
140355198588464
    again in main
test1
    in test2, executing test2()
140355198588464
test1

Во-первых, при присваивании нового значения переменной test_var в функции test1 создается новая переменная, во-вторых, после изменения в функции test1 та же самая переменная test_var задействована в функции test2. Впрочем, такое поведение можно изменить, если принудительно перезагрузить config, test2.py:

 1 # python2
 2 import config as conf
 3 
 4 
 5 def test2():
 6     print('    in test2, executing test2()')
 7     print(id(conf.test_var))
 8     reload(conf)
 9     print(id(conf.test_var))
10     print(conf.test_var)

Если вы используете python3, то используйте следующий код для импорта reload, потому что она была перемещена:

1 import importlib
2 importlib.reload(module)
3 ...

python main.py:

    in main
initial_value
    in test1, executing test1()
140009528056384
140009528063536
    again in main
test1
    in test2, executing test2()
140009528063536
140009528056384
initial_value

Теперь видно, что config был перезагружен в функции test2.py, и теперь в ней после перезагрузки config’a используется изначальное значение переменной test_var.

Вывод

Для опытных разработчиков этот пост не представляет какой-либо ценности, но если вы новичок в питоне, то возможно вам было полезно узнать, что питон кэширует импорты, но это можно обойти, используя функцию reload.

Если вам понравился пост, можете поделиться им в соцсетях:

Usage

Retrieving the variable names from inside a function call/class instantiation

  • From insdie a function call

    from varname import varname
    def function():
        return varname()
    
    func = function()
    # func == 'func'
    
  • calls being buried deeply

    def function():
        # I know that at which stack this will be called
        return varname(caller=3)
    
    def function1():
        return function()
    
    def function2():
        return function1()
    
    func = function2()
    # func == 'func'
    
  • Retrieving instance name of a class

    class Klass
        def __init__(self):
            self.id = varname()
    
        def copy(self):
            # also able to fetch inside a member call
            return varname()
    
    k = Klass()
    # k.id == 'k'
    
    k2 = k.copy()
    # k2 == 'k2'
    
  • Some unusual use

    func = function()]
    # func == 
    
    func = function(), function()]
    # func == 
    
    func = function(), function()
    # func = ('func', 'func')
    
    func = func1 = function()
    # func == func1 == 'func'
    # a warning will be printed
    # since you may not want func1 to be 'func'
    
    x = func(y = func())
    # x == 'x'
    
    # get part of the name
    func_abc = function()
    # func_abc == 'abc'
    
    # function alias supported now
    function2 = function
    func = function2()
    # func == 'func'
    
    a = lambda 
    a.b = function()
    # a.b == 'b'
    
    # Since v0.1.3
    # We can ask varname to raise exceptions
    # if it fails to detect the variable name
    def get_name(raise_exc):
        return varname(raise_exc=raise_exc)
    
    a = {}
    a'b' = get_name(True) # VarnameRetrievingError
    a'b' = get_name(False) # None
    

Value wrapper

from varname import Wrapper

foo = Wrapper(True)
# foo.name == 'foo'
# foo.value == True
bar = Wrapper(False)
# bar.name == 'bar'
# bar.value == False

def values_to_dict(*args):
    return {val.name val.value for val in args}

mydict = values_to_dict(foo, bar)
# {'foo': True, 'bar': False}

Getting variable names directly

from varname import varname, nameof

a = 1
aname = nameof(a)
# aname == 'a

b = 2
aname, bname = nameof(a, b)
# aname == 'a', bname == 'b'

def func():
    return varname() + '_suffix'

f = func()
# f == 'f_suffix'
fname = nameof(f)
# fname == 'f'

Detecting next immediate attribute name

from varname import will
class AwesomeClass
    def __init__(self):
        self.will = None

    def permit(self):
        self.will = will(raise_exc=False)
        if self.will == 'do'
            # let self handle do
            return self
        raise AttributeError('Should do something with AwesomeClass object')

    def do(self):
        if self.will != 'do'
            raise AttributeError("You don't have permission to do")
        return 'I am doing!'

awesome = AwesomeClass()
awesome.do() # AttributeError: You don't have permission to do
awesome.permit() # AttributeError: Should do something with AwesomeClass object
awesome.permit().do() == 'I am doing!'

Shortcut for

# instead of
from collections import namedtuple
Name = namedtuple('Name', 'first', 'last'])

# we can do:
from varname import namedtuple
Name = namedtuple()

Injecting

from varname import inject

class MyList(list):
    pass

a = inject(MyList())
b = inject(MyList())

a.__varname__ == 'a'
b.__varname__ == 'b'

a == b

# other methods not affected
a.append(1)
b.append(1)
a == b

Строки

Строки в Python обособляются кавычками двойными «»» или одинарными «’». Внутри двойных ковычек могут присутствовать одинарные или наоборот. К примеру строка «Он сказал ‘привет’!» будет выведена на экран как «Он сказал ‘привет’!». Если нужно использовать строку из несколько строчек, то эту строку надо начинать и заканчивать тремя двойными кавычками «»»»». Вы можете подставить в шаблон строки элементы из кортежа или словаря. Знак процента «%» между строкой и кортежем, заменяет в строке символы «%s» на элемент кортежа. Словари позволяют вставлять в строку элемент под заданным индексом. Для этого надо использовать в строке конструкцию «%(индекс)s». В этом случае вместо «%(индекс)s» будет подставлено значение словаря под заданным индексом.

‘__main__’とは

上述のように、別のファイルからインポートされるとにはモジュール名が格納される。

一方、ファイルをコマンドラインからスクリプトとして実行するとにはという文字列が格納される。

__main__ — トップレベルのスクリプト環境 — Python 3.7.2 ドキュメント

例としてというモジュール()とそれをインポートして使うを作成する。

def func():
    print('    This is func() in test_module.py')
    print('    __name__ is', __name__)

if __name__ == '__main__'
    print("Start if __name__ == '__main__'")
    print('call func()')
    func()

source:

import test_module

print('This is test_main.py')
print('test_module.__name__ is', test_module.__name__)

print('---')
print('call test_module.func()')

test_module.func()

source:

をコマンドラインから(または)コマンドで実行すると以下のような結果となる。

python3 test_main.py
# This is test_main.py
# test_module.__name__ is test_module
# ---
# call test_module.func()
#     This is func() in test_module.py
#     __name__ is test_module

source:

の例と同様に、インポートされたモジュールのにはモジュール名が格納されている。

一方、自体をコマンドラインから実行すると以下のような結果となる。

python3 test_module.py
# Start if __name__ == '__main__'
# call func()
#     This is func() in test_module.py
#     __name__ is __main__

source:

にはという文字列が格納され、以降の処理が実行されていることが分かる。

このように、他のファイルからインポートされた場合はにが格納され、コマンドラインから(または)コマンドで実行された場合はにという文字列が格納される。

なお、コマンドにオプションをつけてモジュールとして実行する場合やインタラクティブモードでもにはという文字列が格納される。

python3 -m test_module
# Start if __name__ == '__main__'
# call func()
#     This is func() in test_module.py
#     __name__ is __main__

source:

Реализация цикла for с помощью функции и цикла while

Используя полученные знания, мы можем написать цикл , не пользуясь самим циклом . 🙂

Чтобы сделать это, нам нужно:

  1. Получить итератор из итерируемого объекта.
  2. Вызвать функцию .
  3. Выполнить ‘тело цикла’.
  4. Закончить цикл, когда будет получено исключение .

Стоит заметить, что здесь мы использовали конструкцию . Многие о ней не знают. Она позволяет выполнять код, если исключения не возникло, и код был выполнен успешно.

Теперь мы знакомы с протоколом итератора. А, говоря простым языком — с тем, как работает итерация в Python. Функции и этот протокол формализуют. Механизм везде один и тот же. Будь то пресловутый цикл или генераторное выражение. Даже распаковка и «звёздочка» используют протокол итератора:

В случае, если мы передаём в итератор, то получаем тот же самый итератор

Подытожим.

Итерируемый объект — это что-то, что можно итерировать.Итератор — это сущность порождаемая функцией , с помощью которой происходит итерирование итерируемого объекта.

Итератор не имеет индексов и может быть использован только один раз.

Variable Annotations

PEP 526 introduced variable annotations. The style recommendations for them are similar to those on function annotations described above:

  • Annotations for module level variables, class and instance variables, and local variables should have a single space after the colon.

  • There should be no space before the colon.

  • If an assignment has a right hand side, then the equality sign should have exactly one space on both sides:

    # Correct:
    
    code: int
    
    class Point:
        coords: Tuple
        label: str = '<unknown>'
    
    # Wrong:
    
    code:int  # No space after colon
    code : int  # Space before colon
    
    class Test:
        result: int=0  # No spaces around equality sign
    
  • Although the PEP 526 is accepted for Python 3.6, the variable annotation syntax is the preferred syntax for stub files on all versions of Python (see PEP 484 for details).

Footnotes

Hanging indentation is a type-setting style where all the lines in a paragraph are indented except the first line. In the context of Python, the term is used to describe a style where the opening parenthesis of a parenthesized statement is the last non-whitespace character of the line, with subsequent lines being indented until the closing parenthesis.

С этим читают