6再也没有你这样的人还是处男处女、会有BB吗thof

麻烦高手帮忙看下这个功能怎么實现 提供一点思路 [问题点数:50分结帖人febil]

问题如上图所示  简单描述一下  用户一点自定义,可以自添加和删除界面上面的按钮最好能自定義按钮的名称  

问题1:一个按钮被删除后,另外的按钮添加进来 所有的按钮位置都要重新排列怎么实现,是控数组还是 如何把他们排列那么整齐 

问题2:每个按钮要实现的功能不同,那么事件是写到按钮下面还是做成一个方法?根据按钮的名称调用 因为我有很多按钮 大概100個左右

问题2都可以,依你的习惯集中书写,便于自动化管理

问题2:每个按钮要实现的功能不同那么事件是写到按钮下面,还是做成┅个方法根据按钮的名称调用 因为我有很多按钮 大概100个左右

什么叫做“按钮的名称”啊?编程是“面向对象”的可不是什么“面向名稱”的。一个(动态产生的)按钮对象本身就具有事件处理委托方法按钮跑到哪里那么其点击事件也会自然而然地跟着对象“跑”。每┅个按钮对象都有它自己的事件委托值跟按钮的名称有什么关系?

所以你说的“先把那个几个位置的坐标 定义好”这就说明根本没有明皛“ FlowLayoutPanel 容器”的意思了你学习这个控件汇总会自动排列和对齐子控件(按钮)的编程例子再说。

搞明白了没有用过这个控件,拖进来一試 所有疑问都解开了


什么叫做“按钮的名称”啊编程是“面向对象”的,可不是什么“面向名称”的一个(动态产生的)按钮对象本身就具有事件处理委托方法,按钮跑到哪里那么其点击事件也会自然而然地跟着对象“跑”每一个按钮对象都有它自己的事件委托值。哏按钮的名称有什么关系

所以你说的“先把那个几个位置的坐标 定义好”这就说明根本没有明白“ FlowLayoutPanel 容器”的意思了。你学习这个控件汇總会自动排列和对齐子控件(按钮)的编程例子再说

问题2,一个方法除非这些按钮每一个业务都很独立

匿名用户不能发表回复!

 
 
但是在实际调鼡中我们发现程序出错了,上面的代码打印了两个hello经过调试你发现是say_goodbye()出错了。老板要求调用每个方法前都要记录进入函数的名称比洳再也没有你这样的人:
 
好,小A是个毕业生他是再也没有你这样的人实现的。
 
很low吧 嗯是的。小B工作有一段时间了他告诉小A可以再也沒有你这样的人写。
 
是不是好一点那当然,但是每个业务函数里都要调用一下debug()函数是不是很难受?万一老板说say相关的函数不用debugdo相关嘚才需要呢?
那么装饰器这时候应该登场了

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用

 
概括的讲,装饰器的作用就是为已经存在的函数或对象添加额外的功能

 
 
上面的debug函数其实已经是一个装饰器了,它对原函数做了包装并返回了另外一个函数额外添加了一些功能。因为再也没有你这样的人写实在不太优雅在后面版本的Python中支持了@语法糖,下面代码等同于早期的写法
 
这是最简单的装饰器,但是有一个问题如果被装饰的函数需要传入参数,那么这个装饰器就坏了因为返回的函数并不能接受参数,你可以指定装饰器函数wrapper接受和原函数一样的参数比如:
 
再也没有你这样的人你就解决了一个问题,但又多了N个问题因为函數有千千万,你只管你自己的函数别人的函数参数是什么样子,鬼知道还好Python提供了可变参数*args和关键字参数**kwargs,有了这两个参数装饰器僦可以用于任意目标函数了。
 
至此你已完全掌握初级的装饰器写法。

 
带参数的装饰器和类装饰器属于进阶的内容在悝解这些装饰器之前,最好对函数的闭包和装饰器的接口约定有一定了解(参见http://betacat.online/posts/python-closure/)

 
假设我们前文的装饰器需要完成的功能不僅仅是能在进入某个函数后打出log信息,而且还需指定log的级别那么装饰器就会是再也没有你这样的人的。
# 如果没有使用@语法等同于
 
是不昰有一些晕?你可以这么理解当带参数的装饰器被打在某个函数上时,比如@logging(level='DEBUG')它其实是一个函数,会马上被执行只要这个它返回的结果是一个装饰器时,那就没问题细细再体会一下。

 
装饰器函数其实是再也没有你这样的人一个接口约束它必须接受一个callable对象作为参数,然后返回一个callable对象在Python中一般callable对象都是函数,但也有例外只要某个对象重载了__call__()方法,那么这个对象就是callable的
 
__call__再吔没有你这样的人前后都带下划线的方法在Python中被称为内置方法,有时候也被称为魔法方法重载这些魔法方法一般会改变对象的内部行为。上面这个例子就让一个类对象拥有了被调用的行为
回到装饰器上的概念上来,装饰器要求接受一个callable对象并返回一个callable对象(不太严谨,详见后文)那么用类来实现也是也可以的。我们可以让类的构造函数__init__()接受一个函数然后重载__call__()并返回一个函数,也可以达到装饰器函數的效果
 

 
如果需要通过类形式实现带参数的装饰器,那么会比前面的例子稍微复杂一点那么在构造函数里接受的就鈈是一个函数,而是传入的参数通过类把这些参数保存起来。然后在重载__call__方法是就需要接受一个函数并返回一个函数
 
 

 
内置的装饰器和普通的装饰器原理是一样的,只不过返回的不是函数而是类对象,所以更难理解一些

在了解这个装饰器前,你需要知道茬不使用装饰器怎么写一个属性
 
 
以上就是一个Python属性的标准写法,其实和Java挺像的但是太罗嗦。有了@语法糖能达到一样的效果但看起来哽简单。
 
都是在property()的基础上做了一些封装,因为setterdeleterproperty()的第二和第三个参数不能直接套用@语法。getter装饰器和不带getter的属性装饰器效果是一样的估计只是为了凑数,本身没有任何存在的意义经过@property装饰过的函数返回的不再是一个函数,而是一个property对象
 

 
装饰器的@语法就等同调用了這两个类的构造函数。
 
 
至此我们上文提到的装饰器接口定义可以更加明确一些,装饰器必须接受一个callable对象其实它并不关心你返回什么,可以是另外一个callable对象(大部分情况)也可以是其他类对象,比如property

 
装饰器可以让你代码更加优雅,减少重复但也鈈全是优点,也会带来一些问题

 
让我们直接看示例代码。
 
在装饰器中我在各个可能的位置都加上了print语句用于记录被调鼡的情况。你知道他们最后打印出来的顺序吗如果你心里没底,那么最好不要在装饰器函数之外添加逻辑功能否则这个装饰器就不受伱控制了。以下是输出结果:
 

 
装饰器装饰过的函数看上去名字没变其实已经变了。
 
为什么会再也没有你这样的人呢只要你想想装饰器的语法糖@代替的东西就明白了。@等同于再也没有你这样的人的写法
 
logging其实返回的函数名字刚好是wrapper,那么上面的这个語句刚好就是把这个结果赋值给saysay__name__自然也就是wrapper了,不仅仅是name其他属性也都是来自wrapper,比如docsource等等。
使用标准库里的functools.wraps可以基本解决这个問题。
 
看上去不错!主要问题解决了但其实还不太完美。因为函数的签名和源码还是拿不到的
 
如果要彻底解决这个问题可以借用第三方包,比如wrapt后文有介绍。

 
当你想把装饰器用在一个静态方法或者类方法时不好意思,报错了
 
前面已经解释了@staticmethod这个装饰器,其实它返回的并不是一个callable对象而是一个staticmethod对象,那么它是不符合装饰器要求的(比如传入一个callable对象)你自然不能在它之上再加别的裝饰器。要解决这个问题很简单只要把你的装饰器放在@staticmethod之前就好了,因为你的装饰器返回的还是一个正常的函数然后再加上一个@staticmethod是不會出问题的。
 

 
嵌套的装饰函数不太直观我们可以使用第三方包类改进再也没有你这样的人的情况,让装饰器函数可讀性更好

 
是一个非常简单的装饰器加强包。你可以很直观的先定义包装函数wrapper()再使用decorate(func, wrapper)方法就可以完成一个装饰器。
 
你也可以使用它自带嘚@decorator装饰器来完成你的装饰器
 

 
是一个功能非常完善的包,用于实现各种你想到或者你没想到的装饰器使用wrapt实现的装饰器你不需要担心之湔inspect中遇到的所有问题,因为它都帮你处理了甚至inspect.getsource(func)也准确无误。
 
kwargs)注意第二个参数instance是必须的,就算你不用它当装饰器装饰在不同位置时咜将得到不同的值,比如装饰在类实例方法时你可以拿到这个类实例根据instance的值你能够更加灵活的调整你的装饰器。另外argskwargs也是固定的,注意前面没有星号在装饰器内部调用原函数时才带星号。
如果你需要使用wrapt写一个带参数的装饰器可以再也没有你这样的人写。
 
关于wrapt嘚使用建议查阅官方文档,在此不在赘述
 

 
Python的装饰器和Java的注解(Annotation)并不是同一回事,和C#中的特性(Attribute)也不一样完全是两个概念。
裝饰器的理念是对原函数、对象的加强相当于重新封装,所以一般装饰器函数都被命名为wrapper()意义在于包装。函数只有在被调用时才会发揮其作用比如@logging装饰器可以在函数执行时额外输出日志,@cache装饰过的函数可以缓存计算结果等等
而注解和特性则是对目标函数或对象添加┅些属性,相当于将其分类这些属性可以通过反射拿到,在程序运行时对不同的特性函数或对象加以干预比如带有Setup的函数就当成准备步骤执行,或者找到所有带有TestMethod的函数依次执行等等

以前写代码的时候如果觉得某個指定肯定不会为空就不做判断了,但是项目里要求使用指针前都要判断连new出来的指针都不放过,再也没有你这样的人子写出来的代码佷难看啊看代码的人也会觉得不清晰,而且做单元测试的时候判断为空的分支又进不去分支覆盖率就上不去了。

项目里一方面要求分支覆盖率高一方面又要求判断指针,两者矛盾了啊看来得少用指针了,可是老的代码里都是在用指针所以也木有办法不用指针。

不知道有没有类似遭遇的兄弟给个解决之道啊。

我要回帖

更多关于 再也没有你这样的人 的文章

 

随机推荐