官术网_书友最值得收藏!

Writing pure functions

A function with no side effects fits the pure mathematical abstraction of a function: there are no global changes to variables. If we avoid the global statement, we will almost meet this threshold. To be pure, a function should also avoid changing the state mutable objects.

Here's an example of a pure function:

def m(n: int) -> int:
return 2**n-1

This result depends only on the parameter, n. There are no changes to global variables and the function doesn't update any mutable data structures.

Any references to values in the Python global namespace (using a free variable) is something we can rework into a proper parameter. In most cases, it's quite easy. Here is an example that depends on a free variable:

def some_function(a: float, b: float, t: float) -> float:
    return a+b*t+global_adjustment

We can refactor this function to turn the global_adjustment variable into a proper parameter. We would need to change each reference to this function, which may have a large ripple effect through a complex application. A function with global references will include free variables in the body of a function.

There are many internal Python objects that are stateful. Instances of the file class and other file-like objects, are examples of stateful objects in common use. We observe that some of the commonly used stateful objects in Python generally behave as context managers. In a few cases, stateful objects don't completely implement the context manager interface; in these cases, there's often a close() method. We can use the contextlib.closing() function to provide these objects with the proper context manager interface.

We can't easily eliminate all stateful Python objects. Therefore, we must strike a balance between managing state while still exploiting the strengths of functional design. Toward this end, we should always use the with statement to encapsulate stateful file objects into a well-defined scope.

Always use file objects in a with context.

We should always avoid global file objects, global database connections, and the associated stateful object issues. The global file object is a common pattern for handling open files. We may have a function as shown in the following command snippet:

def open(iname: str, oname: str):
    global ifile, ofile
    ifile= open(iname, "r")
    ofile= open(oname, "w")  

Given this context, numerous other functions can use the ifile and ofile variables, hoping they properly refer to the global files, which are left open for the application to use.

This is not a very functional design, and we need to avoid it. The files should be proper parameters to functions, and the open files should be nested in a with statement to assure that their stateful behavior is handled properly. This is an important rewrite to change these variables from globals to formal parameters: it makes the file operations more visible.

This design pattern also applies to databases. A database connection object should generally be provided as a formal argument to an application's functions. This is contrary to the way some popular web frameworks work: some frameworks rely on a global database connection in an effort to make the database a transparent feature of the application. This transparency obscures a dependency between a web operation and the database; it can make unit testing more complex than necessary. Additionally, a multithreaded web server may not benefit from sharing a single database connection: a connection pool is often better. This suggests that there are some benefits of a hybrid approach that uses functional design with a few isolated stateful features.

主站蜘蛛池模板: 五指山市| 泾川县| 凉城县| 中宁县| 都兰县| 滦南县| 盐山县| 沾益县| 都安| 巴中市| 大丰市| 武穴市| 龙江县| 柞水县| 盐津县| 修武县| 杨浦区| 阿合奇县| 德格县| 吴桥县| 文登市| 宜州市| 睢宁县| 铜梁县| 太原市| 临武县| 绥江县| 林西县| 五常市| 巫溪县| 安龙县| 师宗县| 柯坪县| 安平县| 同心县| 水富县| 武邑县| 库车县| 雅安市| 汝南县| 福鼎市|