#在类外可以绑定方法和属性 __slots__
def set_age(self,num):
    self.age = num
def set_score(self,score):
    self.score = score
def set_course(self,course):
    self.course = course
class Student(object):
    def __init__(self):pass

s1 = Student()
s1.name = 'tom' #绑定属性name c++好像不行,属性原来可以在类外设置
print(s1.name) #tom
#绑定方法
set_age(s1,25)
print(s1.age) #25
#也可以这样绑定方法
import types
s1.set_score = types.MethodType(set_score,s1)
s1.set_score(90)
print(s1.score) #90
#蛋是,对另外的对象不管用
# s2 = Student()
# print(s2.name) #AttributeError: 'Student' object has no attribute 'name'
#如果让整个类的所有实例都能用呢?
Student.set_course = types.MethodType(set_course,Student) #把set_course函数做为MethodType的第一个参数,把类名Student作为它的第二个参数
s3 = Student()
s3.set_course('python')
s4 = Student()
s4.set_course('C++')
print(s3.course,s4.course) #结果是2个 C++  C++ ?啥?
#那么加上__slots__
class Student(object):
    __slots__ = ('name','age') #限定了类的外部属性只能是name 和age
    pass
s1 = Student()
s1.name = 'tom'
s1.age = 25
s1.score = 95
print(s1.name,s1.age) #tom 25
print(s1.score)#AttributeError: 'Student' object has no attribute 'score' 【__slots__里没有score 就不能随便定义绑定score属性给实例了】
#蛋是,子类不继承
class ChildStudent(Student):
    pass
s2 = ChildStudent()
s2.score= 99
print(s2.score) # 打印99 ,这里子类不受影响
#定义类的时候可能想不到一些属性,后续可以用他来补充,同时限制了类外不能随便绑定属性,
#偏函数
#函数在执行时,要带上所有必要的参数进行调用。但是,有时参数可以在函数被调用之前提前获知。
# 这种情况下,一个函数有一个或多个参数预先就能用上,以便函数能用更少的参数进行调用。
#比如定义一个求余的函数,每次都提供一个1-100的数num,让100%num 求余
from functools import partial #这句是关键
def mod(n,m):
    return n%m
#我已经确定了,以后每次都拿100 来求余,就可以在mod函数的基础上再定义一个偏函数mod_by_100,原函数第二个参数开始,就放在新函数第一个参数开始往后一一对应
mod_by_100 = partial(mod,100)
print(mod(100,7))#2
print(mod_by_100(7)) #2
#再比如以后学到GUI中,每次创建Button控件的时候都会用主窗口对象top作为第一个参数,
Button(top,command=.....)
MyButton = partial(Button,top)
MyButton(command=callBack,bg='red',fg='white')#command 是回调函数,单击按钮触发的,bg 和fg是背景色和前景色
#没觉得有什么好处,官方的意思是可以有效的’冻结'哪些预先确定的参数来缓存函数参数,比如top冻结了,运行时只需要获取剩余的参数后,在把top解冻,传递到最终的参数中
#网上说,偏函数可以很好的执行DRY(Donot Repeat Yourself)原则,并节省编程成本
#在实际应用中,可以参考《重构》(Refactoring)中说的三次原则(Rule of three),即同样的代码将要出现第三次前,考虑抽象它。
# 违背DRY原则的代码,程序员称之为WET(直译:潮湿,因为DRY是干燥的意思)的,可以理解为Write Everything Twice(任何东西写两遍),We Enjoying Typing(我们享受敲键盘)或Waste Everyone’s Time(浪费所有人的时间)。

#偏函数可以对现有函数进行加强
# 图形用户界面GUI

#Label控件显示一个 helloworld
import tkinter
top = tkinter.Tk() #顶层窗口
label = tkinter.Label(top,text='hello world') #Label是个子窗口
label.pack()#packer方式进行布局,还有placer 和 Grid
tkinter.mainloop()

#button 控件
import tkinter as tk
top= tk.Tk()
quit = tk.Button(top,text = 'push me!',command=top.quit) #button控件 带了command事件,当按下按钮就会触发主窗口退出
quit.pack()
tk.mainloop()
#Label 和 button
import tkinter as tk
top = tk.Tk()
l1 = tk.Label(top,text = 'hello,world')
l1.pack()

b1 = tk.Button(top,text = 'push me',command = top.quit,bg = 'red',fg = 'white')
b1.pack(fill = tk.X,expand = 1) #fill 让button 按钮拉伸整个水平界面,expend 填充整个水平控件
tk.mainloop()
#Scale 滑块控件
from tkinter import *
def resize(ev=None):
    label1.config(font = 'Helvetica -%d bold' %scale1.get())

top = Tk()
top.geometry('250x150')

label1 = Label(top,text='hello world',font = 'Helvetica -12 bold')
label1.pack(fill = Y,expand = 1)

scale1 = Scale(top,from_=10,to=40,orient=HORIZONTAL,command=resize) #command 直接对应毁掉函数 resize,from to是范围,orient是方向
scale1.set(12)#最初值设置成12
scale1.pack(fill = X,expand = 1)

quit = Button(top,text='QUIT',command = top.quit, activeforeground = 'white',activebackground = 'red')#command 调用主窗口的quit方法
#activebackground 鼠标点击下去是红色背景,松开就是白色
quit.pack()

mainloop()
#公路警示牌
from functools import partial as pto
from tkinter import messagebox
from tkinter import Button,X,Tk

#公路牌有三个级别
ERROR = 'error'
WARN = 'warn'
INFO = 'info'

#列出所有公路牌内容和对应的级别
SIGNS = {
    'Wrong Way':ERROR, #走错路,禁止通行
    'Railroad Crossing':WARN, #铁道穿过
    '55 limit':INFO, #限速55公里
}

#创建三个回调函数,分别针对不同的警告,弹出不同类型的对话框 messagebox
errorCB = lambda :messagebox.showerror('Error','Error Button Pressed')
warnCB = lambda :messagebox.showwarning('Warning','Warning Button Pressed')
infoCB = lambda :messagebox.showinfo('Info','Info Button Pressed')

#创建主窗口
top = Tk()
top.title('Road Signs')
Button(top,text = 'Quit',command = top.quit,bg='red',fg='white').pack()


#这里比较难理解,用到了偏函数
MyButton = pto(Button,top)
errorButton = pto(MyButton,command = errorCB,bg='white',fg='red')
warnButton = pto(MyButton,command= warnCB,bg='goldenrod1')
infoButton = pto(MyButton,command = infoCB,bg='white',fg='lime')

#循环,批量创建button
for eachSign in SIGNS:
    signType = SIGNS[eachSign]
    cmd = '%sButton(text=%r%s).pack(fill=X,expand=True)'%(signType,eachSign,'.upper()' if signType == ERROR else '.title()')
    eval(cmd)
top.mainloop()
#基于类的GUI编程
from tkinter import *
from tkinter import messagebox
class Application(Frame): #Application 居然继承了Frame类,Frame是包含其他控件的纯容器,本身创建Button的时候也是实例化类Button
    def __init__(self,master = None):
        super().__init__(master) #调用父类初始化
        self.master = master
        self.pack() # 布局管理器
        self.createWidget() #初始化的时候直接调用 创建子窗口的方法

    def createWidget(self):
        self.btn1 = Button(self)
        self.btn1['text']='test'
        self.btn1['command']=self.btn1_click #回调函数是类的方法
        self.btn1.pack()

        #创建退出按钮
        self.quit = Button(self)
        self.quit['text'] = 'Quit'
        self.quit['command'] = self.master.quit
        self.quit.pack()
    def btn1_click(self):
        messagebox.showinfo('test','hello world')

if __name__ == '__main__':
    top = Tk()
    top.geometry('300x200+50+100') #设置范围 geometry
    app = Application(master = top) #实例化自定义类
    top.mainloop() #和tkinter.mainloop 效果一致
posted on 2020-08-20 18:07  94小渣渣  阅读(109)  评论(0编辑  收藏  举报