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.
- Variable “f” is global in scope and is assigned value 101 which is printed in output
- 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
- 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
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:
- Search the class Dictionary for an attribute
- 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:
- Search the object/instance dictionary
- If the attribute was not found in step 1, then search the class Dictionary for an attribute
- 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 waydir()
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 atypes.MappingProxyType
to prevent direct dictionary updates).Without an argument,
vars()
acts likelocals()
. 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()
andglobals()
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: 20Here variable a is defined in the scope of
outer()
function. If we look atinner()
function, a is not defined there. But, functioninner()
is using variable a and hence variable a ininner()
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 calledfibo.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 namefibo
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 namedB
in a package namedA
. 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 asstring
, 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)