`
huangyiiiiii
  • 浏览: 118581 次
  • 性别: Icon_minigender_1
最近访客 更多访客>>
社区版块
存档分类
最新评论

do it runtime

阅读更多

第一次从静态语言到动态语言的人肯定在思维上需要一个比较大的跳跃,主要是许多静态语言中编译器干的事情到动态语言中后,或是不存在了,或是需要在运行时进行。
典型的例子包括:类型检查,重载,访问控制,常量。(暂时就想到这几个,还有一些代码生成的技术像define、template我们就不提了)

1、类型检查

对于类型检查我想大部分人倾向于可选地进行,毕竟动态语言不是静态语言,duck typing还是给动态语言带来了巨大的灵活性的。
python对类型检查的实现只搜到这么一个:http://oakwinter.com/code/typecheck/ ,粗略看了一下文档,似乎已经相当完善了。

而我自己出于学习的目的也写了个超级简单的:http://huangyilib.googlecode.com/svn/trunk/typecheck.py,这个代码做为学习的材料也还是不错的。而且写完这个我自己也感觉对python的函数参数的处理机制有了更完善的认识。

给大家看下测试输出先,从中大家可以一窥其功能:

call temp(1, 'hello')
call temp(1, 'hello', c=4)
call temp(1, c=4, b='hello')
call temp(a=1, c=4, b='hello')

call temp(1, 2)
TypecheckError : the value 2 of argument 'b' is not type <type 'str'="">

call temp(1, 'hello', c='hello')
TypecheckError : the value 'hello' of argument 'c' is not type <type 'int'="">

call temp(1, c=1)
TypeError : temp() takes at least 2 non-keyword arguments (1 given)

temp() has not this keyword argument 'd'

the default value 1 of argument 'c' is not type <type 'str'="">

temp() has not so meny arguments 4

test success
另外还值得一提的就是,python3000 中的 pep-3107 提议一种给函数增加元数据的方式:
def foo(a: 'x', b: 5 + 6, c: list) -> max(2, 9):
不过这个东西并非为类型检查而生的,类型检查只是它潜在的一个应用而已,它本身只负责存储元数据,具体元数据是啥和元数据怎么用由第三方库决定,其他潜在应用包括:文档生成、rpc、与静态语言之间的交互等等。

2、重载
关于重载首先要说的一点是 python 中灵活的参数传递机制可以减少大量使用重载的场景,不过剩下那些基于实参类型的重载python仍然无能为力。而幸运的是我们有PEAK,其中有个RuleDispatch便是干这事的,而Guido这篇博客:Python 3000 - Adaptation or Generic Functions?说到要把这东西加到python3k中去,也掀起一阵热烈的讨论,只不过在这里我们不叫它重载,叫它Generic Function,但实质是一样的,就是根据传入的不同类型的实参调用合适的函数,比如:
>>> class PrettyPrinter:
... @generic
... def pformat(self, object):
... """Return the pretty string representation of object"""
... return repr(object)
...
>>> @PrettyPrinter.pformat.when(object=list)
... def pformat_list(self, object):
... s = '['
... for item in object:
... s += (' '*self.indent) + self.pformat(item) + ',\n'
... return s + (' '*self.indent) + ']'
...
然后当调用
PrettyPrinter().pformat([1,2,3])
时,实际调用到的函数其实是下面那个pformat_list 。

3、访问控制
python是不对属性做强制性的访问控制的,而是依赖于约定,一方面是坚持相信程序员的信条,另一方面我觉的是确实不好实现,程序中对属性的访问是如此的常见,如果在运行时进行检查,效率上损失太大,得不偿失。
ruby 是进行强制性访问控制的,对象所有属性都只能通过方法暴露,然后对方法进行访问控制,也就是说,每一次你访问一个对象暴露出来的属性,实际上你都是通过调 用一个方法,而调用方法之前访问控制机制还要先判断该调用地点是否可以调用该方法!所以说ruby慢不光是因为它的实现慢,它的语言设计本身就慢!(如对 ruby 有误解,欢迎指出)
另外还有一个原因是ruby中函数不是第一型对象,可以调用函数但不能获取函数对象本身。python中函数是第一型对象,函数对象本身可以当参数传递, 而且class中的方法其实只是普通的函数而已,完全可以把一个外部定义的函数对象交给class给它当方法用,这带来巨大的灵活性,但也使得这种情况下 对方法实现访问控制是根本不可能!你想啊:在class外部定义的函数自然是不能访问 class 的私有属性的,但是当它作为class的方法后就突然变得可以了吗?

4、常量
常量换句话说就是只读的变量,在静态语言中它也是通过编译器在编译期间对代码进行约束。那么在动态语言中又该如何来实现呢?
这个问题最近在两个邮件里都提出来:请教:在python中要实现类似define的功能怎么办?怎么不用property来实现只读属性?
最常见的方法莫过于使用property实现只读的属性:
>>> class Person(object):
... def __init__(self, name):
... self.__name = name
... @property # 只读属性
... def name(self):
... return self.__name
...
>>> p = Person('huangyi')
>>> p.name
'huangyi'
>>> p.name = 'another'
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: can't set attribute
我记得我当时在邮件的讨论中就很详细得总结了一下各种做法,但是刚才去搜的时候,竟然发现它不见了!难道出现了幻觉?估计是gmail当时出了点问题。不过幸好我在另一个地方存了一份;-) 顺便把它改成了doctest的形式。
下面直接粘贴一份语法加亮过的版本,你也可以在这里找到代码语法加亮的html
# -*- coding: utf-8 -*-
'''
感觉楼主的这篇和上次用 python 实现 define 的那篇帖子,想说的都是
一个东西,就是静态语言中的 const,第一次初始化后不能修改的东西。

说起来,python 对象中其实是有这样的东西,就是 imutable object 。
不过常量针对的是名字而非对象,所以在 python 中常量的准确定义应该
是:在第一次绑定后不能重新绑定其他对象的名字。

遗憾的是 python 中没有这样的东西。

其实和类型检查、访问控制等东西一样,静态语言中常量是通过编译器在
编译时进行检查,而 python 就算实现那也只能是在运行时进行计算,势
必损耗性能,我想这也是 python 中没有这样的东西的原因。

但是正如 python 中的访问控制是通过对名字的约定来做的一样,其实常
量也比较适合这样做。

如果实在要用动态语言模拟 const,那么关键在于对名字的绑定进行控制。

下面总结一下各种做法:
'''

def a_const_value():
'''
方法1是通过使用函数替代对名字的直接访问,好像是比较傻的方法。
不过 ruby 中函数调用可以省略括号就有点像了

>>> a_const_value()
'const'
'''
return 'const'

class Temp(object):
'''
class 中通过 property 可以做得更漂亮:

>>> t = Temp()
>>> t.a_const_value
'const'
>>> t.a_const_value = 'another value'
Traceback (most recent call last):
...
AttributeError: can't set attribute
'''
@property
def a_const_value(self):
return 'const'

class ConstError(Exception):
pass

class Consts(object):
'''
方法2是将常量名字放入一个 class 中统一进行管理:

>>> consts = Consts()
>>> consts.a = 2
>>> consts.a
2
>>> consts.a = 3
Traceback (most recent call last):
...
ConstError: can't rebind const name

不过需要注意的是,仍然可以通过 __dict__ 直接访问常量:
>>> consts.__dict__['a'] = 3
>>> consts.a
3
'''
def __setattr__(self, name, value):
if name in self.__dict__:
raise ConstError, 'can\'t rebind const name'
else:
self.__dict__[name] = value

class ConstBase(object):
'''
或者让 class 自己指定那些是常量:

>>> class Temp(ConstBase):
... __consts__ = {'a':None, 'b':2}
... def __init__(self, a):
... self.a = a
...
>>> t = Temp(2)
>>> t.a
2
>>> t.b
2
>>> t.a = 3
Traceback (most recent call last):
...
ConstError: can't rebind const name
>>> t.b = 3
Traceback (most recent call last):
...
ConstError: can't rebind const name
>>> t.c = 5
>>> t.c
5

使用这种方式,也可以直接通过 __dict__ 对常量进行修改:
>>> t.__dict__['a']= 3
>>> t.a
3
'''
__consts__ = {}
def __setattr__(self, name, value):
if name in self.__consts__:
if self.__consts__[name] == None:
self.__consts__[name] = value
else:
raise ConstError, 'can\'t rebind const name'
else:
super(ConstBase, self).__setattr__(name, value)
def __getattr__(self, name):
if name in self.__consts__:
return self.__consts__[name]
else:
return super(ConstBase, self).__getattr__(name, value)

if __name__ == '__main__':
import doctest
doctest.testmod()

相关推荐

    Java Swing, Second Edition

    When Java was first released, its ... it relied heavily on the runtime platform's native user interface components, and it wasn't always possible to hide differences in the way these components behaved.

    Inside.Microsoft.NET.IL.Assembler

    If the runtime can do it, ILAsm must be able to express it. Unlike high-level languages, and like other assembly languages, ILAsm is platform-driven rather than concept-driven. An assembly language ...

    do_it

    【标题】"do_it"可能是指一个开源项目或者编程任务的命名,暗示着我们要执行或完成某项操作。在这个场景中,我们主要关注与C#编程语言相关的知识点。 【描述】"do_it"的描述非常简洁,没有提供具体的技术细节。通常...

    6 第六章 XaaS和IT服务标准.pdf

    ISO20000 的核心是 PDCA (Plan-Do-Check-Act) 循环,帮助组织建立、实施、维护和持续改进其 IT 服务管理系统 (SMS)。该标准覆盖了多个方面,包括服务管理策略和服务计划、服务级别管理、供应商管理、信息安全管理等...

    Dezender5 DezendMe Commandline Decoder

    the tool will do it automatically. 2. Just place the target files in the encoded directory. Then run one of the following executables. zend.exe - Decodes the following: Zend (Expired), Nu-Coder...

    Databox – Data editor save solution v1.2.1p1

    It allows you to view and modify all of your data in your runtime build in a similar way to the editor in Unity. This is a great way to modify values while play-testing your game and do some quick ...

    ObjCRuntimeGuide

    While the runtime system is powerful, most Cocoa applications do not require explicit knowledge of its inner workings. However, for those who need to work with advanced features or optimize ...

    Android代码-QuickPermissions-Kotlin

    How to do it? Let the library do all the hard stuff Advanced Summary Sample Inspiration Android runtime permissions is pain. Android runtime permissions was introduced in the Marshmallow (v 6.0) ...

    Flappy Bird Clone Source Code For Delphi XE5 Firemonkey On Android And IOS

    I accomplished the animation of the firemonkey and the moving ground bar by just using two frames and doing TBitmap.Assign() between them which is not at all the best way to do it but it works for a ...

    Visual.C++.NET托管扩展编程英文版

    The most immediately obvious feature of .NET is the runtime, which Microsoft calls the common language runtime. The concept of a runtime is not new to Microsoft technologies—Visual Basic applications...

    Google C++ Style Guide(Google C++编程规范)高清PDF

    It is very important that any programmer be able to look at another's code and quickly understand it. Maintaining a uniform style and following conventions means that we can more easily use "pattern-...

    libiomp5md.dll

    The best thing to do is to ensure that only a single OpenMP runtime is linked into the pr 解决方法: 如果在Anaconda的base环境下:删除..\Anaconda3\Library\bin\libiomp5md.dll 如果是在某个env(例如名为...

    Learning FPGAs.pdf(完美英文版)

    to do. It used to require creating application-specific integrated circuits (ASICs)—taking weeks or months to produce an actual chip, and requiring piles of cash or wiring together tons of individual...

    [VB6]Alpha Shape Control

    vb6下使用的Shape控件(使用GDI+),这是制作者的描述: This control is similar to VB's shape ... Want to create your own shape and add it during runtime, can do! 比VB6自带的功能强多了,而且还可以做艺术字体

    UPX3.5附带源码

    that do the runtime decompression when a compressed program is started. If you look at the C++ source files, you can find code fragments like this: addLoader("PEMAIN20", ih.entry ? "PEDOJUMP" : ...

    MinGW full 2009-04-10 Windows下的GNU编译器

    MinGW provides a complete Open Source programming tool set which is suitable for the development of native MS-Windows applications, and which do not depend on any 3rd-party C-Runtime DLLs. (It does ...

    commons-logging-1.2

    However many popular logging implementations do automatically initialise themselves; in this case an application may be able to avoid containing any code that is specific to the logging ...

    Learn Node.js by Building 6 Projects-Packt Publishing(2018) .epub

    Node.js is an open-source, cross-platform runtime environment for developing server-side web applications. Node.js is built on the Google Chrome V8 JavaScript engine, which makes it very fast. It is ...

    Programming Elixir

    And we do it both with and without OTP., And Part 3 looks at the more advanced features of the language, from DSLs and code generation to extending the syntax., By the end of this book, you’ll ...

Global site tag (gtag.js) - Google Analytics