Stay Hungry,Stay Foolish!

python variable scope and object inheritance -- lookup chain

Python Variable Scope

https://data-flair.training/blogs/python-variable-scope/

变量作用域,指代特定的代码区域, 在此与区内变量可以被访问。

变量总是跟作用域绑定, 在其定义时候。

 

作用域分为四类:

L:  局部作用域, 例如函数内定义的变量

E:闭包作用域, 函数A内定义函数B, 函数B能看到的函数A中定义的变量,函数A的局部作用域对于函数B来说就是闭包。

G:全局作用域, python解析器启动,建立的环境,由定义的所有全局变量组成。

B:内置作用域, python提供的内置变量。

What is Python Variable Scope?

The scope of a variable in python is that part of the code where it is visible. Actually, to refer to it, you don’t need to use any prefixes then.

Types of Python Variable Scope

There are 4 types of Variable Scope in Python, let’s discuss them one by one:

 

 

 

https://python-tutorials.in/python-variables-declare-concatenate-global-local/

变量寻址过程,实际上是一个链式查找过程,

对于一个函数内部引用的变量,

先查找函数的local环境中是否定义

如果没有找到, 则查看其所属闭包中是否存在此变量,

如果没有找到,则查看全局环境中是否存在此变量,

如果没有找到, 则查看内置环境中是否存在此变量。

 

这是一个从底向上的一个查找过程:

local -》enclosed -》 global -》 built-in

 

Local & Global Variables

In Python when you want to use the same variable for rest of your program or module you declare it a global variable, while if you want to use the variable in a specific function or method, you use a local variable.

Let’s understand this difference between local and global variable with the below program.

  1. Variable “f” is global in scope and is assigned value 101 which is printed in output
  2. Variable f is again declared in function and assumes local scope. It is assigned value “I am learning Python.” which is printed out as an output. This variable is different from the global variable “f” define earlier
  3. Once the function call is over, the local variable f is destroyed. At line 12, when we again, print the value of “f” is it displays the value of global variable f=101

Variables in Python

 

 

Python Attribute lookup

https://www.demo2s.com/python/python-attribute-lookup.html#:~:text=To%20look%20up%20an%20attribute%2C%20Python%20does%20the,step%201%20then%20search%20the%20parent%20class%28es%29%20dictionaries

类属性 和 实例属性 的寻址方法:

从下面的解释,我们看到实例属性的寻址方法,也是一个链式结构, 从实例一直寻找到root对象object:

instance scope -> parent class scope -> parent parent class scope -> ... -> object scope

To look up an attribute, Python does the following for class attributes:

  1. Search the class Dictionary for an attribute
  2. If the attribute is not found in step 1 then search the parent class(es) dictionaries

For object attributes, Python first searches the instance dictionary and repeats the above steps, it thus performs these steps:

  1. Search the object/instance dictionary
  2. If the attribute was not found in step 1, then search the class Dictionary for an attribute
  3. If the attribute is not found in step 2, then search the parent class dictionaries

Thus given the following statements, different steps are taken each time:

student = Student('john')

# Class attribute dictionary
print('Student.__dict__:', Student.__dict__)
# Instance / Object dictionary
print('student.__dict__:', student.__dict__)

student = Student('john')

print('Student.count:', Student.count)  # class lookup
print('student.name:', student.name)  # instance lookup
print('student.count:', student.count)  # lookup finds class attribute

 

https://www.toptal.com/python/python-class-attributes-an-overly-thorough-guide

实例属性寻址图解。

 

 

 

 

变量寻址链 vs 属性寻址链

对于上面种对象的寻址方式学习,我们发现,其都是具有链式结构。

但是对于这链中每个节点都有哪些内容,python提供的工具给我们来审查。

 

链审查工具 - vars dir

https://www.geeksforgeeks.org/difference-between-dir-and-vars-in-python/

vars(node) 只返回当前节点属性

dir(node) 不仅仅返回当前节点属性,还返回node节点的所有父亲节点的属性。

 

dir() Function: 
This function displays more attributes than vars() function, as it is not limited to an instance. It displays the class attributes as well. It also displays the attributes of its ancestor classes.
vars() Function: 
This function displays the attribute of an instance in the form of a dictionary.

 

vars()dir()
Returns a dictionary of objects of single class where used Returns a dictionary of objects of single class where used and its base classes
It returns a dictionary corresponding to the current local symbol table when no argument is passed It returns the list of names in the current local scope when passed no argument
It returns a dictionary corresponding to the object’s symbol table if a module, class or class instance object as argument (or anything else that has a __dict__ attribute) is passed. It attempt to return a list of valid attributes for that object when passed an argument
As instances builtin types do not have __dict__ attribute, it returns an Error when used in a built-in type instance. It can be used with all built-in types without error

 

__dict__

其中每个节点的属性都被存储在 __dict__ 的魔法属性中。

https://www.tutorialspoint.com/What-does-built-in-class-attribute-dict-do-in-Python

类的__dict__,  包括 __init__ 以及类的内置属性。

实例的 __dict__, 仅仅包括 __init__ 中定义的 属于与self对象的属性。

class MyClass(object):
    class_var = 1

    def __init__(self, i_var):
        self.i_var = i_var

foo = MyClass(2)
bar = MyClass(3)

print MyClass.__dict__
print foo.__dict__
print bar.__dict__
{'__module__': '__main__', 'class_var': 1, '__dict__': <attribute '__dict__' of 'MyClass' objects>, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__doc__': None, '__init__': <function __init__ at 0x0000000004E55CF8>}
{'i_var': 2}
{'i_var': 3}

object.__dict__

官方的定义中显示, __dict__ 就是用于存贮对象的属性的。

https://docs.python.org/3/library/stdtypes.html#object.__dict__

object.__dict__

A dictionary or other mapping object used to store an object’s (writable) attributes.

 

 

https://arrayjson.com/__dict__-python/

 

module

模块也是一种特殊性的对象, 所有模块内定义的变量, 都被存储到 它的 __dict__ 属性中。

https://arrayjson.com/__dict__-python/

Module attributes are implicitly referred using the dictionary __dict__  i.e, whenever an attribute of module is called like module.x = 1 it is internally referenced as module.__dict__[‘x’] = 1

 

内置审查函数

dir

不带参数:

返回当前局部作用域的属性名。

 

带参数有三种使用场景:

(1)参数为模块, 列举出模块属性的所有名称。

(2)参数为类型或者类对象, 列举出自身属性名, 和 所有基类的属性名

(3)其它,这里应该是类实例, 列举出自身属性(实例属性),父类属性,以及父类的基类属性。

 

https://docs.python.org/3/library/functions.html?highlight=dir#dir

Without arguments, return the list of names in the current local scope. With an argument, attempt to return a list of valid attributes for that object.

If the object has a method named __dir__(), this method will be called and must return the list of attributes. This allows objects that implement a custom __getattr__() or __getattribute__() function to customize the way dir() reports their attributes.

If the object does not provide __dir__(), the function tries its best to gather information from the object’s __dict__ attribute, if defined, and from its type object. The resulting list is not necessarily complete and may be inaccurate when the object has a custom __getattr__().

The default dir() mechanism behaves differently with different types of objects, as it attempts to produce the most relevant, rather than complete, information:

  • If the object is a module object, the list contains the names of the module’s attributes.

  • If the object is a type or class object, the list contains the names of its attributes, and recursively of the attributes of its bases.

  • Otherwise, the list contains the object’s attributes’ names, the names of its class’s attributes, and recursively of the attributes of its class’s base classes.

The resulting list is sorted alphabetically. For example:

>>>

import struct
dir()   # show the names in the module namespace  
['__builtins__', '__name__', 'struct']
dir(struct)   # show the names in the struct module 
['Struct', '__all__', '__builtins__', '__cached__', '__doc__', '__file__',
 '__initializing__', '__loader__', '__name__', '__package__',
 '_clearcache', 'calcsize', 'error', 'pack', 'pack_into',
 'unpack', 'unpack_from']
class Shape:
    def __dir__(self):
        return ['area', 'perimeter', 'location']
s = Shape()
dir(s)
['area', 'location', 'perimeter']

https://www.geeksforgeeks.org/python-dir-function/

 

vars

https://docs.python.org/3/library/functions.html?highlight=dir#vars

于dir有两点不同:

(1)dir返回属性名称, vars不仅返回属性名,还返回属性值。

(2)vars只返回当前节点属性,即被存储在__dict__中的内容, dir不仅包括当前节点, 还递归向上遍历。

 

Return the __dict__ attribute for a module, class, instance, or any other object with a __dict__ attribute.

Objects such as modules and instances have an updateable __dict__ attribute; however, other objects may have write restrictions on their __dict__ attributes (for example, classes use a types.MappingProxyType to prevent direct dictionary updates).

Without an argument, vars() acts like locals(). Note, the locals dictionary is only useful for reads since updates to the locals dictionary are ignored.

A TypeError exception is raised if an object is specified but it doesn’t have a __dict__ attribute (for example, if its class defines the __slots__ attribute).

 

locals

https://docs.python.org/3/library/functions.html?highlight=dir#locals

返回局部符号表。

Update and return a dictionary representing the current local symbol table. Free variables are returned by locals() when it is called in function blocks, but not in class blocks. Note that at the module level, locals() and globals() are the same dictionary.

 

Free Variable

自由变量,对应 闭包概念。

这里所谓的自由,其实意味着, 变量没有在当前代码块定义, 即没有绑定到当前代码块, 对于当前代码块这个变量是自由的, 不被控制。

https://www.codesansar.com/python-programming/local-global-free-variables-example.htm#:~:text=Free%20Variable%20In%20Python%2C%20there%20exist%20another%20type,there%20then%20it%20is%20known%20as%20free%20variable.

In Python, there exist another type of variable known as Free Variable. If a variable is used in a code block but not defined there then it is known as free variable.

To understand the concept of free variable, lets consider following python program:

Free Variable Example


def outer():
    a = 20
  
    def inner():
        print('Value of a: %d' %(a))
    
    inner()

outer()

Output

Value of a: 20

Here variable a is defined in the scope of outer() function. If we look at inner() function, a is not defined there. But, function inner() is using variable a and hence variable a in inner() function is Free Variable.

Remember that variable a within outer() function is local.

 

globals

python中作用域(变量可见范围)是以模块作为最小单位的

所以模块调用globals,获得的是模块中定义的顶级变量, 可以理解为模块的全局环境。

https://docs.python.org/3/library/functions.html?highlight=dir#globals

Return the dictionary implementing the current module namespace. For code within functions, this is set when the function is defined and remains the same regardless of where the function is called.

 

module & package

https://docs.python.org/3/tutorial/modules.html#

模块就是一个文件, 包含python定义和声明。

 

A module is a file containing Python definitions and statements. The file name is the module name with the suffix .py appended. Within a module, the module’s name (as a string) is available as the value of the global variable __name__. For instance, use your favorite text editor to create a file called fibo.py in the current directory with the following contents:

# Fibonacci numbers module

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while a < n:
        print(a, end=' ')
        a, b = b, a+b
    print()

def fib2(n):   # return Fibonacci series up to n
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a+b
    return result

Now enter the Python interpreter and import this module with the following command:

>>>
>>> import fibo

This does not enter the names of the functions defined in fibo directly in the current symbol table; it only enters the module name fibo there. Using the module name you can access the functions:

>>>
>>> fibo.fib(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.fib2(100)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>> fibo.__name__
'fibo'

If you intend to use a function often you can assign it to a local name:

>>>
>>> fib = fibo.fib
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

 

package就是module命名空间的一种方法。

这是的模块的引用,突破单个文件名的限制, 可以采用层级目录的方式管理大型模块。

 

Packages are a way of structuring Python’s module namespace by using “dotted module names”. For example, the module name A.B designates a submodule named B in a package named A. Just like the use of modules saves the authors of different modules from having to worry about each other’s global variable names, the use of dotted module names saves the authors of multi-module packages like NumPy or Pillow from having to worry about each other’s module names.

Suppose you want to design a collection of modules (a “package”) for the uniform handling of sound files and sound data. There are many different sound file formats (usually recognized by their extension, for example: .wav, .aiff, .au), so you may need to create and maintain a growing collection of modules for the conversion between the various file formats. There are also many different operations you might want to perform on sound data (such as mixing, adding echo, applying an equalizer function, creating an artificial stereo effect), so in addition you will be writing a never-ending stream of modules to perform these operations. Here’s a possible structure for your package (expressed in terms of a hierarchical filesystem):

sound/                          Top-level package
      __init__.py               Initialize the sound package
      formats/                  Subpackage for file format conversions
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  Subpackage for sound effects
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  Subpackage for filters
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...

When importing the package, Python searches through the directories on sys.path looking for the package subdirectory.

The __init__.py files are required to make Python treat directories containing the file as packages. This prevents directories with a common name, such as string, unintentionally hiding valid modules that occur later on the module search path. In the simplest case, __init__.py can just be an empty file, but it can also execute initialization code for the package or set the __all__ variable, described later.

Users of the package can import individual modules from the package, for example:

import sound.effects.echo

This loads the submodule sound.effects.echo. It must be referenced with its full name.

sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)

 

posted @ 2022-05-12 11:25  lightsong  阅读(52)  评论(0编辑  收藏  举报
Life Is Short, We Need Ship To Travel