欢迎访问皮皮网官网
皮皮网

【mfc扫雷游戏源码】【电竞比赛报名系统源码】【服务端启动器源码】func源码

时间:2024-11-25 01:52:33 分类:知识 来源:automapper 源码

1.说说 Python 的元编程
2.求函数y=1/(x-1)的源码函数图像
3.[灵性编程]GO的依赖注入AND自动生成代码
4.c++中定义和声明有什么区别?

func源码

说说 Python 的元编程

       æåˆ°å…ƒè¿™ä¸ªå­—,你也许会想到元数据,元数据就是描述数据本身的数据,元类就是类的类,相应的元编程就是描述代码本身的代码,元编程就是关于创建操作源代码(比如修改、生成或包装原来的代码)的函数和类。主要技术是使用装饰器、元类、描述符类。

       æœ¬æ–‡çš„主要目的是向大家介绍这些元编程技术,并且给出实例来演示它们是怎样定制化源代码的行为。

       è£…饰器 装饰器就是函数的函数,它接受一个函数作为参数并返回一个新的函数,在不改变原来函数代码的情况下为其增加新的功能,比如最常用的计时装饰器:

from functools import wrapsdef timeit(logger=None):"""耗时统计装饰器,单位是秒,保留 4 位小数"""def decorator(func):@wraps(func)def wrapper(*args, **kwargs):start = time.time()result = func(*args, **kwargs)end = time.time()if logger:logger.info(f"{ func.__name__} cost { end - start :.4f} seconds")else:print(f"{ func.__name__} cost { end - start :.4f} seconds")return resultreturn wrapperreturn decorator

       (注:比如上面使用 @wraps(func) 注解是很重要的, 它能保留原始函数的元数据) 只需要在原来的函数上面加上 @timeit() 即可为其增加新的功能:

@timeit()def test_timeit():time.sleep(1)test_timeit()#test_timeit cost 1. seconds

       ä¸Šé¢çš„代码跟下面这样写的效果是一样的:

test_timeit = timeit(test_timeit)test_timeit()

       è£…饰器的执行顺序 当有多个装饰器的时候,他们的调用顺序是怎么样的?

       å‡å¦‚有这样的代码,请问是先打印 Decorator1 还是 Decorator2 ?

from functools import wrapsdef decorator1(func):@wraps(func)def wrapper(*args, **kwargs):print('Decorator 1')return func(*args, **kwargs)return wrapperdef decorator2(func):@wraps(func)def wrapper(*args, **kwargs):print('Decorator 2')return func(*args, **kwargs)return wrapper@decorator1@decorator2def add(x, y):return x + yadd(1,2)# Decorator 1# Decorator 2

       å›žç­”这个问题之前,我先给你打个形象的比喻,装饰器就像函数在穿衣服,离它最近的最先穿,离得远的最后穿,上例中 decorator1 是外套,decorator2 是内衣。

       add = decorator1(decorator2(add))

       åœ¨è°ƒç”¨å‡½æ•°çš„时候,就像脱衣服,先解除最外面的 decorator1,也就是先打印 Decorator1,执行到 return func(

       args, kwargs) 的时候会去解除 decorator2,然后打印 Decorator2,再次执行到 return func(

       args, kwargs) 时会真正执行 add() 函数。

       éœ€è¦æ³¨æ„çš„是打印的位置,如果打印字符串的代码位于调用函数之后,像下面这样,那输出的结果正好相反:

def decorator1(func):@wraps(func)def wrapper(*args, **kwargs):result = func(*args, **kwargs)print('Decorator 1')return resultreturn wrapperdef decorator2(func):@wraps(func)def wrapper(*args, **kwargs):result = func(*args, **kwargs)print('Decorator 2')return resultreturn wrapper

       è£…饰器不仅可以定义为函数,也可以定义为类,只要你确保它实现了__call__() 和 __get__() 方法。

       å…ƒç±» Python 中所有类(object)的元类,就是 type 类,也就是说 Python 类的创建行为由默认的 type 类控制,打个比喻,type 类是所有类的祖先。我们可以通过编程的方式来实现自定义的一些对象创建行为。

       å®šä¸€ä¸ªç±»ç»§æ‰¿ type ç±» A,然后让其他类的元类指向 A,就可以控制 A 的创建行为。典型的就是使用元类实现一个单例:

class Singleton(type):def __init__(self, *args, **kwargs):self._instance = Nonesuper().__init__(*args, **kwargs)def __call__(self, *args, **kwargs):if self._instance is None:self._instance = super().__call__(*args, **kwargs)return self._instanceelse:return self._instanceclass Spam(metaclass=Singleton):def __init__(self):print("Spam!!!")

       å…ƒç±» Singleton 的__init__和__new__ 方法会在定义 Spam 的期间被执行,而 __call__方法会在实例化 Spam 的时候执行。

       descriptor 类(描述符类)

       descriptor 就是任何一个定义了 __get__(),__set__()或 __delete__()的对象,描述器让对象能够自定义属性查找、存储和删除的操作。这里举官方文档[1]一个自定义验证器的例子。

       å®šä¹‰éªŒè¯å™¨ç±»ï¼Œå®ƒæ˜¯ä¸€ä¸ªæè¿°ç¬¦ç±»ï¼ŒåŒæ—¶è¿˜æ˜¯ä¸€ä¸ªæŠ½è±¡ç±»ï¼š

from abc import ABC, abstractmethodclass Validator(ABC):def __set_name__(self, owner, name):self.private_name = '_' + namedef __get__(self, obj, objtype=None):return getattr(obj, self.private_name)def __set__(self, obj, value):self.validate(value)setattr(obj, self.private_name, value)@abstractmethoddef validate(self, value):pass

       è‡ªå®šä¹‰éªŒè¯å™¨éœ€è¦ä»Ž Validator 继承,并且必须提供 validate() 方法以根据需要测试各种约束。

       è¿™æ˜¯ä¸‰ä¸ªå®žç”¨çš„数据验证工具:

       OneOf 验证值是一组受约束的选项之一。

class OneOf(Validator):def __init__(self, *options):self.options = set(options)def validate(self, value):if value not in self.options:raise ValueError(f'Expected { value!r} to be one of { self.options!r}')

       Number 验证值是否为 int 或 float。根据可选参数,它还可以验证值在给定的最小值或最大值之间。

class Number(Validator):def __init__(self, minvalue=None, maxvalue=None):self.minvalue = minvalueself.maxvalue = maxvaluedef validate(self, value):if not isinstance(value, (int, float)):raise TypeError(f'Expected { value!r} to be an int or float')if self.minvalue is not None and value < self.minvalue:raise ValueError(f'Expected { value!r} to be at least { self.minvalue!r}')if self.maxvalue is not None and value > self.maxvalue:raise ValueError(f'Expected { value!r} to be no more than { self.maxvalue!r}')

       String 验证值是否为 str。根据可选参数,它可以验证给定的最小或最大长度。它还可以验证用户定义的 predicate。

class String(Validator):def __init__(self, minsize=None, maxsize=None, predicate=None):self.minsize = minsizeself.maxsize = maxsizeself.predicate = predicatedef validate(self, value):if not isinstance(value, str):raise TypeError(f'Expected { value!r} to be an str')if self.minsize is not None and len(value) < self.minsize:raise ValueError(f'Expected { value!r} to be no smaller than { self.minsize!r}')if self.maxsize is not None and len(value) > self.maxsize:raise ValueError(f'Expected { value!r} to be no bigger than { self.maxsize!r}')if self.predicate is not None and not self.predicate(value):raise ValueError(f'Expected { self.predicate} to be true for { value!r}')

       å®žé™…应用时这样写:

@timeit()def test_timeit():time.sleep(1)test_timeit()#test_timeit cost 1. seconds0

       æè¿°å™¨é˜»æ­¢æ— æ•ˆå®žä¾‹çš„创建:

@timeit()def test_timeit():time.sleep(1)test_timeit()#test_timeit cost 1. seconds1

       æœ€åŽçš„话 关于 Python 的元编程,总结如下:

       å¦‚果希望某些函数拥有相同的功能,希望不改变原有的调用方式、不写重复代码、易维护,可以使用装饰器来实现。

       å¦‚果希望某一些类拥有某些相同的特性,或者在类定义实现对其的控制,我们可以自定义一个元类,然后让它类的元类指向该类。

       å¦‚果希望实例的属性拥有某些共同的特点,就可以自定义一个描述符类。

       ä»¥ä¸Šå°±æ˜¯æœ¬æ¬¡åˆ†äº«çš„所有内容,如果你觉得文章还不错,欢迎关注公众号:Python编程学习圈,每日干货分享,内容覆盖Python电子书、教程、数据库编程、Django,爬虫,云计算等等。或是前往编程学习网,了解更多编程技术知识。

原文:/post/

求函数y=1/(x-1)的函数图像

       绘图源代码:

       def func_x2():

       # 准备 X 轴的数据

       x = np.linspace(-, , )

       # 准备 y 轴的数据

       y = 1/(x-1)

       # 绘图前设置

       # 使用背景

       plt.style.use('ggplot')

       # 获取折线图

       plt.plot(x, y,c='r', marker='o', ls='-' )

       # 添加标题

       plt.title("y = 1/(x-1)")

       # 添加 x 轴的信息

       plt.xlabel("x")

       # 添加 y 轴的信息

       plt.ylabel("y")

       # 显示折线图

       plt.show()

[灵性编程]GO的依赖注入AND自动生成代码

       依赖

       总结下先有的获取对象依赖方式

       比较原始的New,全局global保存

       基于反射读取对象的依赖,程序启动时由DI库实例化(代表作dig等)

       基于反射读取对象的依赖,编译前生成完整构建函数(代表作wire等)

       第一种:最方便,直接快捷,大量依赖时候,但是因为是手动的,容易出现实例顺序非预期,不方便自动测试,mock等。

       第二种:因为是源码启动时反射获取依赖的,需要定义额外的函数给DI系统解析,例如一个结构的注入必须要要额外的代码,非常麻烦,不建议使用

//提供者err:=c.Provide(func(conn*sql.DB)(*UserGateway,*CommentGateway,error){ //...})iferr!=nil{ //...}//使用者err:=c.Invoke(func(l*log.Logger){ //...})iferr!=nil{ //...}

       第三种,同样是基于反射,所以依然需要一个额外函数(只有配置信息)提供反射信息,生成同名函数,便捷度基本和手动New一致,wire由Google开源

funcInitializeNewGormProvider()*Gorm{ wire.Build(NewGormProvider,InitializeNewConfProvider)returnnil}我的方案

       原理和wire一样,根据配置信息生成自动构建函数,但是不基于反射,因为反射需要程序是完整的,编译后才读取信息,相对慢,需要每个目录改完手动执行wire.命令(每个目录每次花费1秒等)。

       先看一个场景,源码数据库服务是依赖配置服务,从结构体就能看出来,不需要funcInitializeNewGormProvider()*Gorm{ }函数反射,未了更加准确(防止注入了不需要的内容)添加一个taginject:""和@Bean注解

//@BeantypeGormstruct{ conf*Conf`inject:""`}

       所以,注入其实是可以直接基于源码的信息都能实现的。

       我只要实现一个go代码解析工具,源码mfc扫雷游戏源码就能生成和wire工具生成相同的代码,因为go源码的关键字和结构实在是太简单了,没有多少语法糖,做一下分词再按语法规则读取源码信息,工具实现比较容易。工具使用php实现(公司都是源码mac,php环境mac电脑自带,方便使用模版生成go代码)/go-home-admin/home-toolset-php重要是php解析很快,整个项目生成一次都是一秒内

ORM生成代码

       编写工具后,也可以生成其他辅助代码,例如原始结构,添加@Orm后,自动根据字段信息生成通用代码

//@OrmtypeGormstruct{ Iduint`json:"id"`UserNamestring`json:"user_name"`}

       逻辑就可以直接使用

u:=&UsersTable{ }data:=u.WhereUserName("test").And(func(table*UsersTable){ table.WhereId(1).OrWhereId(2)}).Or(func(table*UsersTable){ table.WhereId(2).Or(func(table*UsersTable){ table.WhereId(1)})}).Find()//select*formuserswhereuser_name=?and(id=?orid=?)or(id=?or(id=?))utils.Dump(data)

       作者:程序狗著作权归作者所有。

c++中定义和声明有什么区别?

       如果是源码指变量的声明和定义:

       从编译原理上来说,声明是源码仅仅告诉编译器,有个某类型的源码变量会被使用,但是源码编译器并不会为它分配任何内存。而定义就是源码分配了内存。

       对于下面的源码电竞比赛报名系统源码两句代码:

       void Func()

       {

       int a;

       int b=1;

       a=0;

       }

       对于第一行代码,编译器不会做任何事,源码它不会为它在栈中分配一点东西,源码直到第三句,源码a=0;时,源码编译器才会将其压入栈中。服务端启动器源码而对于int b=0;这一句,编译器就会生成一条指令,为它赋值。如果反汇编,看到的狙击起涨点源码指标公式代码可能是这样的:

       push 1;

       push 0;

       当然,并不一定编译器就会样做,也有可能在声明int a时,编译器就会把一个废值入栈,到第三条再为其赋值,这要看编译器的涨停后挂双星选股源码具体取舍,所以,声明不一定不是定义,而定义一定是定义。

       但是,下面的声明,一定仅仅是声明:

       extern int a;

       这表时,有一个int变量a,它一定是在另外其他地方定义的,所以编译器此时一定不会做什么分配内存的事,因为它就是声明,仅仅表明下面的代码引用了一个符号,而这个符号是int类型的a而已。

       如果是指函数的声明和定义:

       声明:一般在头文件里,对编译器说:这里我有一个函数叫function() 让编译器知道这个函数的存在。

       定义:一般在源文件里,具体就是函数的实现过程 写明函数体。

copyright © 2016 powered by 皮皮网   sitemap